diff --git a/Session/src/Loki/Components/ConversationCell.swift b/Session/Components/ConversationCell.swift similarity index 100% rename from Session/src/Loki/Components/ConversationCell.swift rename to Session/Components/ConversationCell.swift diff --git a/Session/src/Loki/Components/ConversationTitleView.swift b/Session/Components/ConversationTitleView.swift similarity index 100% rename from Session/src/Loki/Components/ConversationTitleView.swift rename to Session/Components/ConversationTitleView.swift diff --git a/Session/src/Loki/Components/FakeChatView.swift b/Session/Components/FakeChatView.swift similarity index 100% rename from Session/src/Loki/Components/FakeChatView.swift rename to Session/Components/FakeChatView.swift diff --git a/Session/src/Loki/Components/MentionCandidateSelectionView.swift b/Session/Components/MentionCandidateSelectionView.swift similarity index 100% rename from Session/src/Loki/Components/MentionCandidateSelectionView.swift rename to Session/Components/MentionCandidateSelectionView.swift diff --git a/Session/src/Loki/Components/NewConversationButtonSet.swift b/Session/Components/NewConversationButtonSet.swift similarity index 100% rename from Session/src/Loki/Components/NewConversationButtonSet.swift rename to Session/Components/NewConversationButtonSet.swift diff --git a/Session/src/Loki/Components/PNOptionView.swift b/Session/Components/PNOptionView.swift similarity index 100% rename from Session/src/Loki/Components/PNOptionView.swift rename to Session/Components/PNOptionView.swift diff --git a/Session/src/Loki/Components/PathStatusView.swift b/Session/Components/PathStatusView.swift similarity index 100% rename from Session/src/Loki/Components/PathStatusView.swift rename to Session/Components/PathStatusView.swift diff --git a/Session/src/Loki/Components/SeedReminderView.swift b/Session/Components/SeedReminderView.swift similarity index 100% rename from Session/src/Loki/Components/SeedReminderView.swift rename to Session/Components/SeedReminderView.swift diff --git a/Session/src/Loki/Components/SessionRestorationView.swift b/Session/Components/SessionRestorationView.swift similarity index 100% rename from Session/src/Loki/Components/SessionRestorationView.swift rename to Session/Components/SessionRestorationView.swift diff --git a/Session/src/Loki/Components/UserCell.swift b/Session/Components/UserCell.swift similarity index 100% rename from Session/src/Loki/Components/UserCell.swift rename to Session/Components/UserCell.swift diff --git a/Session/src/Loki/Components/VoiceMessageView.swift b/Session/Components/VoiceMessageView.swift similarity index 100% rename from Session/src/Loki/Components/VoiceMessageView.swift rename to Session/Components/VoiceMessageView.swift diff --git a/Session/src/Loki/Database/Storage+VolumeSamples.swift b/Session/Database/Storage+VolumeSamples.swift similarity index 100% rename from Session/src/Loki/Database/Storage+VolumeSamples.swift rename to Session/Database/Storage+VolumeSamples.swift diff --git a/Session/src/Loki/Dependencies/SRCopyableLabel.swift b/Session/Dependencies/SRCopyableLabel.swift similarity index 100% rename from Session/src/Loki/Dependencies/SRCopyableLabel.swift rename to Session/Dependencies/SRCopyableLabel.swift diff --git a/Session/src/Loki/Dependencies/SwiftCSV/CSV.swift b/Session/Dependencies/SwiftCSV/CSV.swift similarity index 100% rename from Session/src/Loki/Dependencies/SwiftCSV/CSV.swift rename to Session/Dependencies/SwiftCSV/CSV.swift diff --git a/Session/src/Loki/Dependencies/SwiftCSV/Description.swift b/Session/Dependencies/SwiftCSV/Description.swift similarity index 100% rename from Session/src/Loki/Dependencies/SwiftCSV/Description.swift rename to Session/Dependencies/SwiftCSV/Description.swift diff --git a/Session/src/Loki/Dependencies/SwiftCSV/EnumeratedView.swift b/Session/Dependencies/SwiftCSV/EnumeratedView.swift similarity index 100% rename from Session/src/Loki/Dependencies/SwiftCSV/EnumeratedView.swift rename to Session/Dependencies/SwiftCSV/EnumeratedView.swift diff --git a/Session/src/Loki/Dependencies/SwiftCSV/NamedView.swift b/Session/Dependencies/SwiftCSV/NamedView.swift similarity index 100% rename from Session/src/Loki/Dependencies/SwiftCSV/NamedView.swift rename to Session/Dependencies/SwiftCSV/NamedView.swift diff --git a/Session/src/Loki/Dependencies/SwiftCSV/Parser.swift b/Session/Dependencies/SwiftCSV/Parser.swift similarity index 100% rename from Session/src/Loki/Dependencies/SwiftCSV/Parser.swift rename to Session/Dependencies/SwiftCSV/Parser.swift diff --git a/Session/src/Loki/Dependencies/SwiftCSV/ParsingState.swift b/Session/Dependencies/SwiftCSV/ParsingState.swift similarity index 100% rename from Session/src/Loki/Dependencies/SwiftCSV/ParsingState.swift rename to Session/Dependencies/SwiftCSV/ParsingState.swift diff --git a/Session/src/Loki/Dependencies/SwiftCSV/String+Lines.swift b/Session/Dependencies/SwiftCSV/String+Lines.swift similarity index 100% rename from Session/src/Loki/Dependencies/SwiftCSV/String+Lines.swift rename to Session/Dependencies/SwiftCSV/String+Lines.swift diff --git a/Session/AudioFiles/NewMessage.aifc b/Session/Meta/AudioFiles/NewMessage.aifc similarity index 100% rename from Session/AudioFiles/NewMessage.aifc rename to Session/Meta/AudioFiles/NewMessage.aifc diff --git a/Session/AudioFiles/busy_tone_ansi.caf b/Session/Meta/AudioFiles/busy_tone_ansi.caf similarity index 100% rename from Session/AudioFiles/busy_tone_ansi.caf rename to Session/Meta/AudioFiles/busy_tone_ansi.caf diff --git a/Session/AudioFiles/end_call_tone_cept.caf b/Session/Meta/AudioFiles/end_call_tone_cept.caf similarity index 100% rename from Session/AudioFiles/end_call_tone_cept.caf rename to Session/Meta/AudioFiles/end_call_tone_cept.caf diff --git a/Session/AudioFiles/messageReceivedSounds/aurora-quiet.aifc b/Session/Meta/AudioFiles/messageReceivedSounds/aurora-quiet.aifc similarity index 100% rename from Session/AudioFiles/messageReceivedSounds/aurora-quiet.aifc rename to Session/Meta/AudioFiles/messageReceivedSounds/aurora-quiet.aifc diff --git a/Session/AudioFiles/messageReceivedSounds/aurora.aifc b/Session/Meta/AudioFiles/messageReceivedSounds/aurora.aifc similarity index 100% rename from Session/AudioFiles/messageReceivedSounds/aurora.aifc rename to Session/Meta/AudioFiles/messageReceivedSounds/aurora.aifc diff --git a/Session/AudioFiles/messageReceivedSounds/bamboo-quiet.aifc b/Session/Meta/AudioFiles/messageReceivedSounds/bamboo-quiet.aifc similarity index 100% rename from Session/AudioFiles/messageReceivedSounds/bamboo-quiet.aifc rename to Session/Meta/AudioFiles/messageReceivedSounds/bamboo-quiet.aifc diff --git a/Session/AudioFiles/messageReceivedSounds/bamboo.aifc b/Session/Meta/AudioFiles/messageReceivedSounds/bamboo.aifc similarity index 100% rename from Session/AudioFiles/messageReceivedSounds/bamboo.aifc rename to Session/Meta/AudioFiles/messageReceivedSounds/bamboo.aifc diff --git a/Session/AudioFiles/messageReceivedSounds/chord-quiet.aifc b/Session/Meta/AudioFiles/messageReceivedSounds/chord-quiet.aifc similarity index 100% rename from Session/AudioFiles/messageReceivedSounds/chord-quiet.aifc rename to Session/Meta/AudioFiles/messageReceivedSounds/chord-quiet.aifc diff --git a/Session/AudioFiles/messageReceivedSounds/chord.aifc b/Session/Meta/AudioFiles/messageReceivedSounds/chord.aifc similarity index 100% rename from Session/AudioFiles/messageReceivedSounds/chord.aifc rename to Session/Meta/AudioFiles/messageReceivedSounds/chord.aifc diff --git a/Session/AudioFiles/messageReceivedSounds/circles-quiet.aifc b/Session/Meta/AudioFiles/messageReceivedSounds/circles-quiet.aifc similarity index 100% rename from Session/AudioFiles/messageReceivedSounds/circles-quiet.aifc rename to Session/Meta/AudioFiles/messageReceivedSounds/circles-quiet.aifc diff --git a/Session/AudioFiles/messageReceivedSounds/circles.aifc b/Session/Meta/AudioFiles/messageReceivedSounds/circles.aifc similarity index 100% rename from Session/AudioFiles/messageReceivedSounds/circles.aifc rename to Session/Meta/AudioFiles/messageReceivedSounds/circles.aifc diff --git a/Session/AudioFiles/messageReceivedSounds/classic-quiet.aifc b/Session/Meta/AudioFiles/messageReceivedSounds/classic-quiet.aifc similarity index 100% rename from Session/AudioFiles/messageReceivedSounds/classic-quiet.aifc rename to Session/Meta/AudioFiles/messageReceivedSounds/classic-quiet.aifc diff --git a/Session/AudioFiles/messageReceivedSounds/classic.aifc b/Session/Meta/AudioFiles/messageReceivedSounds/classic.aifc similarity index 100% rename from Session/AudioFiles/messageReceivedSounds/classic.aifc rename to Session/Meta/AudioFiles/messageReceivedSounds/classic.aifc diff --git a/Session/AudioFiles/messageReceivedSounds/complete-quiet.aifc b/Session/Meta/AudioFiles/messageReceivedSounds/complete-quiet.aifc similarity index 100% rename from Session/AudioFiles/messageReceivedSounds/complete-quiet.aifc rename to Session/Meta/AudioFiles/messageReceivedSounds/complete-quiet.aifc diff --git a/Session/AudioFiles/messageReceivedSounds/complete.aifc b/Session/Meta/AudioFiles/messageReceivedSounds/complete.aifc similarity index 100% rename from Session/AudioFiles/messageReceivedSounds/complete.aifc rename to Session/Meta/AudioFiles/messageReceivedSounds/complete.aifc diff --git a/Session/AudioFiles/messageReceivedSounds/hello-quiet.aifc b/Session/Meta/AudioFiles/messageReceivedSounds/hello-quiet.aifc similarity index 100% rename from Session/AudioFiles/messageReceivedSounds/hello-quiet.aifc rename to Session/Meta/AudioFiles/messageReceivedSounds/hello-quiet.aifc diff --git a/Session/AudioFiles/messageReceivedSounds/hello.aifc b/Session/Meta/AudioFiles/messageReceivedSounds/hello.aifc similarity index 100% rename from Session/AudioFiles/messageReceivedSounds/hello.aifc rename to Session/Meta/AudioFiles/messageReceivedSounds/hello.aifc diff --git a/Session/AudioFiles/messageReceivedSounds/input-quiet.aifc b/Session/Meta/AudioFiles/messageReceivedSounds/input-quiet.aifc similarity index 100% rename from Session/AudioFiles/messageReceivedSounds/input-quiet.aifc rename to Session/Meta/AudioFiles/messageReceivedSounds/input-quiet.aifc diff --git a/Session/AudioFiles/messageReceivedSounds/input.aifc b/Session/Meta/AudioFiles/messageReceivedSounds/input.aifc similarity index 100% rename from Session/AudioFiles/messageReceivedSounds/input.aifc rename to Session/Meta/AudioFiles/messageReceivedSounds/input.aifc diff --git a/Session/AudioFiles/messageReceivedSounds/keys-quiet.aifc b/Session/Meta/AudioFiles/messageReceivedSounds/keys-quiet.aifc similarity index 100% rename from Session/AudioFiles/messageReceivedSounds/keys-quiet.aifc rename to Session/Meta/AudioFiles/messageReceivedSounds/keys-quiet.aifc diff --git a/Session/AudioFiles/messageReceivedSounds/keys.aifc b/Session/Meta/AudioFiles/messageReceivedSounds/keys.aifc similarity index 100% rename from Session/AudioFiles/messageReceivedSounds/keys.aifc rename to Session/Meta/AudioFiles/messageReceivedSounds/keys.aifc diff --git a/Session/AudioFiles/messageReceivedSounds/make-quiet.sh b/Session/Meta/AudioFiles/messageReceivedSounds/make-quiet.sh similarity index 100% rename from Session/AudioFiles/messageReceivedSounds/make-quiet.sh rename to Session/Meta/AudioFiles/messageReceivedSounds/make-quiet.sh diff --git a/Session/AudioFiles/messageReceivedSounds/note-quiet.aifc b/Session/Meta/AudioFiles/messageReceivedSounds/note-quiet.aifc similarity index 100% rename from Session/AudioFiles/messageReceivedSounds/note-quiet.aifc rename to Session/Meta/AudioFiles/messageReceivedSounds/note-quiet.aifc diff --git a/Session/AudioFiles/messageReceivedSounds/note.aifc b/Session/Meta/AudioFiles/messageReceivedSounds/note.aifc similarity index 100% rename from Session/AudioFiles/messageReceivedSounds/note.aifc rename to Session/Meta/AudioFiles/messageReceivedSounds/note.aifc diff --git a/Session/AudioFiles/messageReceivedSounds/popcorn-quiet.aifc b/Session/Meta/AudioFiles/messageReceivedSounds/popcorn-quiet.aifc similarity index 100% rename from Session/AudioFiles/messageReceivedSounds/popcorn-quiet.aifc rename to Session/Meta/AudioFiles/messageReceivedSounds/popcorn-quiet.aifc diff --git a/Session/AudioFiles/messageReceivedSounds/popcorn.aifc b/Session/Meta/AudioFiles/messageReceivedSounds/popcorn.aifc similarity index 100% rename from Session/AudioFiles/messageReceivedSounds/popcorn.aifc rename to Session/Meta/AudioFiles/messageReceivedSounds/popcorn.aifc diff --git a/Session/AudioFiles/messageReceivedSounds/pulse-quiet.aifc b/Session/Meta/AudioFiles/messageReceivedSounds/pulse-quiet.aifc similarity index 100% rename from Session/AudioFiles/messageReceivedSounds/pulse-quiet.aifc rename to Session/Meta/AudioFiles/messageReceivedSounds/pulse-quiet.aifc diff --git a/Session/AudioFiles/messageReceivedSounds/pulse.aifc b/Session/Meta/AudioFiles/messageReceivedSounds/pulse.aifc similarity index 100% rename from Session/AudioFiles/messageReceivedSounds/pulse.aifc rename to Session/Meta/AudioFiles/messageReceivedSounds/pulse.aifc diff --git a/Session/AudioFiles/messageReceivedSounds/synth-quiet.aifc b/Session/Meta/AudioFiles/messageReceivedSounds/synth-quiet.aifc similarity index 100% rename from Session/AudioFiles/messageReceivedSounds/synth-quiet.aifc rename to Session/Meta/AudioFiles/messageReceivedSounds/synth-quiet.aifc diff --git a/Session/AudioFiles/messageReceivedSounds/synth.aifc b/Session/Meta/AudioFiles/messageReceivedSounds/synth.aifc similarity index 100% rename from Session/AudioFiles/messageReceivedSounds/synth.aifc rename to Session/Meta/AudioFiles/messageReceivedSounds/synth.aifc diff --git a/Session/AudioFiles/message_sent.aiff b/Session/Meta/AudioFiles/message_sent.aiff similarity index 100% rename from Session/AudioFiles/message_sent.aiff rename to Session/Meta/AudioFiles/message_sent.aiff diff --git a/Session/AudioFiles/ringback_tone_ansi.caf b/Session/Meta/AudioFiles/ringback_tone_ansi.caf similarity index 100% rename from Session/AudioFiles/ringback_tone_ansi.caf rename to Session/Meta/AudioFiles/ringback_tone_ansi.caf diff --git a/Session/AudioFiles/ringtoneSounds/Opening.m4r b/Session/Meta/AudioFiles/ringtoneSounds/Opening.m4r similarity index 100% rename from Session/AudioFiles/ringtoneSounds/Opening.m4r rename to Session/Meta/AudioFiles/ringtoneSounds/Opening.m4r diff --git a/Session/AudioFiles/sonarping.mp3 b/Session/Meta/AudioFiles/sonarping.mp3 similarity index 100% rename from Session/AudioFiles/sonarping.mp3 rename to Session/Meta/AudioFiles/sonarping.mp3 diff --git a/Session/CSV/GeoLite2-Country-Blocks-IPv4.csv b/Session/Meta/CSV/GeoLite2-Country-Blocks-IPv4.csv similarity index 100% rename from Session/CSV/GeoLite2-Country-Blocks-IPv4.csv rename to Session/Meta/CSV/GeoLite2-Country-Blocks-IPv4.csv diff --git a/Session/CSV/GeoLite2-Country-Locations-English.csv b/Session/Meta/CSV/GeoLite2-Country-Locations-English.csv similarity index 100% rename from Session/CSV/GeoLite2-Country-Locations-English.csv rename to Session/Meta/CSV/GeoLite2-Country-Locations-English.csv diff --git a/Session/Fonts/ElegantIcons.ttf b/Session/Meta/Fonts/ElegantIcons.ttf similarity index 100% rename from Session/Fonts/ElegantIcons.ttf rename to Session/Meta/Fonts/ElegantIcons.ttf diff --git a/Session/SpaceMono-Bold.ttf b/Session/Meta/Fonts/SpaceMono-Bold.ttf similarity index 100% rename from Session/SpaceMono-Bold.ttf rename to Session/Meta/Fonts/SpaceMono-Bold.ttf diff --git a/Session/Fonts/Loki/SpaceMono-Regular.ttf b/Session/Meta/Fonts/SpaceMono-Regular.ttf similarity index 100% rename from Session/Fonts/Loki/SpaceMono-Regular.ttf rename to Session/Meta/Fonts/SpaceMono-Regular.ttf diff --git a/Session/Fonts/dripicons-v2.ttf b/Session/Meta/Fonts/dripicons-v2.ttf similarity index 100% rename from Session/Fonts/dripicons-v2.ttf rename to Session/Meta/Fonts/dripicons-v2.ttf diff --git a/Session/Fonts/fontawesome-webfont.ttf b/Session/Meta/Fonts/fontawesome-webfont.ttf similarity index 100% rename from Session/Fonts/fontawesome-webfont.ttf rename to Session/Meta/Fonts/fontawesome-webfont.ttf diff --git a/Session/Images.xcassets/AppIcon.appiconset/Contents.json b/Session/Meta/Images.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from Session/Images.xcassets/AppIcon.appiconset/Contents.json rename to Session/Meta/Images.xcassets/AppIcon.appiconset/Contents.json diff --git a/Session/Images.xcassets/AppIcon.appiconset/Icon-1024.png b/Session/Meta/Images.xcassets/AppIcon.appiconset/Icon-1024.png similarity index 100% rename from Session/Images.xcassets/AppIcon.appiconset/Icon-1024.png rename to Session/Meta/Images.xcassets/AppIcon.appiconset/Icon-1024.png diff --git a/Session/Images.xcassets/AppIcon.appiconset/Icon-120.png b/Session/Meta/Images.xcassets/AppIcon.appiconset/Icon-120.png similarity index 100% rename from Session/Images.xcassets/AppIcon.appiconset/Icon-120.png rename to Session/Meta/Images.xcassets/AppIcon.appiconset/Icon-120.png diff --git a/Session/Images.xcassets/AppIcon.appiconset/Icon-121.png b/Session/Meta/Images.xcassets/AppIcon.appiconset/Icon-121.png similarity index 100% rename from Session/Images.xcassets/AppIcon.appiconset/Icon-121.png rename to Session/Meta/Images.xcassets/AppIcon.appiconset/Icon-121.png diff --git a/Session/Images.xcassets/AppIcon.appiconset/Icon-152.png b/Session/Meta/Images.xcassets/AppIcon.appiconset/Icon-152.png similarity index 100% rename from Session/Images.xcassets/AppIcon.appiconset/Icon-152.png rename to Session/Meta/Images.xcassets/AppIcon.appiconset/Icon-152.png diff --git a/Session/Images.xcassets/AppIcon.appiconset/Icon-167.png b/Session/Meta/Images.xcassets/AppIcon.appiconset/Icon-167.png similarity index 100% rename from Session/Images.xcassets/AppIcon.appiconset/Icon-167.png rename to Session/Meta/Images.xcassets/AppIcon.appiconset/Icon-167.png diff --git a/Session/Images.xcassets/AppIcon.appiconset/Icon-180.png b/Session/Meta/Images.xcassets/AppIcon.appiconset/Icon-180.png similarity index 100% rename from Session/Images.xcassets/AppIcon.appiconset/Icon-180.png rename to Session/Meta/Images.xcassets/AppIcon.appiconset/Icon-180.png diff --git a/Session/Images.xcassets/AppIcon.appiconset/Icon-20.png b/Session/Meta/Images.xcassets/AppIcon.appiconset/Icon-20.png similarity index 100% rename from Session/Images.xcassets/AppIcon.appiconset/Icon-20.png rename to Session/Meta/Images.xcassets/AppIcon.appiconset/Icon-20.png diff --git a/Session/Images.xcassets/AppIcon.appiconset/Icon-29.png b/Session/Meta/Images.xcassets/AppIcon.appiconset/Icon-29.png similarity index 100% rename from Session/Images.xcassets/AppIcon.appiconset/Icon-29.png rename to Session/Meta/Images.xcassets/AppIcon.appiconset/Icon-29.png diff --git a/Session/Images.xcassets/AppIcon.appiconset/Icon-30.png b/Session/Meta/Images.xcassets/AppIcon.appiconset/Icon-30.png similarity index 100% rename from Session/Images.xcassets/AppIcon.appiconset/Icon-30.png rename to Session/Meta/Images.xcassets/AppIcon.appiconset/Icon-30.png diff --git a/Session/Images.xcassets/AppIcon.appiconset/Icon-40.png b/Session/Meta/Images.xcassets/AppIcon.appiconset/Icon-40.png similarity index 100% rename from Session/Images.xcassets/AppIcon.appiconset/Icon-40.png rename to Session/Meta/Images.xcassets/AppIcon.appiconset/Icon-40.png diff --git a/Session/Images.xcassets/AppIcon.appiconset/Icon-41.png b/Session/Meta/Images.xcassets/AppIcon.appiconset/Icon-41.png similarity index 100% rename from Session/Images.xcassets/AppIcon.appiconset/Icon-41.png rename to Session/Meta/Images.xcassets/AppIcon.appiconset/Icon-41.png diff --git a/Session/Images.xcassets/AppIcon.appiconset/Icon-42.png b/Session/Meta/Images.xcassets/AppIcon.appiconset/Icon-42.png similarity index 100% rename from Session/Images.xcassets/AppIcon.appiconset/Icon-42.png rename to Session/Meta/Images.xcassets/AppIcon.appiconset/Icon-42.png diff --git a/Session/Images.xcassets/AppIcon.appiconset/Icon-58.png b/Session/Meta/Images.xcassets/AppIcon.appiconset/Icon-58.png similarity index 100% rename from Session/Images.xcassets/AppIcon.appiconset/Icon-58.png rename to Session/Meta/Images.xcassets/AppIcon.appiconset/Icon-58.png diff --git a/Session/Images.xcassets/AppIcon.appiconset/Icon-59.png b/Session/Meta/Images.xcassets/AppIcon.appiconset/Icon-59.png similarity index 100% rename from Session/Images.xcassets/AppIcon.appiconset/Icon-59.png rename to Session/Meta/Images.xcassets/AppIcon.appiconset/Icon-59.png diff --git a/Session/Images.xcassets/AppIcon.appiconset/Icon-60.png b/Session/Meta/Images.xcassets/AppIcon.appiconset/Icon-60.png similarity index 100% rename from Session/Images.xcassets/AppIcon.appiconset/Icon-60.png rename to Session/Meta/Images.xcassets/AppIcon.appiconset/Icon-60.png diff --git a/Session/Images.xcassets/AppIcon.appiconset/Icon-76.png b/Session/Meta/Images.xcassets/AppIcon.appiconset/Icon-76.png similarity index 100% rename from Session/Images.xcassets/AppIcon.appiconset/Icon-76.png rename to Session/Meta/Images.xcassets/AppIcon.appiconset/Icon-76.png diff --git a/Session/Images.xcassets/AppIcon.appiconset/Icon-80.png b/Session/Meta/Images.xcassets/AppIcon.appiconset/Icon-80.png similarity index 100% rename from Session/Images.xcassets/AppIcon.appiconset/Icon-80.png rename to Session/Meta/Images.xcassets/AppIcon.appiconset/Icon-80.png diff --git a/Session/Images.xcassets/AppIcon.appiconset/Icon-81.png b/Session/Meta/Images.xcassets/AppIcon.appiconset/Icon-81.png similarity index 100% rename from Session/Images.xcassets/AppIcon.appiconset/Icon-81.png rename to Session/Meta/Images.xcassets/AppIcon.appiconset/Icon-81.png diff --git a/Session/Images.xcassets/AppIcon.appiconset/Icon-87.png b/Session/Meta/Images.xcassets/AppIcon.appiconset/Icon-87.png similarity index 100% rename from Session/Images.xcassets/AppIcon.appiconset/Icon-87.png rename to Session/Meta/Images.xcassets/AppIcon.appiconset/Icon-87.png diff --git a/Session/Images.xcassets/Contents.json b/Session/Meta/Images.xcassets/Contents.json similarity index 100% rename from Session/Images.xcassets/Contents.json rename to Session/Meta/Images.xcassets/Contents.json diff --git a/Session/Images.xcassets/Loki V2/AddPerson.imageset/AddPerson.pdf b/Session/Meta/Images.xcassets/Loki V2/AddPerson.imageset/AddPerson.pdf similarity index 100% rename from Session/Images.xcassets/Loki V2/AddPerson.imageset/AddPerson.pdf rename to Session/Meta/Images.xcassets/Loki V2/AddPerson.imageset/AddPerson.pdf diff --git a/Session/Images.xcassets/Loki V2/AddPerson.imageset/Contents.json b/Session/Meta/Images.xcassets/Loki V2/AddPerson.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/Loki V2/AddPerson.imageset/Contents.json rename to Session/Meta/Images.xcassets/Loki V2/AddPerson.imageset/Contents.json diff --git a/Session/Images.xcassets/Loki V2/ArrowUpDarkMode.imageset/ArrowUp.pdf b/Session/Meta/Images.xcassets/Loki V2/ArrowUpDarkMode.imageset/ArrowUp.pdf similarity index 100% rename from Session/Images.xcassets/Loki V2/ArrowUpDarkMode.imageset/ArrowUp.pdf rename to Session/Meta/Images.xcassets/Loki V2/ArrowUpDarkMode.imageset/ArrowUp.pdf diff --git a/Session/Images.xcassets/Loki V2/ArrowUpDarkMode.imageset/Contents.json b/Session/Meta/Images.xcassets/Loki V2/ArrowUpDarkMode.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/Loki V2/ArrowUpDarkMode.imageset/Contents.json rename to Session/Meta/Images.xcassets/Loki V2/ArrowUpDarkMode.imageset/Contents.json diff --git a/Session/Images.xcassets/Loki V2/ArrowUpLightMode.imageset/ArrowUpLightMode.pdf b/Session/Meta/Images.xcassets/Loki V2/ArrowUpLightMode.imageset/ArrowUpLightMode.pdf similarity index 100% rename from Session/Images.xcassets/Loki V2/ArrowUpLightMode.imageset/ArrowUpLightMode.pdf rename to Session/Meta/Images.xcassets/Loki V2/ArrowUpLightMode.imageset/ArrowUpLightMode.pdf diff --git a/Session/Images.xcassets/Loki V2/ArrowUpLightMode.imageset/Contents.json b/Session/Meta/Images.xcassets/Loki V2/ArrowUpLightMode.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/Loki V2/ArrowUpLightMode.imageset/Contents.json rename to Session/Meta/Images.xcassets/Loki V2/ArrowUpLightMode.imageset/Contents.json diff --git a/Session/Images.xcassets/Loki V2/ChatBubbles.imageset/ChatBubbles.pdf b/Session/Meta/Images.xcassets/Loki V2/ChatBubbles.imageset/ChatBubbles.pdf similarity index 100% rename from Session/Images.xcassets/Loki V2/ChatBubbles.imageset/ChatBubbles.pdf rename to Session/Meta/Images.xcassets/Loki V2/ChatBubbles.imageset/ChatBubbles.pdf diff --git a/Session/Images.xcassets/Loki V2/ChatBubbles.imageset/Contents.json b/Session/Meta/Images.xcassets/Loki V2/ChatBubbles.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/Loki V2/ChatBubbles.imageset/Contents.json rename to Session/Meta/Images.xcassets/Loki V2/ChatBubbles.imageset/Contents.json diff --git a/Session/Images.xcassets/Loki V2/Check.imageset/Check.pdf b/Session/Meta/Images.xcassets/Loki V2/Check.imageset/Check.pdf similarity index 100% rename from Session/Images.xcassets/Loki V2/Check.imageset/Check.pdf rename to Session/Meta/Images.xcassets/Loki V2/Check.imageset/Check.pdf diff --git a/Session/Images.xcassets/Loki V2/Check.imageset/Contents.json b/Session/Meta/Images.xcassets/Loki V2/Check.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/Loki V2/Check.imageset/Contents.json rename to Session/Meta/Images.xcassets/Loki V2/Check.imageset/Contents.json diff --git a/Session/Images.xcassets/Loki V2/Circle.imageset/Circle.pdf b/Session/Meta/Images.xcassets/Loki V2/Circle.imageset/Circle.pdf similarity index 100% rename from Session/Images.xcassets/Loki V2/Circle.imageset/Circle.pdf rename to Session/Meta/Images.xcassets/Loki V2/Circle.imageset/Circle.pdf diff --git a/Session/Images.xcassets/Loki V2/Circle.imageset/Contents.json b/Session/Meta/Images.xcassets/Loki V2/Circle.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/Loki V2/Circle.imageset/Contents.json rename to Session/Meta/Images.xcassets/Loki V2/Circle.imageset/Contents.json diff --git a/Session/Images.xcassets/Loki V2/CircleCheck.imageset/CircleCheck.pdf b/Session/Meta/Images.xcassets/Loki V2/CircleCheck.imageset/CircleCheck.pdf similarity index 100% rename from Session/Images.xcassets/Loki V2/CircleCheck.imageset/CircleCheck.pdf rename to Session/Meta/Images.xcassets/Loki V2/CircleCheck.imageset/CircleCheck.pdf diff --git a/Session/Images.xcassets/Loki V2/CircleCheck.imageset/Contents.json b/Session/Meta/Images.xcassets/Loki V2/CircleCheck.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/Loki V2/CircleCheck.imageset/Contents.json rename to Session/Meta/Images.xcassets/Loki V2/CircleCheck.imageset/Contents.json diff --git a/Session/Images.xcassets/Loki V2/CircleDotDotDot.imageset/CircleDotDotDot.pdf b/Session/Meta/Images.xcassets/Loki V2/CircleDotDotDot.imageset/CircleDotDotDot.pdf similarity index 100% rename from Session/Images.xcassets/Loki V2/CircleDotDotDot.imageset/CircleDotDotDot.pdf rename to Session/Meta/Images.xcassets/Loki V2/CircleDotDotDot.imageset/CircleDotDotDot.pdf diff --git a/Session/Images.xcassets/Loki V2/CircleDotDotDot.imageset/Contents.json b/Session/Meta/Images.xcassets/Loki V2/CircleDotDotDot.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/Loki V2/CircleDotDotDot.imageset/Contents.json rename to Session/Meta/Images.xcassets/Loki V2/CircleDotDotDot.imageset/Contents.json diff --git a/Session/Images.xcassets/Loki V2/CirclePause.imageset/CirclePause.pdf b/Session/Meta/Images.xcassets/Loki V2/CirclePause.imageset/CirclePause.pdf similarity index 100% rename from Session/Images.xcassets/Loki V2/CirclePause.imageset/CirclePause.pdf rename to Session/Meta/Images.xcassets/Loki V2/CirclePause.imageset/CirclePause.pdf diff --git a/Session/Images.xcassets/Loki V2/CirclePause.imageset/Contents.json b/Session/Meta/Images.xcassets/Loki V2/CirclePause.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/Loki V2/CirclePause.imageset/Contents.json rename to Session/Meta/Images.xcassets/Loki V2/CirclePause.imageset/Contents.json diff --git a/Session/Images.xcassets/Loki V2/CirclePlay.imageset/CirclePlay.pdf b/Session/Meta/Images.xcassets/Loki V2/CirclePlay.imageset/CirclePlay.pdf similarity index 100% rename from Session/Images.xcassets/Loki V2/CirclePlay.imageset/CirclePlay.pdf rename to Session/Meta/Images.xcassets/Loki V2/CirclePlay.imageset/CirclePlay.pdf diff --git a/Session/Images.xcassets/Loki V2/CirclePlay.imageset/Contents.json b/Session/Meta/Images.xcassets/Loki V2/CirclePlay.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/Loki V2/CirclePlay.imageset/Contents.json rename to Session/Meta/Images.xcassets/Loki V2/CirclePlay.imageset/Contents.json diff --git a/Session/Images.xcassets/Loki V2/CirclePlus.imageset/CirclePlus.pdf b/Session/Meta/Images.xcassets/Loki V2/CirclePlus.imageset/CirclePlus.pdf similarity index 100% rename from Session/Images.xcassets/Loki V2/CirclePlus.imageset/CirclePlus.pdf rename to Session/Meta/Images.xcassets/Loki V2/CirclePlus.imageset/CirclePlus.pdf diff --git a/Session/Images.xcassets/Loki V2/CirclePlus.imageset/Contents.json b/Session/Meta/Images.xcassets/Loki V2/CirclePlus.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/Loki V2/CirclePlus.imageset/Contents.json rename to Session/Meta/Images.xcassets/Loki V2/CirclePlus.imageset/Contents.json diff --git a/Session/Images.xcassets/Loki V2/Contents.json b/Session/Meta/Images.xcassets/Loki V2/Contents.json similarity index 100% rename from Session/Images.xcassets/Loki V2/Contents.json rename to Session/Meta/Images.xcassets/Loki V2/Contents.json diff --git a/Session/Images.xcassets/Loki V2/FilledCircleCheckDarkMode.imageset/Contents.json b/Session/Meta/Images.xcassets/Loki V2/FilledCircleCheckDarkMode.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/Loki V2/FilledCircleCheckDarkMode.imageset/Contents.json rename to Session/Meta/Images.xcassets/Loki V2/FilledCircleCheckDarkMode.imageset/Contents.json diff --git a/Session/Images.xcassets/Loki V2/FilledCircleCheckDarkMode.imageset/FilledCircleCheckDarkMode.pdf b/Session/Meta/Images.xcassets/Loki V2/FilledCircleCheckDarkMode.imageset/FilledCircleCheckDarkMode.pdf similarity index 100% rename from Session/Images.xcassets/Loki V2/FilledCircleCheckDarkMode.imageset/FilledCircleCheckDarkMode.pdf rename to Session/Meta/Images.xcassets/Loki V2/FilledCircleCheckDarkMode.imageset/FilledCircleCheckDarkMode.pdf diff --git a/Session/Images.xcassets/Loki V2/FilledCircleCheckLightMode.imageset/Contents.json b/Session/Meta/Images.xcassets/Loki V2/FilledCircleCheckLightMode.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/Loki V2/FilledCircleCheckLightMode.imageset/Contents.json rename to Session/Meta/Images.xcassets/Loki V2/FilledCircleCheckLightMode.imageset/Contents.json diff --git a/Session/Images.xcassets/Loki V2/FilledCircleCheckLightMode.imageset/FilledCircleCheckLightMode.pdf b/Session/Meta/Images.xcassets/Loki V2/FilledCircleCheckLightMode.imageset/FilledCircleCheckLightMode.pdf similarity index 100% rename from Session/Images.xcassets/Loki V2/FilledCircleCheckLightMode.imageset/FilledCircleCheckLightMode.pdf rename to Session/Meta/Images.xcassets/Loki V2/FilledCircleCheckLightMode.imageset/FilledCircleCheckLightMode.pdf diff --git a/Session/Images.xcassets/Loki V2/Flag.imageset/Contents.json b/Session/Meta/Images.xcassets/Loki V2/Flag.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/Loki V2/Flag.imageset/Contents.json rename to Session/Meta/Images.xcassets/Loki V2/Flag.imageset/Contents.json diff --git a/Session/Images.xcassets/Loki V2/Flag.imageset/Flag.pdf b/Session/Meta/Images.xcassets/Loki V2/Flag.imageset/Flag.pdf similarity index 100% rename from Session/Images.xcassets/Loki V2/Flag.imageset/Flag.pdf rename to Session/Meta/Images.xcassets/Loki V2/Flag.imageset/Flag.pdf diff --git a/Session/Images.xcassets/Loki V2/Gear.imageset/Contents.json b/Session/Meta/Images.xcassets/Loki V2/Gear.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/Loki V2/Gear.imageset/Contents.json rename to Session/Meta/Images.xcassets/Loki V2/Gear.imageset/Contents.json diff --git a/Session/Images.xcassets/Loki V2/Gear.imageset/Gear.pdf b/Session/Meta/Images.xcassets/Loki V2/Gear.imageset/Gear.pdf similarity index 100% rename from Session/Images.xcassets/Loki V2/Gear.imageset/Gear.pdf rename to Session/Meta/Images.xcassets/Loki V2/Gear.imageset/Gear.pdf diff --git a/Session/Images.xcassets/Loki V2/Globe.imageset/Contents.json b/Session/Meta/Images.xcassets/Loki V2/Globe.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/Loki V2/Globe.imageset/Contents.json rename to Session/Meta/Images.xcassets/Loki V2/Globe.imageset/Contents.json diff --git a/Session/Images.xcassets/Loki V2/Globe.imageset/Globe.pdf b/Session/Meta/Images.xcassets/Loki V2/Globe.imageset/Globe.pdf similarity index 100% rename from Session/Images.xcassets/Loki V2/Globe.imageset/Globe.pdf rename to Session/Meta/Images.xcassets/Loki V2/Globe.imageset/Globe.pdf diff --git a/Session/Images.xcassets/Loki V2/Group.imageset/Contents.json b/Session/Meta/Images.xcassets/Loki V2/Group.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/Loki V2/Group.imageset/Contents.json rename to Session/Meta/Images.xcassets/Loki V2/Group.imageset/Contents.json diff --git a/Session/Images.xcassets/Loki V2/Group.imageset/Group.pdf b/Session/Meta/Images.xcassets/Loki V2/Group.imageset/Group.pdf similarity index 100% rename from Session/Images.xcassets/Loki V2/Group.imageset/Group.pdf rename to Session/Meta/Images.xcassets/Loki V2/Group.imageset/Group.pdf diff --git a/Session/Images.xcassets/Loki V2/Key.imageset/Contents.json b/Session/Meta/Images.xcassets/Loki V2/Key.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/Loki V2/Key.imageset/Contents.json rename to Session/Meta/Images.xcassets/Loki V2/Key.imageset/Contents.json diff --git a/Session/Images.xcassets/Loki V2/Key.imageset/Key.pdf b/Session/Meta/Images.xcassets/Loki V2/Key.imageset/Key.pdf similarity index 100% rename from Session/Images.xcassets/Loki V2/Key.imageset/Key.pdf rename to Session/Meta/Images.xcassets/Loki V2/Key.imageset/Key.pdf diff --git a/Session/Images.xcassets/Loki V2/MagnifyingGlass.imageset/Contents.json b/Session/Meta/Images.xcassets/Loki V2/MagnifyingGlass.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/Loki V2/MagnifyingGlass.imageset/Contents.json rename to Session/Meta/Images.xcassets/Loki V2/MagnifyingGlass.imageset/Contents.json diff --git a/Session/Images.xcassets/Loki V2/MagnifyingGlass.imageset/MagnifyingGlass.pdf b/Session/Meta/Images.xcassets/Loki V2/MagnifyingGlass.imageset/MagnifyingGlass.pdf similarity index 100% rename from Session/Images.xcassets/Loki V2/MagnifyingGlass.imageset/MagnifyingGlass.pdf rename to Session/Meta/Images.xcassets/Loki V2/MagnifyingGlass.imageset/MagnifyingGlass.pdf diff --git a/Session/Images.xcassets/Loki V2/Message.imageset/Contents.json b/Session/Meta/Images.xcassets/Loki V2/Message.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/Loki V2/Message.imageset/Contents.json rename to Session/Meta/Images.xcassets/Loki V2/Message.imageset/Contents.json diff --git a/Session/Images.xcassets/Loki V2/Message.imageset/Message.pdf b/Session/Meta/Images.xcassets/Loki V2/Message.imageset/Message.pdf similarity index 100% rename from Session/Images.xcassets/Loki V2/Message.imageset/Message.pdf rename to Session/Meta/Images.xcassets/Loki V2/Message.imageset/Message.pdf diff --git a/Session/Images.xcassets/Loki V2/Microphone.imageset/Contents.json b/Session/Meta/Images.xcassets/Loki V2/Microphone.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/Loki V2/Microphone.imageset/Contents.json rename to Session/Meta/Images.xcassets/Loki V2/Microphone.imageset/Contents.json diff --git a/Session/Images.xcassets/Loki V2/Microphone.imageset/Microphone.pdf b/Session/Meta/Images.xcassets/Loki V2/Microphone.imageset/Microphone.pdf similarity index 100% rename from Session/Images.xcassets/Loki V2/Microphone.imageset/Microphone.pdf rename to Session/Meta/Images.xcassets/Loki V2/Microphone.imageset/Microphone.pdf diff --git a/Session/Images.xcassets/Loki V2/Mute.imageset/Contents.json b/Session/Meta/Images.xcassets/Loki V2/Mute.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/Loki V2/Mute.imageset/Contents.json rename to Session/Meta/Images.xcassets/Loki V2/Mute.imageset/Contents.json diff --git a/Session/Images.xcassets/Loki V2/Mute.imageset/Mute.pdf b/Session/Meta/Images.xcassets/Loki V2/Mute.imageset/Mute.pdf similarity index 100% rename from Session/Images.xcassets/Loki V2/Mute.imageset/Mute.pdf rename to Session/Meta/Images.xcassets/Loki V2/Mute.imageset/Mute.pdf diff --git a/Session/Images.xcassets/Loki V2/Pause.imageset/Contents.json b/Session/Meta/Images.xcassets/Loki V2/Pause.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/Loki V2/Pause.imageset/Contents.json rename to Session/Meta/Images.xcassets/Loki V2/Pause.imageset/Contents.json diff --git a/Session/Images.xcassets/Loki V2/Pause.imageset/Pause.pdf b/Session/Meta/Images.xcassets/Loki V2/Pause.imageset/Pause.pdf similarity index 100% rename from Session/Images.xcassets/Loki V2/Pause.imageset/Pause.pdf rename to Session/Meta/Images.xcassets/Loki V2/Pause.imageset/Pause.pdf diff --git a/Session/Images.xcassets/Loki V2/People.imageset/Contents.json b/Session/Meta/Images.xcassets/Loki V2/People.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/Loki V2/People.imageset/Contents.json rename to Session/Meta/Images.xcassets/Loki V2/People.imageset/Contents.json diff --git a/Session/Images.xcassets/Loki V2/People.imageset/People.pdf b/Session/Meta/Images.xcassets/Loki V2/People.imageset/People.pdf similarity index 100% rename from Session/Images.xcassets/Loki V2/People.imageset/People.pdf rename to Session/Meta/Images.xcassets/Loki V2/People.imageset/People.pdf diff --git a/Session/Images.xcassets/Loki V2/Play.imageset/Contents.json b/Session/Meta/Images.xcassets/Loki V2/Play.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/Loki V2/Play.imageset/Contents.json rename to Session/Meta/Images.xcassets/Loki V2/Play.imageset/Contents.json diff --git a/Session/Images.xcassets/Loki V2/Play.imageset/Play.pdf b/Session/Meta/Images.xcassets/Loki V2/Play.imageset/Play.pdf similarity index 100% rename from Session/Images.xcassets/Loki V2/Play.imageset/Play.pdf rename to Session/Meta/Images.xcassets/Loki V2/Play.imageset/Play.pdf diff --git a/Session/Images.xcassets/Loki V2/Plus.imageset/Contents.json b/Session/Meta/Images.xcassets/Loki V2/Plus.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/Loki V2/Plus.imageset/Contents.json rename to Session/Meta/Images.xcassets/Loki V2/Plus.imageset/Contents.json diff --git a/Session/Images.xcassets/Loki V2/Plus.imageset/Plus.pdf b/Session/Meta/Images.xcassets/Loki V2/Plus.imageset/Plus.pdf similarity index 100% rename from Session/Images.xcassets/Loki V2/Plus.imageset/Plus.pdf rename to Session/Meta/Images.xcassets/Loki V2/Plus.imageset/Plus.pdf diff --git a/Session/Images.xcassets/Loki V2/QRCode.imageset/Contents.json b/Session/Meta/Images.xcassets/Loki V2/QRCode.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/Loki V2/QRCode.imageset/Contents.json rename to Session/Meta/Images.xcassets/Loki V2/QRCode.imageset/Contents.json diff --git a/Session/Images.xcassets/Loki V2/QRCode.imageset/QRCodeFilled.pdf b/Session/Meta/Images.xcassets/Loki V2/QRCode.imageset/QRCodeFilled.pdf similarity index 100% rename from Session/Images.xcassets/Loki V2/QRCode.imageset/QRCodeFilled.pdf rename to Session/Meta/Images.xcassets/Loki V2/QRCode.imageset/QRCodeFilled.pdf diff --git a/Session/Images.xcassets/Loki V2/QuestionMark.imageset/Contents.json b/Session/Meta/Images.xcassets/Loki V2/QuestionMark.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/Loki V2/QuestionMark.imageset/Contents.json rename to Session/Meta/Images.xcassets/Loki V2/QuestionMark.imageset/Contents.json diff --git a/Session/Images.xcassets/Loki V2/QuestionMark.imageset/QuestionMark.pdf b/Session/Meta/Images.xcassets/Loki V2/QuestionMark.imageset/QuestionMark.pdf similarity index 100% rename from Session/Images.xcassets/Loki V2/QuestionMark.imageset/QuestionMark.pdf rename to Session/Meta/Images.xcassets/Loki V2/QuestionMark.imageset/QuestionMark.pdf diff --git a/Session/Images.xcassets/Loki V2/SessionGreen32.imageset/Contents.json b/Session/Meta/Images.xcassets/Loki V2/SessionGreen32.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/Loki V2/SessionGreen32.imageset/Contents.json rename to Session/Meta/Images.xcassets/Loki V2/SessionGreen32.imageset/Contents.json diff --git a/Session/Images.xcassets/Loki V2/SessionGreen32.imageset/SessionGreen32.png b/Session/Meta/Images.xcassets/Loki V2/SessionGreen32.imageset/SessionGreen32.png similarity index 100% rename from Session/Images.xcassets/Loki V2/SessionGreen32.imageset/SessionGreen32.png rename to Session/Meta/Images.xcassets/Loki V2/SessionGreen32.imageset/SessionGreen32.png diff --git a/Session/Images.xcassets/Loki V2/SessionGreen32.imageset/SessionGreen32@2x.png b/Session/Meta/Images.xcassets/Loki V2/SessionGreen32.imageset/SessionGreen32@2x.png similarity index 100% rename from Session/Images.xcassets/Loki V2/SessionGreen32.imageset/SessionGreen32@2x.png rename to Session/Meta/Images.xcassets/Loki V2/SessionGreen32.imageset/SessionGreen32@2x.png diff --git a/Session/Images.xcassets/Loki V2/SessionGreen32.imageset/SessionGreen32@3x.png b/Session/Meta/Images.xcassets/Loki V2/SessionGreen32.imageset/SessionGreen32@3x.png similarity index 100% rename from Session/Images.xcassets/Loki V2/SessionGreen32.imageset/SessionGreen32@3x.png rename to Session/Meta/Images.xcassets/Loki V2/SessionGreen32.imageset/SessionGreen32@3x.png diff --git a/Session/Images.xcassets/Loki V2/SessionGreen64.imageset/Contents.json b/Session/Meta/Images.xcassets/Loki V2/SessionGreen64.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/Loki V2/SessionGreen64.imageset/Contents.json rename to Session/Meta/Images.xcassets/Loki V2/SessionGreen64.imageset/Contents.json diff --git a/Session/Images.xcassets/Loki V2/SessionGreen64.imageset/SessionGreen64.png b/Session/Meta/Images.xcassets/Loki V2/SessionGreen64.imageset/SessionGreen64.png similarity index 100% rename from Session/Images.xcassets/Loki V2/SessionGreen64.imageset/SessionGreen64.png rename to Session/Meta/Images.xcassets/Loki V2/SessionGreen64.imageset/SessionGreen64.png diff --git a/Session/Images.xcassets/Loki V2/SessionGreen64.imageset/SessionGreen64@2x.png b/Session/Meta/Images.xcassets/Loki V2/SessionGreen64.imageset/SessionGreen64@2x.png similarity index 100% rename from Session/Images.xcassets/Loki V2/SessionGreen64.imageset/SessionGreen64@2x.png rename to Session/Meta/Images.xcassets/Loki V2/SessionGreen64.imageset/SessionGreen64@2x.png diff --git a/Session/Images.xcassets/Loki V2/SessionGreen64.imageset/SessionGreen64@3x.png b/Session/Meta/Images.xcassets/Loki V2/SessionGreen64.imageset/SessionGreen64@3x.png similarity index 100% rename from Session/Images.xcassets/Loki V2/SessionGreen64.imageset/SessionGreen64@3x.png rename to Session/Meta/Images.xcassets/Loki V2/SessionGreen64.imageset/SessionGreen64@3x.png diff --git a/Session/Images.xcassets/Loki V2/SessionWhite16.imageset/Contents.json b/Session/Meta/Images.xcassets/Loki V2/SessionWhite16.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/Loki V2/SessionWhite16.imageset/Contents.json rename to Session/Meta/Images.xcassets/Loki V2/SessionWhite16.imageset/Contents.json diff --git a/Session/Images.xcassets/Loki V2/SessionWhite16.imageset/SessionWhite16.png b/Session/Meta/Images.xcassets/Loki V2/SessionWhite16.imageset/SessionWhite16.png similarity index 100% rename from Session/Images.xcassets/Loki V2/SessionWhite16.imageset/SessionWhite16.png rename to Session/Meta/Images.xcassets/Loki V2/SessionWhite16.imageset/SessionWhite16.png diff --git a/Session/Images.xcassets/Loki V2/SessionWhite16.imageset/SessionWhite16@2x.png b/Session/Meta/Images.xcassets/Loki V2/SessionWhite16.imageset/SessionWhite16@2x.png similarity index 100% rename from Session/Images.xcassets/Loki V2/SessionWhite16.imageset/SessionWhite16@2x.png rename to Session/Meta/Images.xcassets/Loki V2/SessionWhite16.imageset/SessionWhite16@2x.png diff --git a/Session/Images.xcassets/Loki V2/SessionWhite16.imageset/SessionWhite16@3x.png b/Session/Meta/Images.xcassets/Loki V2/SessionWhite16.imageset/SessionWhite16@3x.png similarity index 100% rename from Session/Images.xcassets/Loki V2/SessionWhite16.imageset/SessionWhite16@3x.png rename to Session/Meta/Images.xcassets/Loki V2/SessionWhite16.imageset/SessionWhite16@3x.png diff --git a/Session/Images.xcassets/Loki V2/SessionWhite24.imageset/Contents.json b/Session/Meta/Images.xcassets/Loki V2/SessionWhite24.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/Loki V2/SessionWhite24.imageset/Contents.json rename to Session/Meta/Images.xcassets/Loki V2/SessionWhite24.imageset/Contents.json diff --git a/Session/Images.xcassets/Loki V2/SessionWhite24.imageset/SessionWhite24.png b/Session/Meta/Images.xcassets/Loki V2/SessionWhite24.imageset/SessionWhite24.png similarity index 100% rename from Session/Images.xcassets/Loki V2/SessionWhite24.imageset/SessionWhite24.png rename to Session/Meta/Images.xcassets/Loki V2/SessionWhite24.imageset/SessionWhite24.png diff --git a/Session/Images.xcassets/Loki V2/SessionWhite24.imageset/SessionWhite24@2x.png b/Session/Meta/Images.xcassets/Loki V2/SessionWhite24.imageset/SessionWhite24@2x.png similarity index 100% rename from Session/Images.xcassets/Loki V2/SessionWhite24.imageset/SessionWhite24@2x.png rename to Session/Meta/Images.xcassets/Loki V2/SessionWhite24.imageset/SessionWhite24@2x.png diff --git a/Session/Images.xcassets/Loki V2/SessionWhite24.imageset/SessionWhite24@3x.png b/Session/Meta/Images.xcassets/Loki V2/SessionWhite24.imageset/SessionWhite24@3x.png similarity index 100% rename from Session/Images.xcassets/Loki V2/SessionWhite24.imageset/SessionWhite24@3x.png rename to Session/Meta/Images.xcassets/Loki V2/SessionWhite24.imageset/SessionWhite24@3x.png diff --git a/Session/Images.xcassets/Loki V2/SessionWhite40.imageset/Contents.json b/Session/Meta/Images.xcassets/Loki V2/SessionWhite40.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/Loki V2/SessionWhite40.imageset/Contents.json rename to Session/Meta/Images.xcassets/Loki V2/SessionWhite40.imageset/Contents.json diff --git a/Session/Images.xcassets/Loki V2/SessionWhite40.imageset/SessionWhite40.png b/Session/Meta/Images.xcassets/Loki V2/SessionWhite40.imageset/SessionWhite40.png similarity index 100% rename from Session/Images.xcassets/Loki V2/SessionWhite40.imageset/SessionWhite40.png rename to Session/Meta/Images.xcassets/Loki V2/SessionWhite40.imageset/SessionWhite40.png diff --git a/Session/Images.xcassets/Loki V2/SessionWhite40.imageset/SessionWhite40@2x.png b/Session/Meta/Images.xcassets/Loki V2/SessionWhite40.imageset/SessionWhite40@2x.png similarity index 100% rename from Session/Images.xcassets/Loki V2/SessionWhite40.imageset/SessionWhite40@2x.png rename to Session/Meta/Images.xcassets/Loki V2/SessionWhite40.imageset/SessionWhite40@2x.png diff --git a/Session/Images.xcassets/Loki V2/SessionWhite40.imageset/SessionWhite40@3x.png b/Session/Meta/Images.xcassets/Loki V2/SessionWhite40.imageset/SessionWhite40@3x.png similarity index 100% rename from Session/Images.xcassets/Loki V2/SessionWhite40.imageset/SessionWhite40@3x.png rename to Session/Meta/Images.xcassets/Loki V2/SessionWhite40.imageset/SessionWhite40@3x.png diff --git a/Session/Images.xcassets/Loki V2/Star.imageset/Contents.json b/Session/Meta/Images.xcassets/Loki V2/Star.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/Loki V2/Star.imageset/Contents.json rename to Session/Meta/Images.xcassets/Loki V2/Star.imageset/Contents.json diff --git a/Session/Images.xcassets/Loki V2/Star.imageset/StarOutline.pdf b/Session/Meta/Images.xcassets/Loki V2/Star.imageset/StarOutline.pdf similarity index 100% rename from Session/Images.xcassets/Loki V2/Star.imageset/StarOutline.pdf rename to Session/Meta/Images.xcassets/Loki V2/Star.imageset/StarOutline.pdf diff --git a/Session/Images.xcassets/Loki V2/Sun.imageset/Contents.json b/Session/Meta/Images.xcassets/Loki V2/Sun.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/Loki V2/Sun.imageset/Contents.json rename to Session/Meta/Images.xcassets/Loki V2/Sun.imageset/Contents.json diff --git a/Session/Images.xcassets/Loki V2/Sun.imageset/Sun.pdf b/Session/Meta/Images.xcassets/Loki V2/Sun.imageset/Sun.pdf similarity index 100% rename from Session/Images.xcassets/Loki V2/Sun.imageset/Sun.pdf rename to Session/Meta/Images.xcassets/Loki V2/Sun.imageset/Sun.pdf diff --git a/Session/Images.xcassets/Loki V2/X.imageset/Contents.json b/Session/Meta/Images.xcassets/Loki V2/X.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/Loki V2/X.imageset/Contents.json rename to Session/Meta/Images.xcassets/Loki V2/X.imageset/Contents.json diff --git a/Session/Images.xcassets/Loki V2/X.imageset/X.pdf b/Session/Meta/Images.xcassets/Loki V2/X.imageset/X.pdf similarity index 100% rename from Session/Images.xcassets/Loki V2/X.imageset/X.pdf rename to Session/Meta/Images.xcassets/Loki V2/X.imageset/X.pdf diff --git a/Session/Images.xcassets/Loki/Cog.imageset/Contents.json b/Session/Meta/Images.xcassets/Loki/Cog.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/Loki/Cog.imageset/Contents.json rename to Session/Meta/Images.xcassets/Loki/Cog.imageset/Contents.json diff --git a/Session/Images.xcassets/Loki/Cog.imageset/pow.png b/Session/Meta/Images.xcassets/Loki/Cog.imageset/pow.png similarity index 100% rename from Session/Images.xcassets/Loki/Cog.imageset/pow.png rename to Session/Meta/Images.xcassets/Loki/Cog.imageset/pow.png diff --git a/Session/Images.xcassets/Loki/Cog.imageset/pow@2x.png b/Session/Meta/Images.xcassets/Loki/Cog.imageset/pow@2x.png similarity index 100% rename from Session/Images.xcassets/Loki/Cog.imageset/pow@2x.png rename to Session/Meta/Images.xcassets/Loki/Cog.imageset/pow@2x.png diff --git a/Session/Images.xcassets/Loki/Cog.imageset/pow@3x.png b/Session/Meta/Images.xcassets/Loki/Cog.imageset/pow@3x.png similarity index 100% rename from Session/Images.xcassets/Loki/Cog.imageset/pow@3x.png rename to Session/Meta/Images.xcassets/Loki/Cog.imageset/pow@3x.png diff --git a/Session/Images.xcassets/Loki/Contents.json b/Session/Meta/Images.xcassets/Loki/Contents.json similarity index 100% rename from Session/Images.xcassets/Loki/Contents.json rename to Session/Meta/Images.xcassets/Loki/Contents.json diff --git a/Session/Images.xcassets/Loki/Crown.imageset/Contents.json b/Session/Meta/Images.xcassets/Loki/Crown.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/Loki/Crown.imageset/Contents.json rename to Session/Meta/Images.xcassets/Loki/Crown.imageset/Contents.json diff --git a/Session/Images.xcassets/Loki/Crown.imageset/crown.pdf b/Session/Meta/Images.xcassets/Loki/Crown.imageset/crown.pdf similarity index 100% rename from Session/Images.xcassets/Loki/Crown.imageset/crown.pdf rename to Session/Meta/Images.xcassets/Loki/Crown.imageset/crown.pdf diff --git a/Session/Images.xcassets/Loki/Loki.imageset/Contents.json b/Session/Meta/Images.xcassets/Loki/Loki.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/Loki/Loki.imageset/Contents.json rename to Session/Meta/Images.xcassets/Loki/Loki.imageset/Contents.json diff --git a/Session/Images.xcassets/Loki/Loki.imageset/Loki_Logo_Icon_White.pdf b/Session/Meta/Images.xcassets/Loki/Loki.imageset/Loki_Logo_Icon_White.pdf similarity index 100% rename from Session/Images.xcassets/Loki/Loki.imageset/Loki_Logo_Icon_White.pdf rename to Session/Meta/Images.xcassets/Loki/Loki.imageset/Loki_Logo_Icon_White.pdf diff --git a/Session/Images.xcassets/NavBarBack.imageset/Contents.json b/Session/Meta/Images.xcassets/NavBarBack.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/NavBarBack.imageset/Contents.json rename to Session/Meta/Images.xcassets/NavBarBack.imageset/Contents.json diff --git a/Session/Images.xcassets/NavBarBack.imageset/NavBarBackWhite@1x.png b/Session/Meta/Images.xcassets/NavBarBack.imageset/NavBarBackWhite@1x.png similarity index 100% rename from Session/Images.xcassets/NavBarBack.imageset/NavBarBackWhite@1x.png rename to Session/Meta/Images.xcassets/NavBarBack.imageset/NavBarBackWhite@1x.png diff --git a/Session/Images.xcassets/NavBarBack.imageset/NavBarBackWhite@2x.png b/Session/Meta/Images.xcassets/NavBarBack.imageset/NavBarBackWhite@2x.png similarity index 100% rename from Session/Images.xcassets/NavBarBack.imageset/NavBarBackWhite@2x.png rename to Session/Meta/Images.xcassets/NavBarBack.imageset/NavBarBackWhite@2x.png diff --git a/Session/Images.xcassets/NavBarBack.imageset/NavBarBackWhite@3x.png b/Session/Meta/Images.xcassets/NavBarBack.imageset/NavBarBackWhite@3x.png similarity index 100% rename from Session/Images.xcassets/NavBarBack.imageset/NavBarBackWhite@3x.png rename to Session/Meta/Images.xcassets/NavBarBack.imageset/NavBarBackWhite@3x.png diff --git a/Session/Images.xcassets/NavBarBackRTL.imageset/Contents.json b/Session/Meta/Images.xcassets/NavBarBackRTL.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/NavBarBackRTL.imageset/Contents.json rename to Session/Meta/Images.xcassets/NavBarBackRTL.imageset/Contents.json diff --git a/Session/Images.xcassets/NavBarBackRTL.imageset/NavBarBackWhiteRTL@1x.png b/Session/Meta/Images.xcassets/NavBarBackRTL.imageset/NavBarBackWhiteRTL@1x.png similarity index 100% rename from Session/Images.xcassets/NavBarBackRTL.imageset/NavBarBackWhiteRTL@1x.png rename to Session/Meta/Images.xcassets/NavBarBackRTL.imageset/NavBarBackWhiteRTL@1x.png diff --git a/Session/Images.xcassets/NavBarBackRTL.imageset/NavBarBackWhiteRTL@2x.png b/Session/Meta/Images.xcassets/NavBarBackRTL.imageset/NavBarBackWhiteRTL@2x.png similarity index 100% rename from Session/Images.xcassets/NavBarBackRTL.imageset/NavBarBackWhiteRTL@2x.png rename to Session/Meta/Images.xcassets/NavBarBackRTL.imageset/NavBarBackWhiteRTL@2x.png diff --git a/Session/Images.xcassets/NavBarBackRTL.imageset/NavBarBackWhiteRTL@3x.png b/Session/Meta/Images.xcassets/NavBarBackRTL.imageset/NavBarBackWhiteRTL@3x.png similarity index 100% rename from Session/Images.xcassets/NavBarBackRTL.imageset/NavBarBackWhiteRTL@3x.png rename to Session/Meta/Images.xcassets/NavBarBackRTL.imageset/NavBarBackWhiteRTL@3x.png diff --git a/Session/Images.xcassets/NavBarBackWithShadow.imageset/Contents.json b/Session/Meta/Images.xcassets/NavBarBackWithShadow.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/NavBarBackWithShadow.imageset/Contents.json rename to Session/Meta/Images.xcassets/NavBarBackWithShadow.imageset/Contents.json diff --git a/Session/Images.xcassets/NavBarBackWithShadow.imageset/chevron-left-shadow-24@1x.png b/Session/Meta/Images.xcassets/NavBarBackWithShadow.imageset/chevron-left-shadow-24@1x.png similarity index 100% rename from Session/Images.xcassets/NavBarBackWithShadow.imageset/chevron-left-shadow-24@1x.png rename to Session/Meta/Images.xcassets/NavBarBackWithShadow.imageset/chevron-left-shadow-24@1x.png diff --git a/Session/Images.xcassets/NavBarBackWithShadow.imageset/chevron-left-shadow-24@2x.png b/Session/Meta/Images.xcassets/NavBarBackWithShadow.imageset/chevron-left-shadow-24@2x.png similarity index 100% rename from Session/Images.xcassets/NavBarBackWithShadow.imageset/chevron-left-shadow-24@2x.png rename to Session/Meta/Images.xcassets/NavBarBackWithShadow.imageset/chevron-left-shadow-24@2x.png diff --git a/Session/Images.xcassets/NavBarBackWithShadow.imageset/chevron-left-shadow-24@3x.png b/Session/Meta/Images.xcassets/NavBarBackWithShadow.imageset/chevron-left-shadow-24@3x.png similarity index 100% rename from Session/Images.xcassets/NavBarBackWithShadow.imageset/chevron-left-shadow-24@3x.png rename to Session/Meta/Images.xcassets/NavBarBackWithShadow.imageset/chevron-left-shadow-24@3x.png diff --git a/Session/Images.xcassets/NavBarBackWithShadowRTL.imageset/Contents.json b/Session/Meta/Images.xcassets/NavBarBackWithShadowRTL.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/NavBarBackWithShadowRTL.imageset/Contents.json rename to Session/Meta/Images.xcassets/NavBarBackWithShadowRTL.imageset/Contents.json diff --git a/Session/Images.xcassets/NavBarBackWithShadowRTL.imageset/chevron-right-shadow-24@1x.png b/Session/Meta/Images.xcassets/NavBarBackWithShadowRTL.imageset/chevron-right-shadow-24@1x.png similarity index 100% rename from Session/Images.xcassets/NavBarBackWithShadowRTL.imageset/chevron-right-shadow-24@1x.png rename to Session/Meta/Images.xcassets/NavBarBackWithShadowRTL.imageset/chevron-right-shadow-24@1x.png diff --git a/Session/Images.xcassets/NavBarBackWithShadowRTL.imageset/chevron-right-shadow-24@2x.png b/Session/Meta/Images.xcassets/NavBarBackWithShadowRTL.imageset/chevron-right-shadow-24@2x.png similarity index 100% rename from Session/Images.xcassets/NavBarBackWithShadowRTL.imageset/chevron-right-shadow-24@2x.png rename to Session/Meta/Images.xcassets/NavBarBackWithShadowRTL.imageset/chevron-right-shadow-24@2x.png diff --git a/Session/Images.xcassets/NavBarBackWithShadowRTL.imageset/chevron-right-shadow-24@3x.png b/Session/Meta/Images.xcassets/NavBarBackWithShadowRTL.imageset/chevron-right-shadow-24@3x.png similarity index 100% rename from Session/Images.xcassets/NavBarBackWithShadowRTL.imageset/chevron-right-shadow-24@3x.png rename to Session/Meta/Images.xcassets/NavBarBackWithShadowRTL.imageset/chevron-right-shadow-24@3x.png diff --git a/Session/Images.xcassets/_arrow_button.imageset/Contents.json b/Session/Meta/Images.xcassets/_arrow_button.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/_arrow_button.imageset/Contents.json rename to Session/Meta/Images.xcassets/_arrow_button.imageset/Contents.json diff --git a/Session/Images.xcassets/_arrow_button.imageset/btnBack--white.pdf b/Session/Meta/Images.xcassets/_arrow_button.imageset/btnBack--white.pdf similarity index 100% rename from Session/Images.xcassets/_arrow_button.imageset/btnBack--white.pdf rename to Session/Meta/Images.xcassets/_arrow_button.imageset/btnBack--white.pdf diff --git a/Session/Images.xcassets/actionsheet_camera_black.imageset/Contents.json b/Session/Meta/Images.xcassets/actionsheet_camera_black.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/actionsheet_camera_black.imageset/Contents.json rename to Session/Meta/Images.xcassets/actionsheet_camera_black.imageset/Contents.json diff --git a/Session/Images.xcassets/actionsheet_camera_black.imageset/actionsheet_camera_black@1x.png b/Session/Meta/Images.xcassets/actionsheet_camera_black.imageset/actionsheet_camera_black@1x.png similarity index 100% rename from Session/Images.xcassets/actionsheet_camera_black.imageset/actionsheet_camera_black@1x.png rename to Session/Meta/Images.xcassets/actionsheet_camera_black.imageset/actionsheet_camera_black@1x.png diff --git a/Session/Images.xcassets/actionsheet_camera_black.imageset/actionsheet_camera_black@2x.png b/Session/Meta/Images.xcassets/actionsheet_camera_black.imageset/actionsheet_camera_black@2x.png similarity index 100% rename from Session/Images.xcassets/actionsheet_camera_black.imageset/actionsheet_camera_black@2x.png rename to Session/Meta/Images.xcassets/actionsheet_camera_black.imageset/actionsheet_camera_black@2x.png diff --git a/Session/Images.xcassets/actionsheet_camera_black.imageset/actionsheet_camera_black@3x.png b/Session/Meta/Images.xcassets/actionsheet_camera_black.imageset/actionsheet_camera_black@3x.png similarity index 100% rename from Session/Images.xcassets/actionsheet_camera_black.imageset/actionsheet_camera_black@3x.png rename to Session/Meta/Images.xcassets/actionsheet_camera_black.imageset/actionsheet_camera_black@3x.png diff --git a/Session/Images.xcassets/actionsheet_camera_roll_black.imageset/Contents.json b/Session/Meta/Images.xcassets/actionsheet_camera_roll_black.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/actionsheet_camera_roll_black.imageset/Contents.json rename to Session/Meta/Images.xcassets/actionsheet_camera_roll_black.imageset/Contents.json diff --git a/Session/Images.xcassets/actionsheet_camera_roll_black.imageset/actionsheet_camera_roll_black@1x.png b/Session/Meta/Images.xcassets/actionsheet_camera_roll_black.imageset/actionsheet_camera_roll_black@1x.png similarity index 100% rename from Session/Images.xcassets/actionsheet_camera_roll_black.imageset/actionsheet_camera_roll_black@1x.png rename to Session/Meta/Images.xcassets/actionsheet_camera_roll_black.imageset/actionsheet_camera_roll_black@1x.png diff --git a/Session/Images.xcassets/actionsheet_camera_roll_black.imageset/actionsheet_camera_roll_black@2x.png b/Session/Meta/Images.xcassets/actionsheet_camera_roll_black.imageset/actionsheet_camera_roll_black@2x.png similarity index 100% rename from Session/Images.xcassets/actionsheet_camera_roll_black.imageset/actionsheet_camera_roll_black@2x.png rename to Session/Meta/Images.xcassets/actionsheet_camera_roll_black.imageset/actionsheet_camera_roll_black@2x.png diff --git a/Session/Images.xcassets/actionsheet_camera_roll_black.imageset/actionsheet_camera_roll_black@3x.png b/Session/Meta/Images.xcassets/actionsheet_camera_roll_black.imageset/actionsheet_camera_roll_black@3x.png similarity index 100% rename from Session/Images.xcassets/actionsheet_camera_roll_black.imageset/actionsheet_camera_roll_black@3x.png rename to Session/Meta/Images.xcassets/actionsheet_camera_roll_black.imageset/actionsheet_camera_roll_black@3x.png diff --git a/Session/Images.xcassets/actionsheet_contact.imageset/Contents.json b/Session/Meta/Images.xcassets/actionsheet_contact.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/actionsheet_contact.imageset/Contents.json rename to Session/Meta/Images.xcassets/actionsheet_contact.imageset/Contents.json diff --git a/Session/Images.xcassets/actionsheet_contact.imageset/person_outline_24@1x.png b/Session/Meta/Images.xcassets/actionsheet_contact.imageset/person_outline_24@1x.png similarity index 100% rename from Session/Images.xcassets/actionsheet_contact.imageset/person_outline_24@1x.png rename to Session/Meta/Images.xcassets/actionsheet_contact.imageset/person_outline_24@1x.png diff --git a/Session/Images.xcassets/actionsheet_contact.imageset/person_outline_24@2x.png b/Session/Meta/Images.xcassets/actionsheet_contact.imageset/person_outline_24@2x.png similarity index 100% rename from Session/Images.xcassets/actionsheet_contact.imageset/person_outline_24@2x.png rename to Session/Meta/Images.xcassets/actionsheet_contact.imageset/person_outline_24@2x.png diff --git a/Session/Images.xcassets/actionsheet_contact.imageset/person_outline_24@3x.png b/Session/Meta/Images.xcassets/actionsheet_contact.imageset/person_outline_24@3x.png similarity index 100% rename from Session/Images.xcassets/actionsheet_contact.imageset/person_outline_24@3x.png rename to Session/Meta/Images.xcassets/actionsheet_contact.imageset/person_outline_24@3x.png diff --git a/Session/Images.xcassets/actionsheet_document_black.imageset/Contents.json b/Session/Meta/Images.xcassets/actionsheet_document_black.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/actionsheet_document_black.imageset/Contents.json rename to Session/Meta/Images.xcassets/actionsheet_document_black.imageset/Contents.json diff --git a/Session/Images.xcassets/actionsheet_document_black.imageset/actionsheet_document_black@1x.png b/Session/Meta/Images.xcassets/actionsheet_document_black.imageset/actionsheet_document_black@1x.png similarity index 100% rename from Session/Images.xcassets/actionsheet_document_black.imageset/actionsheet_document_black@1x.png rename to Session/Meta/Images.xcassets/actionsheet_document_black.imageset/actionsheet_document_black@1x.png diff --git a/Session/Images.xcassets/actionsheet_document_black.imageset/actionsheet_document_black@2x.png b/Session/Meta/Images.xcassets/actionsheet_document_black.imageset/actionsheet_document_black@2x.png similarity index 100% rename from Session/Images.xcassets/actionsheet_document_black.imageset/actionsheet_document_black@2x.png rename to Session/Meta/Images.xcassets/actionsheet_document_black.imageset/actionsheet_document_black@2x.png diff --git a/Session/Images.xcassets/actionsheet_document_black.imageset/actionsheet_document_black@3x.png b/Session/Meta/Images.xcassets/actionsheet_document_black.imageset/actionsheet_document_black@3x.png similarity index 100% rename from Session/Images.xcassets/actionsheet_document_black.imageset/actionsheet_document_black@3x.png rename to Session/Meta/Images.xcassets/actionsheet_document_black.imageset/actionsheet_document_black@3x.png diff --git a/Session/Images.xcassets/actionsheet_gif_black.imageset/Contents.json b/Session/Meta/Images.xcassets/actionsheet_gif_black.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/actionsheet_gif_black.imageset/Contents.json rename to Session/Meta/Images.xcassets/actionsheet_gif_black.imageset/Contents.json diff --git a/Session/Images.xcassets/actionsheet_gif_black.imageset/actionsheet_gif_black@1x.png b/Session/Meta/Images.xcassets/actionsheet_gif_black.imageset/actionsheet_gif_black@1x.png similarity index 100% rename from Session/Images.xcassets/actionsheet_gif_black.imageset/actionsheet_gif_black@1x.png rename to Session/Meta/Images.xcassets/actionsheet_gif_black.imageset/actionsheet_gif_black@1x.png diff --git a/Session/Images.xcassets/actionsheet_gif_black.imageset/actionsheet_gif_black@2x.png b/Session/Meta/Images.xcassets/actionsheet_gif_black.imageset/actionsheet_gif_black@2x.png similarity index 100% rename from Session/Images.xcassets/actionsheet_gif_black.imageset/actionsheet_gif_black@2x.png rename to Session/Meta/Images.xcassets/actionsheet_gif_black.imageset/actionsheet_gif_black@2x.png diff --git a/Session/Images.xcassets/actionsheet_gif_black.imageset/actionsheet_gif_black@3x.png b/Session/Meta/Images.xcassets/actionsheet_gif_black.imageset/actionsheet_gif_black@3x.png similarity index 100% rename from Session/Images.xcassets/actionsheet_gif_black.imageset/actionsheet_gif_black@3x.png rename to Session/Meta/Images.xcassets/actionsheet_gif_black.imageset/actionsheet_gif_black@3x.png diff --git a/Session/Images.xcassets/add-conversation.imageset/Contents.json b/Session/Meta/Images.xcassets/add-conversation.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/add-conversation.imageset/Contents.json rename to Session/Meta/Images.xcassets/add-conversation.imageset/Contents.json diff --git a/Session/Images.xcassets/add-conversation.imageset/add_conversation.pdf b/Session/Meta/Images.xcassets/add-conversation.imageset/add_conversation.pdf similarity index 100% rename from Session/Images.xcassets/add-conversation.imageset/add_conversation.pdf rename to Session/Meta/Images.xcassets/add-conversation.imageset/add_conversation.pdf diff --git a/Session/Images.xcassets/album_add_more.imageset/Contents.json b/Session/Meta/Images.xcassets/album_add_more.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/album_add_more.imageset/Contents.json rename to Session/Meta/Images.xcassets/album_add_more.imageset/Contents.json diff --git a/Session/Images.xcassets/album_add_more.imageset/create-album-outline-32@1x.png b/Session/Meta/Images.xcassets/album_add_more.imageset/create-album-outline-32@1x.png similarity index 100% rename from Session/Images.xcassets/album_add_more.imageset/create-album-outline-32@1x.png rename to Session/Meta/Images.xcassets/album_add_more.imageset/create-album-outline-32@1x.png diff --git a/Session/Images.xcassets/album_add_more.imageset/create-album-outline-32@2x.png b/Session/Meta/Images.xcassets/album_add_more.imageset/create-album-outline-32@2x.png similarity index 100% rename from Session/Images.xcassets/album_add_more.imageset/create-album-outline-32@2x.png rename to Session/Meta/Images.xcassets/album_add_more.imageset/create-album-outline-32@2x.png diff --git a/Session/Images.xcassets/album_add_more.imageset/create-album-outline-32@3x.png b/Session/Meta/Images.xcassets/album_add_more.imageset/create-album-outline-32@3x.png similarity index 100% rename from Session/Images.xcassets/album_add_more.imageset/create-album-outline-32@3x.png rename to Session/Meta/Images.xcassets/album_add_more.imageset/create-album-outline-32@3x.png diff --git a/Session/Images.xcassets/attachment_audio.imageset/Contents.json b/Session/Meta/Images.xcassets/attachment_audio.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/attachment_audio.imageset/Contents.json rename to Session/Meta/Images.xcassets/attachment_audio.imageset/Contents.json diff --git a/Session/Images.xcassets/attachment_audio.imageset/attachment_audio@1x.png b/Session/Meta/Images.xcassets/attachment_audio.imageset/attachment_audio@1x.png similarity index 100% rename from Session/Images.xcassets/attachment_audio.imageset/attachment_audio@1x.png rename to Session/Meta/Images.xcassets/attachment_audio.imageset/attachment_audio@1x.png diff --git a/Session/Images.xcassets/attachment_audio.imageset/attachment_audio@2x.png b/Session/Meta/Images.xcassets/attachment_audio.imageset/attachment_audio@2x.png similarity index 100% rename from Session/Images.xcassets/attachment_audio.imageset/attachment_audio@2x.png rename to Session/Meta/Images.xcassets/attachment_audio.imageset/attachment_audio@2x.png diff --git a/Session/Images.xcassets/attachment_audio.imageset/attachment_audio@3x.png b/Session/Meta/Images.xcassets/attachment_audio.imageset/attachment_audio@3x.png similarity index 100% rename from Session/Images.xcassets/attachment_audio.imageset/attachment_audio@3x.png rename to Session/Meta/Images.xcassets/attachment_audio.imageset/attachment_audio@3x.png diff --git a/Session/Images.xcassets/attachment_file.imageset/Contents.json b/Session/Meta/Images.xcassets/attachment_file.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/attachment_file.imageset/Contents.json rename to Session/Meta/Images.xcassets/attachment_file.imageset/Contents.json diff --git a/Session/Images.xcassets/attachment_file.imageset/attachment_file@1x.png b/Session/Meta/Images.xcassets/attachment_file.imageset/attachment_file@1x.png similarity index 100% rename from Session/Images.xcassets/attachment_file.imageset/attachment_file@1x.png rename to Session/Meta/Images.xcassets/attachment_file.imageset/attachment_file@1x.png diff --git a/Session/Images.xcassets/attachment_file.imageset/attachment_file@2x.png b/Session/Meta/Images.xcassets/attachment_file.imageset/attachment_file@2x.png similarity index 100% rename from Session/Images.xcassets/attachment_file.imageset/attachment_file@2x.png rename to Session/Meta/Images.xcassets/attachment_file.imageset/attachment_file@2x.png diff --git a/Session/Images.xcassets/attachment_file.imageset/attachment_file@3x.png b/Session/Meta/Images.xcassets/attachment_file.imageset/attachment_file@3x.png similarity index 100% rename from Session/Images.xcassets/attachment_file.imageset/attachment_file@3x.png rename to Session/Meta/Images.xcassets/attachment_file.imageset/attachment_file@3x.png diff --git a/Session/Images.xcassets/attachment_play_button.imageset/Contents.json b/Session/Meta/Images.xcassets/attachment_play_button.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/attachment_play_button.imageset/Contents.json rename to Session/Meta/Images.xcassets/attachment_play_button.imageset/Contents.json diff --git a/Session/Images.xcassets/attachment_play_button.imageset/attachment_play_button@1x.png b/Session/Meta/Images.xcassets/attachment_play_button.imageset/attachment_play_button@1x.png similarity index 100% rename from Session/Images.xcassets/attachment_play_button.imageset/attachment_play_button@1x.png rename to Session/Meta/Images.xcassets/attachment_play_button.imageset/attachment_play_button@1x.png diff --git a/Session/Images.xcassets/attachment_play_button.imageset/attachment_play_button@2x.png b/Session/Meta/Images.xcassets/attachment_play_button.imageset/attachment_play_button@2x.png similarity index 100% rename from Session/Images.xcassets/attachment_play_button.imageset/attachment_play_button@2x.png rename to Session/Meta/Images.xcassets/attachment_play_button.imageset/attachment_play_button@2x.png diff --git a/Session/Images.xcassets/attachment_play_button.imageset/attachment_play_button@3x.png b/Session/Meta/Images.xcassets/attachment_play_button.imageset/attachment_play_button@3x.png similarity index 100% rename from Session/Images.xcassets/attachment_play_button.imageset/attachment_play_button@3x.png rename to Session/Meta/Images.xcassets/attachment_play_button.imageset/attachment_play_button@3x.png diff --git a/Session/Images.xcassets/audio-call-mute-active.imageset/Contents.json b/Session/Meta/Images.xcassets/audio-call-mute-active.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/audio-call-mute-active.imageset/Contents.json rename to Session/Meta/Images.xcassets/audio-call-mute-active.imageset/Contents.json diff --git a/Session/Images.xcassets/audio-call-mute-active.imageset/ic_mute_active.png b/Session/Meta/Images.xcassets/audio-call-mute-active.imageset/ic_mute_active.png similarity index 100% rename from Session/Images.xcassets/audio-call-mute-active.imageset/ic_mute_active.png rename to Session/Meta/Images.xcassets/audio-call-mute-active.imageset/ic_mute_active.png diff --git a/Session/Images.xcassets/audio-call-mute-inactive.imageset/Contents.json b/Session/Meta/Images.xcassets/audio-call-mute-inactive.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/audio-call-mute-inactive.imageset/Contents.json rename to Session/Meta/Images.xcassets/audio-call-mute-inactive.imageset/Contents.json diff --git a/Session/Images.xcassets/audio-call-mute-inactive.imageset/ic_mute_inactive.png b/Session/Meta/Images.xcassets/audio-call-mute-inactive.imageset/ic_mute_inactive.png similarity index 100% rename from Session/Images.xcassets/audio-call-mute-inactive.imageset/ic_mute_inactive.png rename to Session/Meta/Images.xcassets/audio-call-mute-inactive.imageset/ic_mute_inactive.png diff --git a/Session/Images.xcassets/audio-call-speaker-active.imageset/Contents.json b/Session/Meta/Images.xcassets/audio-call-speaker-active.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/audio-call-speaker-active.imageset/Contents.json rename to Session/Meta/Images.xcassets/audio-call-speaker-active.imageset/Contents.json diff --git a/Session/Images.xcassets/audio-call-speaker-active.imageset/ic_speaker_active.png b/Session/Meta/Images.xcassets/audio-call-speaker-active.imageset/ic_speaker_active.png similarity index 100% rename from Session/Images.xcassets/audio-call-speaker-active.imageset/ic_speaker_active.png rename to Session/Meta/Images.xcassets/audio-call-speaker-active.imageset/ic_speaker_active.png diff --git a/Session/Images.xcassets/audio-call-speaker-inactive.imageset/Contents.json b/Session/Meta/Images.xcassets/audio-call-speaker-inactive.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/audio-call-speaker-inactive.imageset/Contents.json rename to Session/Meta/Images.xcassets/audio-call-speaker-inactive.imageset/Contents.json diff --git a/Session/Images.xcassets/audio-call-speaker-inactive.imageset/ic_speaker_inactive.png b/Session/Meta/Images.xcassets/audio-call-speaker-inactive.imageset/ic_speaker_inactive.png similarity index 100% rename from Session/Images.xcassets/audio-call-speaker-inactive.imageset/ic_speaker_inactive.png rename to Session/Meta/Images.xcassets/audio-call-speaker-inactive.imageset/ic_speaker_inactive.png diff --git a/Session/Images.xcassets/audio-call-video-active.imageset/Contents.json b/Session/Meta/Images.xcassets/audio-call-video-active.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/audio-call-video-active.imageset/Contents.json rename to Session/Meta/Images.xcassets/audio-call-video-active.imageset/Contents.json diff --git a/Session/Images.xcassets/audio-call-video-active.imageset/ic_video_active.png b/Session/Meta/Images.xcassets/audio-call-video-active.imageset/ic_video_active.png similarity index 100% rename from Session/Images.xcassets/audio-call-video-active.imageset/ic_video_active.png rename to Session/Meta/Images.xcassets/audio-call-video-active.imageset/ic_video_active.png diff --git a/Session/Images.xcassets/audio-call-video-inactive.imageset/Contents.json b/Session/Meta/Images.xcassets/audio-call-video-inactive.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/audio-call-video-inactive.imageset/Contents.json rename to Session/Meta/Images.xcassets/audio-call-video-inactive.imageset/Contents.json diff --git a/Session/Images.xcassets/audio-call-video-inactive.imageset/ic_video_inactive.png b/Session/Meta/Images.xcassets/audio-call-video-inactive.imageset/ic_video_inactive.png similarity index 100% rename from Session/Images.xcassets/audio-call-video-inactive.imageset/ic_video_inactive.png rename to Session/Meta/Images.xcassets/audio-call-video-inactive.imageset/ic_video_inactive.png diff --git a/Session/Images.xcassets/audio_pause_black_48.imageset/Contents.json b/Session/Meta/Images.xcassets/audio_pause_black_48.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/audio_pause_black_48.imageset/Contents.json rename to Session/Meta/Images.xcassets/audio_pause_black_48.imageset/Contents.json diff --git a/Session/Images.xcassets/audio_pause_black_48.imageset/pause-48@1x.png b/Session/Meta/Images.xcassets/audio_pause_black_48.imageset/pause-48@1x.png similarity index 100% rename from Session/Images.xcassets/audio_pause_black_48.imageset/pause-48@1x.png rename to Session/Meta/Images.xcassets/audio_pause_black_48.imageset/pause-48@1x.png diff --git a/Session/Images.xcassets/audio_pause_black_48.imageset/pause-48@2x.png b/Session/Meta/Images.xcassets/audio_pause_black_48.imageset/pause-48@2x.png similarity index 100% rename from Session/Images.xcassets/audio_pause_black_48.imageset/pause-48@2x.png rename to Session/Meta/Images.xcassets/audio_pause_black_48.imageset/pause-48@2x.png diff --git a/Session/Images.xcassets/audio_pause_black_48.imageset/pause-48@3x.png b/Session/Meta/Images.xcassets/audio_pause_black_48.imageset/pause-48@3x.png similarity index 100% rename from Session/Images.xcassets/audio_pause_black_48.imageset/pause-48@3x.png rename to Session/Meta/Images.xcassets/audio_pause_black_48.imageset/pause-48@3x.png diff --git a/Session/Images.xcassets/audio_pause_black_large.imageset/Contents.json b/Session/Meta/Images.xcassets/audio_pause_black_large.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/audio_pause_black_large.imageset/Contents.json rename to Session/Meta/Images.xcassets/audio_pause_black_large.imageset/Contents.json diff --git a/Session/Images.xcassets/audio_pause_black_large.imageset/audio_pause_black_large@1x.png b/Session/Meta/Images.xcassets/audio_pause_black_large.imageset/audio_pause_black_large@1x.png similarity index 100% rename from Session/Images.xcassets/audio_pause_black_large.imageset/audio_pause_black_large@1x.png rename to Session/Meta/Images.xcassets/audio_pause_black_large.imageset/audio_pause_black_large@1x.png diff --git a/Session/Images.xcassets/audio_pause_black_large.imageset/audio_pause_black_large@2x.png b/Session/Meta/Images.xcassets/audio_pause_black_large.imageset/audio_pause_black_large@2x.png similarity index 100% rename from Session/Images.xcassets/audio_pause_black_large.imageset/audio_pause_black_large@2x.png rename to Session/Meta/Images.xcassets/audio_pause_black_large.imageset/audio_pause_black_large@2x.png diff --git a/Session/Images.xcassets/audio_pause_black_large.imageset/audio_pause_black_large@3x.png b/Session/Meta/Images.xcassets/audio_pause_black_large.imageset/audio_pause_black_large@3x.png similarity index 100% rename from Session/Images.xcassets/audio_pause_black_large.imageset/audio_pause_black_large@3x.png rename to Session/Meta/Images.xcassets/audio_pause_black_large.imageset/audio_pause_black_large@3x.png diff --git a/Session/Images.xcassets/audio_play_black_48.imageset/Contents.json b/Session/Meta/Images.xcassets/audio_play_black_48.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/audio_play_black_48.imageset/Contents.json rename to Session/Meta/Images.xcassets/audio_play_black_48.imageset/Contents.json diff --git a/Session/Images.xcassets/audio_play_black_48.imageset/play-48@1x.png b/Session/Meta/Images.xcassets/audio_play_black_48.imageset/play-48@1x.png similarity index 100% rename from Session/Images.xcassets/audio_play_black_48.imageset/play-48@1x.png rename to Session/Meta/Images.xcassets/audio_play_black_48.imageset/play-48@1x.png diff --git a/Session/Images.xcassets/audio_play_black_48.imageset/play-48@2x.png b/Session/Meta/Images.xcassets/audio_play_black_48.imageset/play-48@2x.png similarity index 100% rename from Session/Images.xcassets/audio_play_black_48.imageset/play-48@2x.png rename to Session/Meta/Images.xcassets/audio_play_black_48.imageset/play-48@2x.png diff --git a/Session/Images.xcassets/audio_play_black_48.imageset/play-48@3x.png b/Session/Meta/Images.xcassets/audio_play_black_48.imageset/play-48@3x.png similarity index 100% rename from Session/Images.xcassets/audio_play_black_48.imageset/play-48@3x.png rename to Session/Meta/Images.xcassets/audio_play_black_48.imageset/play-48@3x.png diff --git a/Session/Images.xcassets/audio_play_black_large.imageset/Contents.json b/Session/Meta/Images.xcassets/audio_play_black_large.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/audio_play_black_large.imageset/Contents.json rename to Session/Meta/Images.xcassets/audio_play_black_large.imageset/Contents.json diff --git a/Session/Images.xcassets/audio_play_black_large.imageset/audio_play_black_large@1x.png b/Session/Meta/Images.xcassets/audio_play_black_large.imageset/audio_play_black_large@1x.png similarity index 100% rename from Session/Images.xcassets/audio_play_black_large.imageset/audio_play_black_large@1x.png rename to Session/Meta/Images.xcassets/audio_play_black_large.imageset/audio_play_black_large@1x.png diff --git a/Session/Images.xcassets/audio_play_black_large.imageset/audio_play_black_large@2x.png b/Session/Meta/Images.xcassets/audio_play_black_large.imageset/audio_play_black_large@2x.png similarity index 100% rename from Session/Images.xcassets/audio_play_black_large.imageset/audio_play_black_large@2x.png rename to Session/Meta/Images.xcassets/audio_play_black_large.imageset/audio_play_black_large@2x.png diff --git a/Session/Images.xcassets/audio_play_black_large.imageset/audio_play_black_large@3x.png b/Session/Meta/Images.xcassets/audio_play_black_large.imageset/audio_play_black_large@3x.png similarity index 100% rename from Session/Images.xcassets/audio_play_black_large.imageset/audio_play_black_large@3x.png rename to Session/Meta/Images.xcassets/audio_play_black_large.imageset/audio_play_black_large@3x.png diff --git a/Session/Images.xcassets/banner_close.imageset/Contents.json b/Session/Meta/Images.xcassets/banner_close.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/banner_close.imageset/Contents.json rename to Session/Meta/Images.xcassets/banner_close.imageset/Contents.json diff --git a/Session/Images.xcassets/banner_close.imageset/banner_close@1x.png b/Session/Meta/Images.xcassets/banner_close.imageset/banner_close@1x.png similarity index 100% rename from Session/Images.xcassets/banner_close.imageset/banner_close@1x.png rename to Session/Meta/Images.xcassets/banner_close.imageset/banner_close@1x.png diff --git a/Session/Images.xcassets/banner_close.imageset/banner_close@2x.png b/Session/Meta/Images.xcassets/banner_close.imageset/banner_close@2x.png similarity index 100% rename from Session/Images.xcassets/banner_close.imageset/banner_close@2x.png rename to Session/Meta/Images.xcassets/banner_close.imageset/banner_close@2x.png diff --git a/Session/Images.xcassets/banner_close.imageset/banner_close@3x.png b/Session/Meta/Images.xcassets/banner_close.imageset/banner_close@3x.png similarity index 100% rename from Session/Images.xcassets/banner_close.imageset/banner_close@3x.png rename to Session/Meta/Images.xcassets/banner_close.imageset/banner_close@3x.png diff --git a/Session/Images.xcassets/btnCancel--blue.imageset/Contents.json b/Session/Meta/Images.xcassets/btnCancel--blue.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/btnCancel--blue.imageset/Contents.json rename to Session/Meta/Images.xcassets/btnCancel--blue.imageset/Contents.json diff --git a/Session/Images.xcassets/btnCancel--blue.imageset/btnCancel--blue.pdf b/Session/Meta/Images.xcassets/btnCancel--blue.imageset/btnCancel--blue.pdf similarity index 100% rename from Session/Images.xcassets/btnCancel--blue.imageset/btnCancel--blue.pdf rename to Session/Meta/Images.xcassets/btnCancel--blue.imageset/btnCancel--blue.pdf diff --git a/Session/Images.xcassets/btnCancel--white.imageset/Contents.json b/Session/Meta/Images.xcassets/btnCancel--white.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/btnCancel--white.imageset/Contents.json rename to Session/Meta/Images.xcassets/btnCancel--white.imageset/Contents.json diff --git a/Session/Images.xcassets/btnCancel--white.imageset/cancel.pdf b/Session/Meta/Images.xcassets/btnCancel--white.imageset/cancel.pdf similarity index 100% rename from Session/Images.xcassets/btnCancel--white.imageset/cancel.pdf rename to Session/Meta/Images.xcassets/btnCancel--white.imageset/cancel.pdf diff --git a/Session/Images.xcassets/btnGroup--white.imageset/Contents.json b/Session/Meta/Images.xcassets/btnGroup--white.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/btnGroup--white.imageset/Contents.json rename to Session/Meta/Images.xcassets/btnGroup--white.imageset/Contents.json diff --git a/Session/Images.xcassets/btnGroup--white.imageset/add_group.pdf b/Session/Meta/Images.xcassets/btnGroup--white.imageset/add_group.pdf similarity index 100% rename from Session/Images.xcassets/btnGroup--white.imageset/add_group.pdf rename to Session/Meta/Images.xcassets/btnGroup--white.imageset/add_group.pdf diff --git a/Session/Images.xcassets/btnQRShow--white-1.imageset/Contents.json b/Session/Meta/Images.xcassets/btnQRShow--white-1.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/btnQRShow--white-1.imageset/Contents.json rename to Session/Meta/Images.xcassets/btnQRShow--white-1.imageset/Contents.json diff --git a/Session/Images.xcassets/btnQRShow--white-1.imageset/btnQRShow--white.pdf b/Session/Meta/Images.xcassets/btnQRShow--white-1.imageset/btnQRShow--white.pdf similarity index 100% rename from Session/Images.xcassets/btnQRShow--white-1.imageset/btnQRShow--white.pdf rename to Session/Meta/Images.xcassets/btnQRShow--white-1.imageset/btnQRShow--white.pdf diff --git a/Session/Images.xcassets/btnQRShow--white.imageset/Contents.json b/Session/Meta/Images.xcassets/btnQRShow--white.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/btnQRShow--white.imageset/Contents.json rename to Session/Meta/Images.xcassets/btnQRShow--white.imageset/Contents.json diff --git a/Session/Images.xcassets/btnQRShow--white.imageset/btnQRShow--white.pdf b/Session/Meta/Images.xcassets/btnQRShow--white.imageset/btnQRShow--white.pdf similarity index 100% rename from Session/Images.xcassets/btnQRShow--white.imageset/btnQRShow--white.pdf rename to Session/Meta/Images.xcassets/btnQRShow--white.imageset/btnQRShow--white.pdf diff --git a/Session/Images.xcassets/btnRefresh--white.imageset/Contents.json b/Session/Meta/Images.xcassets/btnRefresh--white.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/btnRefresh--white.imageset/Contents.json rename to Session/Meta/Images.xcassets/btnRefresh--white.imageset/Contents.json diff --git a/Session/Images.xcassets/btnRefresh--white.imageset/btnRefresh--white.pdf b/Session/Meta/Images.xcassets/btnRefresh--white.imageset/btnRefresh--white.pdf similarity index 100% rename from Session/Images.xcassets/btnRefresh--white.imageset/btnRefresh--white.pdf rename to Session/Meta/Images.xcassets/btnRefresh--white.imageset/btnRefresh--white.pdf diff --git a/Session/Images.xcassets/button_phone_white.imageset/Contents.json b/Session/Meta/Images.xcassets/button_phone_white.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/button_phone_white.imageset/Contents.json rename to Session/Meta/Images.xcassets/button_phone_white.imageset/Contents.json diff --git a/Session/Images.xcassets/button_phone_white.imageset/button_phone_white@1x.png b/Session/Meta/Images.xcassets/button_phone_white.imageset/button_phone_white@1x.png similarity index 100% rename from Session/Images.xcassets/button_phone_white.imageset/button_phone_white@1x.png rename to Session/Meta/Images.xcassets/button_phone_white.imageset/button_phone_white@1x.png diff --git a/Session/Images.xcassets/button_phone_white.imageset/button_phone_white@2x.png b/Session/Meta/Images.xcassets/button_phone_white.imageset/button_phone_white@2x.png similarity index 100% rename from Session/Images.xcassets/button_phone_white.imageset/button_phone_white@2x.png rename to Session/Meta/Images.xcassets/button_phone_white.imageset/button_phone_white@2x.png diff --git a/Session/Images.xcassets/button_phone_white.imageset/button_phone_white@3x.png b/Session/Meta/Images.xcassets/button_phone_white.imageset/button_phone_white@3x.png similarity index 100% rename from Session/Images.xcassets/button_phone_white.imageset/button_phone_white@3x.png rename to Session/Meta/Images.xcassets/button_phone_white.imageset/button_phone_white@3x.png diff --git a/Session/Images.xcassets/button_settings_white.imageset/Contents.json b/Session/Meta/Images.xcassets/button_settings_white.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/button_settings_white.imageset/Contents.json rename to Session/Meta/Images.xcassets/button_settings_white.imageset/Contents.json diff --git a/Session/Images.xcassets/button_settings_white.imageset/button_settings_white@1x.png b/Session/Meta/Images.xcassets/button_settings_white.imageset/button_settings_white@1x.png similarity index 100% rename from Session/Images.xcassets/button_settings_white.imageset/button_settings_white@1x.png rename to Session/Meta/Images.xcassets/button_settings_white.imageset/button_settings_white@1x.png diff --git a/Session/Images.xcassets/button_settings_white.imageset/button_settings_white@2x.png b/Session/Meta/Images.xcassets/button_settings_white.imageset/button_settings_white@2x.png similarity index 100% rename from Session/Images.xcassets/button_settings_white.imageset/button_settings_white@2x.png rename to Session/Meta/Images.xcassets/button_settings_white.imageset/button_settings_white@2x.png diff --git a/Session/Images.xcassets/button_settings_white.imageset/button_settings_white@3x.png b/Session/Meta/Images.xcassets/button_settings_white.imageset/button_settings_white@3x.png similarity index 100% rename from Session/Images.xcassets/button_settings_white.imageset/button_settings_white@3x.png rename to Session/Meta/Images.xcassets/button_settings_white.imageset/button_settings_white@3x.png diff --git a/Session/Images.xcassets/call-active-wide.imageset/Contents.json b/Session/Meta/Images.xcassets/call-active-wide.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/call-active-wide.imageset/Contents.json rename to Session/Meta/Images.xcassets/call-active-wide.imageset/Contents.json diff --git a/Session/Images.xcassets/call-active-wide.imageset/call-active-wide.png b/Session/Meta/Images.xcassets/call-active-wide.imageset/call-active-wide.png similarity index 100% rename from Session/Images.xcassets/call-active-wide.imageset/call-active-wide.png rename to Session/Meta/Images.xcassets/call-active-wide.imageset/call-active-wide.png diff --git a/Session/Images.xcassets/cancel-cross-white.imageset/Contents.json b/Session/Meta/Images.xcassets/cancel-cross-white.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/cancel-cross-white.imageset/Contents.json rename to Session/Meta/Images.xcassets/cancel-cross-white.imageset/Contents.json diff --git a/Session/Images.xcassets/cancel-cross-white.imageset/cancel-cross-white@1x.png b/Session/Meta/Images.xcassets/cancel-cross-white.imageset/cancel-cross-white@1x.png similarity index 100% rename from Session/Images.xcassets/cancel-cross-white.imageset/cancel-cross-white@1x.png rename to Session/Meta/Images.xcassets/cancel-cross-white.imageset/cancel-cross-white@1x.png diff --git a/Session/Images.xcassets/cancel-cross-white.imageset/cancel-cross-white@2x.png b/Session/Meta/Images.xcassets/cancel-cross-white.imageset/cancel-cross-white@2x.png similarity index 100% rename from Session/Images.xcassets/cancel-cross-white.imageset/cancel-cross-white@2x.png rename to Session/Meta/Images.xcassets/cancel-cross-white.imageset/cancel-cross-white@2x.png diff --git a/Session/Images.xcassets/cancel-cross-white.imageset/cancel-cross-white@3x.png b/Session/Meta/Images.xcassets/cancel-cross-white.imageset/cancel-cross-white@3x.png similarity index 100% rename from Session/Images.xcassets/cancel-cross-white.imageset/cancel-cross-white@3x.png rename to Session/Meta/Images.xcassets/cancel-cross-white.imageset/cancel-cross-white@3x.png diff --git a/Session/Images.xcassets/cellBtnDelete.imageset/Contents.json b/Session/Meta/Images.xcassets/cellBtnDelete.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/cellBtnDelete.imageset/Contents.json rename to Session/Meta/Images.xcassets/cellBtnDelete.imageset/Contents.json diff --git a/Session/Images.xcassets/cellBtnDelete.imageset/cellBtnDelete.pdf b/Session/Meta/Images.xcassets/cellBtnDelete.imageset/cellBtnDelete.pdf similarity index 100% rename from Session/Images.xcassets/cellBtnDelete.imageset/cellBtnDelete.pdf rename to Session/Meta/Images.xcassets/cellBtnDelete.imageset/cellBtnDelete.pdf diff --git a/Session/Images.xcassets/cellBtnMoveToArchive--blue.imageset/Contents.json b/Session/Meta/Images.xcassets/cellBtnMoveToArchive--blue.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/cellBtnMoveToArchive--blue.imageset/Contents.json rename to Session/Meta/Images.xcassets/cellBtnMoveToArchive--blue.imageset/Contents.json diff --git a/Session/Images.xcassets/cellBtnMoveToArchive--blue.imageset/cellBtnMoveToArchive--blue.pdf b/Session/Meta/Images.xcassets/cellBtnMoveToArchive--blue.imageset/cellBtnMoveToArchive--blue.pdf similarity index 100% rename from Session/Images.xcassets/cellBtnMoveToArchive--blue.imageset/cellBtnMoveToArchive--blue.pdf rename to Session/Meta/Images.xcassets/cellBtnMoveToArchive--blue.imageset/cellBtnMoveToArchive--blue.pdf diff --git a/Session/Images.xcassets/cellBtnMoveToInbox--blue.imageset/Contents.json b/Session/Meta/Images.xcassets/cellBtnMoveToInbox--blue.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/cellBtnMoveToInbox--blue.imageset/Contents.json rename to Session/Meta/Images.xcassets/cellBtnMoveToInbox--blue.imageset/Contents.json diff --git a/Session/Images.xcassets/cellBtnMoveToInbox--blue.imageset/cellBtnMoveToInbox--blue.pdf b/Session/Meta/Images.xcassets/cellBtnMoveToInbox--blue.imageset/cellBtnMoveToInbox--blue.pdf similarity index 100% rename from Session/Images.xcassets/cellBtnMoveToInbox--blue.imageset/cellBtnMoveToInbox--blue.pdf rename to Session/Meta/Images.xcassets/cellBtnMoveToInbox--blue.imageset/cellBtnMoveToInbox--blue.pdf diff --git a/Session/Images.xcassets/compose-cancel.imageset/Contents.json b/Session/Meta/Images.xcassets/compose-cancel.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/compose-cancel.imageset/Contents.json rename to Session/Meta/Images.xcassets/compose-cancel.imageset/Contents.json diff --git a/Session/Images.xcassets/compose-cancel.imageset/x-20@1x.png b/Session/Meta/Images.xcassets/compose-cancel.imageset/x-20@1x.png similarity index 100% rename from Session/Images.xcassets/compose-cancel.imageset/x-20@1x.png rename to Session/Meta/Images.xcassets/compose-cancel.imageset/x-20@1x.png diff --git a/Session/Images.xcassets/compose-cancel.imageset/x-20@2x.png b/Session/Meta/Images.xcassets/compose-cancel.imageset/x-20@2x.png similarity index 100% rename from Session/Images.xcassets/compose-cancel.imageset/x-20@2x.png rename to Session/Meta/Images.xcassets/compose-cancel.imageset/x-20@2x.png diff --git a/Session/Images.xcassets/compose-cancel.imageset/x-20@3x.png b/Session/Meta/Images.xcassets/compose-cancel.imageset/x-20@3x.png similarity index 100% rename from Session/Images.xcassets/compose-cancel.imageset/x-20@3x.png rename to Session/Meta/Images.xcassets/compose-cancel.imageset/x-20@3x.png diff --git a/Session/Images.xcassets/contact-avatar-1024.imageset/Contents.json b/Session/Meta/Images.xcassets/contact-avatar-1024.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/contact-avatar-1024.imageset/Contents.json rename to Session/Meta/Images.xcassets/contact-avatar-1024.imageset/Contents.json diff --git a/Session/Images.xcassets/contact-avatar-1024.imageset/contact-avatar-1024.png b/Session/Meta/Images.xcassets/contact-avatar-1024.imageset/contact-avatar-1024.png similarity index 100% rename from Session/Images.xcassets/contact-avatar-1024.imageset/contact-avatar-1024.png rename to Session/Meta/Images.xcassets/contact-avatar-1024.imageset/contact-avatar-1024.png diff --git a/Session/Images.xcassets/contact-avatar-84.imageset/Contents.json b/Session/Meta/Images.xcassets/contact-avatar-84.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/contact-avatar-84.imageset/Contents.json rename to Session/Meta/Images.xcassets/contact-avatar-84.imageset/Contents.json diff --git a/Session/Images.xcassets/contact-avatar-84.imageset/contact-avatar-84.png b/Session/Meta/Images.xcassets/contact-avatar-84.imageset/contact-avatar-84.png similarity index 100% rename from Session/Images.xcassets/contact-avatar-84.imageset/contact-avatar-84.png rename to Session/Meta/Images.xcassets/contact-avatar-84.imageset/contact-avatar-84.png diff --git a/Session/Images.xcassets/contact-options-action.imageset/Contents.json b/Session/Meta/Images.xcassets/contact-options-action.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/contact-options-action.imageset/Contents.json rename to Session/Meta/Images.xcassets/contact-options-action.imageset/Contents.json diff --git a/Session/Images.xcassets/contact-options-action.imageset/contact-options-action.pdf b/Session/Meta/Images.xcassets/contact-options-action.imageset/contact-options-action.pdf similarity index 100% rename from Session/Images.xcassets/contact-options-action.imageset/contact-options-action.pdf rename to Session/Meta/Images.xcassets/contact-options-action.imageset/contact-options-action.pdf diff --git a/Session/Images.xcassets/contact_checkbox_checked.imageset/Contents.json b/Session/Meta/Images.xcassets/contact_checkbox_checked.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/contact_checkbox_checked.imageset/Contents.json rename to Session/Meta/Images.xcassets/contact_checkbox_checked.imageset/Contents.json diff --git a/Session/Images.xcassets/contact_checkbox_checked.imageset/checkbox_checked@1x.png b/Session/Meta/Images.xcassets/contact_checkbox_checked.imageset/checkbox_checked@1x.png similarity index 100% rename from Session/Images.xcassets/contact_checkbox_checked.imageset/checkbox_checked@1x.png rename to Session/Meta/Images.xcassets/contact_checkbox_checked.imageset/checkbox_checked@1x.png diff --git a/Session/Images.xcassets/contact_checkbox_checked.imageset/checkbox_checked@2x.png b/Session/Meta/Images.xcassets/contact_checkbox_checked.imageset/checkbox_checked@2x.png similarity index 100% rename from Session/Images.xcassets/contact_checkbox_checked.imageset/checkbox_checked@2x.png rename to Session/Meta/Images.xcassets/contact_checkbox_checked.imageset/checkbox_checked@2x.png diff --git a/Session/Images.xcassets/contact_checkbox_checked.imageset/checkbox_checked@3x.png b/Session/Meta/Images.xcassets/contact_checkbox_checked.imageset/checkbox_checked@3x.png similarity index 100% rename from Session/Images.xcassets/contact_checkbox_checked.imageset/checkbox_checked@3x.png rename to Session/Meta/Images.xcassets/contact_checkbox_checked.imageset/checkbox_checked@3x.png diff --git a/Session/Images.xcassets/contact_checkbox_unchecked.imageset/Contents.json b/Session/Meta/Images.xcassets/contact_checkbox_unchecked.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/contact_checkbox_unchecked.imageset/Contents.json rename to Session/Meta/Images.xcassets/contact_checkbox_unchecked.imageset/Contents.json diff --git a/Session/Images.xcassets/contact_checkbox_unchecked.imageset/checkbox_unchecked@1x.png b/Session/Meta/Images.xcassets/contact_checkbox_unchecked.imageset/checkbox_unchecked@1x.png similarity index 100% rename from Session/Images.xcassets/contact_checkbox_unchecked.imageset/checkbox_unchecked@1x.png rename to Session/Meta/Images.xcassets/contact_checkbox_unchecked.imageset/checkbox_unchecked@1x.png diff --git a/Session/Images.xcassets/contact_checkbox_unchecked.imageset/checkbox_unchecked@2x.png b/Session/Meta/Images.xcassets/contact_checkbox_unchecked.imageset/checkbox_unchecked@2x.png similarity index 100% rename from Session/Images.xcassets/contact_checkbox_unchecked.imageset/checkbox_unchecked@2x.png rename to Session/Meta/Images.xcassets/contact_checkbox_unchecked.imageset/checkbox_unchecked@2x.png diff --git a/Session/Images.xcassets/contact_checkbox_unchecked.imageset/checkbox_unchecked@3x.png b/Session/Meta/Images.xcassets/contact_checkbox_unchecked.imageset/checkbox_unchecked@3x.png similarity index 100% rename from Session/Images.xcassets/contact_checkbox_unchecked.imageset/checkbox_unchecked@3x.png rename to Session/Meta/Images.xcassets/contact_checkbox_unchecked.imageset/checkbox_unchecked@3x.png diff --git a/Session/Images.xcassets/contact_view_audio_call.imageset/Contents.json b/Session/Meta/Images.xcassets/contact_view_audio_call.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/contact_view_audio_call.imageset/Contents.json rename to Session/Meta/Images.xcassets/contact_view_audio_call.imageset/Contents.json diff --git a/Session/Images.xcassets/contact_view_audio_call.imageset/phone_20@1x.png b/Session/Meta/Images.xcassets/contact_view_audio_call.imageset/phone_20@1x.png similarity index 100% rename from Session/Images.xcassets/contact_view_audio_call.imageset/phone_20@1x.png rename to Session/Meta/Images.xcassets/contact_view_audio_call.imageset/phone_20@1x.png diff --git a/Session/Images.xcassets/contact_view_audio_call.imageset/phone_20@2x.png b/Session/Meta/Images.xcassets/contact_view_audio_call.imageset/phone_20@2x.png similarity index 100% rename from Session/Images.xcassets/contact_view_audio_call.imageset/phone_20@2x.png rename to Session/Meta/Images.xcassets/contact_view_audio_call.imageset/phone_20@2x.png diff --git a/Session/Images.xcassets/contact_view_audio_call.imageset/phone_20@3x.png b/Session/Meta/Images.xcassets/contact_view_audio_call.imageset/phone_20@3x.png similarity index 100% rename from Session/Images.xcassets/contact_view_audio_call.imageset/phone_20@3x.png rename to Session/Meta/Images.xcassets/contact_view_audio_call.imageset/phone_20@3x.png diff --git a/Session/Images.xcassets/contact_view_message.imageset/Contents.json b/Session/Meta/Images.xcassets/contact_view_message.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/contact_view_message.imageset/Contents.json rename to Session/Meta/Images.xcassets/contact_view_message.imageset/Contents.json diff --git a/Session/Images.xcassets/contact_view_message.imageset/message_20@1x.png b/Session/Meta/Images.xcassets/contact_view_message.imageset/message_20@1x.png similarity index 100% rename from Session/Images.xcassets/contact_view_message.imageset/message_20@1x.png rename to Session/Meta/Images.xcassets/contact_view_message.imageset/message_20@1x.png diff --git a/Session/Images.xcassets/contact_view_message.imageset/message_20@2x.png b/Session/Meta/Images.xcassets/contact_view_message.imageset/message_20@2x.png similarity index 100% rename from Session/Images.xcassets/contact_view_message.imageset/message_20@2x.png rename to Session/Meta/Images.xcassets/contact_view_message.imageset/message_20@2x.png diff --git a/Session/Images.xcassets/contact_view_message.imageset/message_20@3x.png b/Session/Meta/Images.xcassets/contact_view_message.imageset/message_20@3x.png similarity index 100% rename from Session/Images.xcassets/contact_view_message.imageset/message_20@3x.png rename to Session/Meta/Images.xcassets/contact_view_message.imageset/message_20@3x.png diff --git a/Session/Images.xcassets/contact_view_video_call.imageset/Contents.json b/Session/Meta/Images.xcassets/contact_view_video_call.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/contact_view_video_call.imageset/Contents.json rename to Session/Meta/Images.xcassets/contact_view_video_call.imageset/Contents.json diff --git a/Session/Images.xcassets/contact_view_video_call.imageset/video_20@1x.png b/Session/Meta/Images.xcassets/contact_view_video_call.imageset/video_20@1x.png similarity index 100% rename from Session/Images.xcassets/contact_view_video_call.imageset/video_20@1x.png rename to Session/Meta/Images.xcassets/contact_view_video_call.imageset/video_20@1x.png diff --git a/Session/Images.xcassets/contact_view_video_call.imageset/video_20@2x.png b/Session/Meta/Images.xcassets/contact_view_video_call.imageset/video_20@2x.png similarity index 100% rename from Session/Images.xcassets/contact_view_video_call.imageset/video_20@2x.png rename to Session/Meta/Images.xcassets/contact_view_video_call.imageset/video_20@2x.png diff --git a/Session/Images.xcassets/contact_view_video_call.imageset/video_20@3x.png b/Session/Meta/Images.xcassets/contact_view_video_call.imageset/video_20@3x.png similarity index 100% rename from Session/Images.xcassets/contact_view_video_call.imageset/video_20@3x.png rename to Session/Meta/Images.xcassets/contact_view_video_call.imageset/video_20@3x.png diff --git a/Session/Images.xcassets/conversation_settings_search.imageset/Contents.json b/Session/Meta/Images.xcassets/conversation_settings_search.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/conversation_settings_search.imageset/Contents.json rename to Session/Meta/Images.xcassets/conversation_settings_search.imageset/Contents.json diff --git a/Session/Images.xcassets/conversation_settings_search.imageset/search-24@1x.png b/Session/Meta/Images.xcassets/conversation_settings_search.imageset/search-24@1x.png similarity index 100% rename from Session/Images.xcassets/conversation_settings_search.imageset/search-24@1x.png rename to Session/Meta/Images.xcassets/conversation_settings_search.imageset/search-24@1x.png diff --git a/Session/Images.xcassets/conversation_settings_search.imageset/search-24@2x.png b/Session/Meta/Images.xcassets/conversation_settings_search.imageset/search-24@2x.png similarity index 100% rename from Session/Images.xcassets/conversation_settings_search.imageset/search-24@2x.png rename to Session/Meta/Images.xcassets/conversation_settings_search.imageset/search-24@2x.png diff --git a/Session/Images.xcassets/conversation_settings_search.imageset/search-24@3x.png b/Session/Meta/Images.xcassets/conversation_settings_search.imageset/search-24@3x.png similarity index 100% rename from Session/Images.xcassets/conversation_settings_search.imageset/search-24@3x.png rename to Session/Meta/Images.xcassets/conversation_settings_search.imageset/search-24@3x.png diff --git a/Session/Images.xcassets/disappearing_message_00.imageset/Contents.json b/Session/Meta/Images.xcassets/disappearing_message_00.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/disappearing_message_00.imageset/Contents.json rename to Session/Meta/Images.xcassets/disappearing_message_00.imageset/Contents.json diff --git a/Session/Images.xcassets/disappearing_message_00.imageset/timer00_12@1x.png b/Session/Meta/Images.xcassets/disappearing_message_00.imageset/timer00_12@1x.png similarity index 100% rename from Session/Images.xcassets/disappearing_message_00.imageset/timer00_12@1x.png rename to Session/Meta/Images.xcassets/disappearing_message_00.imageset/timer00_12@1x.png diff --git a/Session/Images.xcassets/disappearing_message_00.imageset/timer00_12@2x.png b/Session/Meta/Images.xcassets/disappearing_message_00.imageset/timer00_12@2x.png similarity index 100% rename from Session/Images.xcassets/disappearing_message_00.imageset/timer00_12@2x.png rename to Session/Meta/Images.xcassets/disappearing_message_00.imageset/timer00_12@2x.png diff --git a/Session/Images.xcassets/disappearing_message_00.imageset/timer00_12@3x.png b/Session/Meta/Images.xcassets/disappearing_message_00.imageset/timer00_12@3x.png similarity index 100% rename from Session/Images.xcassets/disappearing_message_00.imageset/timer00_12@3x.png rename to Session/Meta/Images.xcassets/disappearing_message_00.imageset/timer00_12@3x.png diff --git a/Session/Images.xcassets/disappearing_message_05.imageset/Contents.json b/Session/Meta/Images.xcassets/disappearing_message_05.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/disappearing_message_05.imageset/Contents.json rename to Session/Meta/Images.xcassets/disappearing_message_05.imageset/Contents.json diff --git a/Session/Images.xcassets/disappearing_message_05.imageset/timer05_12@1x.png b/Session/Meta/Images.xcassets/disappearing_message_05.imageset/timer05_12@1x.png similarity index 100% rename from Session/Images.xcassets/disappearing_message_05.imageset/timer05_12@1x.png rename to Session/Meta/Images.xcassets/disappearing_message_05.imageset/timer05_12@1x.png diff --git a/Session/Images.xcassets/disappearing_message_05.imageset/timer05_12@2x.png b/Session/Meta/Images.xcassets/disappearing_message_05.imageset/timer05_12@2x.png similarity index 100% rename from Session/Images.xcassets/disappearing_message_05.imageset/timer05_12@2x.png rename to Session/Meta/Images.xcassets/disappearing_message_05.imageset/timer05_12@2x.png diff --git a/Session/Images.xcassets/disappearing_message_05.imageset/timer05_12@3x.png b/Session/Meta/Images.xcassets/disappearing_message_05.imageset/timer05_12@3x.png similarity index 100% rename from Session/Images.xcassets/disappearing_message_05.imageset/timer05_12@3x.png rename to Session/Meta/Images.xcassets/disappearing_message_05.imageset/timer05_12@3x.png diff --git a/Session/Images.xcassets/disappearing_message_10.imageset/Contents.json b/Session/Meta/Images.xcassets/disappearing_message_10.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/disappearing_message_10.imageset/Contents.json rename to Session/Meta/Images.xcassets/disappearing_message_10.imageset/Contents.json diff --git a/Session/Images.xcassets/disappearing_message_10.imageset/timer10_12@1x.png b/Session/Meta/Images.xcassets/disappearing_message_10.imageset/timer10_12@1x.png similarity index 100% rename from Session/Images.xcassets/disappearing_message_10.imageset/timer10_12@1x.png rename to Session/Meta/Images.xcassets/disappearing_message_10.imageset/timer10_12@1x.png diff --git a/Session/Images.xcassets/disappearing_message_10.imageset/timer10_12@2x.png b/Session/Meta/Images.xcassets/disappearing_message_10.imageset/timer10_12@2x.png similarity index 100% rename from Session/Images.xcassets/disappearing_message_10.imageset/timer10_12@2x.png rename to Session/Meta/Images.xcassets/disappearing_message_10.imageset/timer10_12@2x.png diff --git a/Session/Images.xcassets/disappearing_message_10.imageset/timer10_12@3x.png b/Session/Meta/Images.xcassets/disappearing_message_10.imageset/timer10_12@3x.png similarity index 100% rename from Session/Images.xcassets/disappearing_message_10.imageset/timer10_12@3x.png rename to Session/Meta/Images.xcassets/disappearing_message_10.imageset/timer10_12@3x.png diff --git a/Session/Images.xcassets/disappearing_message_15.imageset/Contents.json b/Session/Meta/Images.xcassets/disappearing_message_15.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/disappearing_message_15.imageset/Contents.json rename to Session/Meta/Images.xcassets/disappearing_message_15.imageset/Contents.json diff --git a/Session/Images.xcassets/disappearing_message_15.imageset/timer15_12@1x.png b/Session/Meta/Images.xcassets/disappearing_message_15.imageset/timer15_12@1x.png similarity index 100% rename from Session/Images.xcassets/disappearing_message_15.imageset/timer15_12@1x.png rename to Session/Meta/Images.xcassets/disappearing_message_15.imageset/timer15_12@1x.png diff --git a/Session/Images.xcassets/disappearing_message_15.imageset/timer15_12@2x.png b/Session/Meta/Images.xcassets/disappearing_message_15.imageset/timer15_12@2x.png similarity index 100% rename from Session/Images.xcassets/disappearing_message_15.imageset/timer15_12@2x.png rename to Session/Meta/Images.xcassets/disappearing_message_15.imageset/timer15_12@2x.png diff --git a/Session/Images.xcassets/disappearing_message_15.imageset/timer15_12@3x.png b/Session/Meta/Images.xcassets/disappearing_message_15.imageset/timer15_12@3x.png similarity index 100% rename from Session/Images.xcassets/disappearing_message_15.imageset/timer15_12@3x.png rename to Session/Meta/Images.xcassets/disappearing_message_15.imageset/timer15_12@3x.png diff --git a/Session/Images.xcassets/disappearing_message_20.imageset/Contents.json b/Session/Meta/Images.xcassets/disappearing_message_20.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/disappearing_message_20.imageset/Contents.json rename to Session/Meta/Images.xcassets/disappearing_message_20.imageset/Contents.json diff --git a/Session/Images.xcassets/disappearing_message_20.imageset/timer20_12@1x.png b/Session/Meta/Images.xcassets/disappearing_message_20.imageset/timer20_12@1x.png similarity index 100% rename from Session/Images.xcassets/disappearing_message_20.imageset/timer20_12@1x.png rename to Session/Meta/Images.xcassets/disappearing_message_20.imageset/timer20_12@1x.png diff --git a/Session/Images.xcassets/disappearing_message_20.imageset/timer20_12@2x.png b/Session/Meta/Images.xcassets/disappearing_message_20.imageset/timer20_12@2x.png similarity index 100% rename from Session/Images.xcassets/disappearing_message_20.imageset/timer20_12@2x.png rename to Session/Meta/Images.xcassets/disappearing_message_20.imageset/timer20_12@2x.png diff --git a/Session/Images.xcassets/disappearing_message_20.imageset/timer20_12@3x.png b/Session/Meta/Images.xcassets/disappearing_message_20.imageset/timer20_12@3x.png similarity index 100% rename from Session/Images.xcassets/disappearing_message_20.imageset/timer20_12@3x.png rename to Session/Meta/Images.xcassets/disappearing_message_20.imageset/timer20_12@3x.png diff --git a/Session/Images.xcassets/disappearing_message_25.imageset/Contents.json b/Session/Meta/Images.xcassets/disappearing_message_25.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/disappearing_message_25.imageset/Contents.json rename to Session/Meta/Images.xcassets/disappearing_message_25.imageset/Contents.json diff --git a/Session/Images.xcassets/disappearing_message_25.imageset/timer25_12@1x.png b/Session/Meta/Images.xcassets/disappearing_message_25.imageset/timer25_12@1x.png similarity index 100% rename from Session/Images.xcassets/disappearing_message_25.imageset/timer25_12@1x.png rename to Session/Meta/Images.xcassets/disappearing_message_25.imageset/timer25_12@1x.png diff --git a/Session/Images.xcassets/disappearing_message_25.imageset/timer25_12@2x.png b/Session/Meta/Images.xcassets/disappearing_message_25.imageset/timer25_12@2x.png similarity index 100% rename from Session/Images.xcassets/disappearing_message_25.imageset/timer25_12@2x.png rename to Session/Meta/Images.xcassets/disappearing_message_25.imageset/timer25_12@2x.png diff --git a/Session/Images.xcassets/disappearing_message_25.imageset/timer25_12@3x.png b/Session/Meta/Images.xcassets/disappearing_message_25.imageset/timer25_12@3x.png similarity index 100% rename from Session/Images.xcassets/disappearing_message_25.imageset/timer25_12@3x.png rename to Session/Meta/Images.xcassets/disappearing_message_25.imageset/timer25_12@3x.png diff --git a/Session/Images.xcassets/disappearing_message_30.imageset/Contents.json b/Session/Meta/Images.xcassets/disappearing_message_30.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/disappearing_message_30.imageset/Contents.json rename to Session/Meta/Images.xcassets/disappearing_message_30.imageset/Contents.json diff --git a/Session/Images.xcassets/disappearing_message_30.imageset/timer30_12@1x.png b/Session/Meta/Images.xcassets/disappearing_message_30.imageset/timer30_12@1x.png similarity index 100% rename from Session/Images.xcassets/disappearing_message_30.imageset/timer30_12@1x.png rename to Session/Meta/Images.xcassets/disappearing_message_30.imageset/timer30_12@1x.png diff --git a/Session/Images.xcassets/disappearing_message_30.imageset/timer30_12@2x.png b/Session/Meta/Images.xcassets/disappearing_message_30.imageset/timer30_12@2x.png similarity index 100% rename from Session/Images.xcassets/disappearing_message_30.imageset/timer30_12@2x.png rename to Session/Meta/Images.xcassets/disappearing_message_30.imageset/timer30_12@2x.png diff --git a/Session/Images.xcassets/disappearing_message_30.imageset/timer30_12@3x.png b/Session/Meta/Images.xcassets/disappearing_message_30.imageset/timer30_12@3x.png similarity index 100% rename from Session/Images.xcassets/disappearing_message_30.imageset/timer30_12@3x.png rename to Session/Meta/Images.xcassets/disappearing_message_30.imageset/timer30_12@3x.png diff --git a/Session/Images.xcassets/disappearing_message_35.imageset/Contents.json b/Session/Meta/Images.xcassets/disappearing_message_35.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/disappearing_message_35.imageset/Contents.json rename to Session/Meta/Images.xcassets/disappearing_message_35.imageset/Contents.json diff --git a/Session/Images.xcassets/disappearing_message_35.imageset/timer35_12@1x.png b/Session/Meta/Images.xcassets/disappearing_message_35.imageset/timer35_12@1x.png similarity index 100% rename from Session/Images.xcassets/disappearing_message_35.imageset/timer35_12@1x.png rename to Session/Meta/Images.xcassets/disappearing_message_35.imageset/timer35_12@1x.png diff --git a/Session/Images.xcassets/disappearing_message_35.imageset/timer35_12@2x.png b/Session/Meta/Images.xcassets/disappearing_message_35.imageset/timer35_12@2x.png similarity index 100% rename from Session/Images.xcassets/disappearing_message_35.imageset/timer35_12@2x.png rename to Session/Meta/Images.xcassets/disappearing_message_35.imageset/timer35_12@2x.png diff --git a/Session/Images.xcassets/disappearing_message_35.imageset/timer35_12@3x.png b/Session/Meta/Images.xcassets/disappearing_message_35.imageset/timer35_12@3x.png similarity index 100% rename from Session/Images.xcassets/disappearing_message_35.imageset/timer35_12@3x.png rename to Session/Meta/Images.xcassets/disappearing_message_35.imageset/timer35_12@3x.png diff --git a/Session/Images.xcassets/disappearing_message_40.imageset/Contents.json b/Session/Meta/Images.xcassets/disappearing_message_40.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/disappearing_message_40.imageset/Contents.json rename to Session/Meta/Images.xcassets/disappearing_message_40.imageset/Contents.json diff --git a/Session/Images.xcassets/disappearing_message_40.imageset/timer40_12@1x.png b/Session/Meta/Images.xcassets/disappearing_message_40.imageset/timer40_12@1x.png similarity index 100% rename from Session/Images.xcassets/disappearing_message_40.imageset/timer40_12@1x.png rename to Session/Meta/Images.xcassets/disappearing_message_40.imageset/timer40_12@1x.png diff --git a/Session/Images.xcassets/disappearing_message_40.imageset/timer40_12@2x.png b/Session/Meta/Images.xcassets/disappearing_message_40.imageset/timer40_12@2x.png similarity index 100% rename from Session/Images.xcassets/disappearing_message_40.imageset/timer40_12@2x.png rename to Session/Meta/Images.xcassets/disappearing_message_40.imageset/timer40_12@2x.png diff --git a/Session/Images.xcassets/disappearing_message_40.imageset/timer40_12@3x.png b/Session/Meta/Images.xcassets/disappearing_message_40.imageset/timer40_12@3x.png similarity index 100% rename from Session/Images.xcassets/disappearing_message_40.imageset/timer40_12@3x.png rename to Session/Meta/Images.xcassets/disappearing_message_40.imageset/timer40_12@3x.png diff --git a/Session/Images.xcassets/disappearing_message_45.imageset/Contents.json b/Session/Meta/Images.xcassets/disappearing_message_45.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/disappearing_message_45.imageset/Contents.json rename to Session/Meta/Images.xcassets/disappearing_message_45.imageset/Contents.json diff --git a/Session/Images.xcassets/disappearing_message_45.imageset/timer45_12@1x.png b/Session/Meta/Images.xcassets/disappearing_message_45.imageset/timer45_12@1x.png similarity index 100% rename from Session/Images.xcassets/disappearing_message_45.imageset/timer45_12@1x.png rename to Session/Meta/Images.xcassets/disappearing_message_45.imageset/timer45_12@1x.png diff --git a/Session/Images.xcassets/disappearing_message_45.imageset/timer45_12@2x.png b/Session/Meta/Images.xcassets/disappearing_message_45.imageset/timer45_12@2x.png similarity index 100% rename from Session/Images.xcassets/disappearing_message_45.imageset/timer45_12@2x.png rename to Session/Meta/Images.xcassets/disappearing_message_45.imageset/timer45_12@2x.png diff --git a/Session/Images.xcassets/disappearing_message_45.imageset/timer45_12@3x.png b/Session/Meta/Images.xcassets/disappearing_message_45.imageset/timer45_12@3x.png similarity index 100% rename from Session/Images.xcassets/disappearing_message_45.imageset/timer45_12@3x.png rename to Session/Meta/Images.xcassets/disappearing_message_45.imageset/timer45_12@3x.png diff --git a/Session/Images.xcassets/disappearing_message_50.imageset/Contents.json b/Session/Meta/Images.xcassets/disappearing_message_50.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/disappearing_message_50.imageset/Contents.json rename to Session/Meta/Images.xcassets/disappearing_message_50.imageset/Contents.json diff --git a/Session/Images.xcassets/disappearing_message_50.imageset/timer50_12@1x.png b/Session/Meta/Images.xcassets/disappearing_message_50.imageset/timer50_12@1x.png similarity index 100% rename from Session/Images.xcassets/disappearing_message_50.imageset/timer50_12@1x.png rename to Session/Meta/Images.xcassets/disappearing_message_50.imageset/timer50_12@1x.png diff --git a/Session/Images.xcassets/disappearing_message_50.imageset/timer50_12@2x.png b/Session/Meta/Images.xcassets/disappearing_message_50.imageset/timer50_12@2x.png similarity index 100% rename from Session/Images.xcassets/disappearing_message_50.imageset/timer50_12@2x.png rename to Session/Meta/Images.xcassets/disappearing_message_50.imageset/timer50_12@2x.png diff --git a/Session/Images.xcassets/disappearing_message_50.imageset/timer50_12@3x.png b/Session/Meta/Images.xcassets/disappearing_message_50.imageset/timer50_12@3x.png similarity index 100% rename from Session/Images.xcassets/disappearing_message_50.imageset/timer50_12@3x.png rename to Session/Meta/Images.xcassets/disappearing_message_50.imageset/timer50_12@3x.png diff --git a/Session/Images.xcassets/disappearing_message_55.imageset/Contents.json b/Session/Meta/Images.xcassets/disappearing_message_55.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/disappearing_message_55.imageset/Contents.json rename to Session/Meta/Images.xcassets/disappearing_message_55.imageset/Contents.json diff --git a/Session/Images.xcassets/disappearing_message_55.imageset/timer55_12@1x.png b/Session/Meta/Images.xcassets/disappearing_message_55.imageset/timer55_12@1x.png similarity index 100% rename from Session/Images.xcassets/disappearing_message_55.imageset/timer55_12@1x.png rename to Session/Meta/Images.xcassets/disappearing_message_55.imageset/timer55_12@1x.png diff --git a/Session/Images.xcassets/disappearing_message_55.imageset/timer55_12@2x.png b/Session/Meta/Images.xcassets/disappearing_message_55.imageset/timer55_12@2x.png similarity index 100% rename from Session/Images.xcassets/disappearing_message_55.imageset/timer55_12@2x.png rename to Session/Meta/Images.xcassets/disappearing_message_55.imageset/timer55_12@2x.png diff --git a/Session/Images.xcassets/disappearing_message_55.imageset/timer55_12@3x.png b/Session/Meta/Images.xcassets/disappearing_message_55.imageset/timer55_12@3x.png similarity index 100% rename from Session/Images.xcassets/disappearing_message_55.imageset/timer55_12@3x.png rename to Session/Meta/Images.xcassets/disappearing_message_55.imageset/timer55_12@3x.png diff --git a/Session/Images.xcassets/disappearing_message_60.imageset/Contents.json b/Session/Meta/Images.xcassets/disappearing_message_60.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/disappearing_message_60.imageset/Contents.json rename to Session/Meta/Images.xcassets/disappearing_message_60.imageset/Contents.json diff --git a/Session/Images.xcassets/disappearing_message_60.imageset/timer60_12@1x.png b/Session/Meta/Images.xcassets/disappearing_message_60.imageset/timer60_12@1x.png similarity index 100% rename from Session/Images.xcassets/disappearing_message_60.imageset/timer60_12@1x.png rename to Session/Meta/Images.xcassets/disappearing_message_60.imageset/timer60_12@1x.png diff --git a/Session/Images.xcassets/disappearing_message_60.imageset/timer60_12@2x.png b/Session/Meta/Images.xcassets/disappearing_message_60.imageset/timer60_12@2x.png similarity index 100% rename from Session/Images.xcassets/disappearing_message_60.imageset/timer60_12@2x.png rename to Session/Meta/Images.xcassets/disappearing_message_60.imageset/timer60_12@2x.png diff --git a/Session/Images.xcassets/disappearing_message_60.imageset/timer60_12@3x.png b/Session/Meta/Images.xcassets/disappearing_message_60.imageset/timer60_12@3x.png similarity index 100% rename from Session/Images.xcassets/disappearing_message_60.imageset/timer60_12@3x.png rename to Session/Meta/Images.xcassets/disappearing_message_60.imageset/timer60_12@3x.png diff --git a/Session/Images.xcassets/file-black-40.imageset/Contents.json b/Session/Meta/Images.xcassets/file-black-40.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/file-black-40.imageset/Contents.json rename to Session/Meta/Images.xcassets/file-black-40.imageset/Contents.json diff --git a/Session/Images.xcassets/file-black-40.imageset/file-black-40@1x.png b/Session/Meta/Images.xcassets/file-black-40.imageset/file-black-40@1x.png similarity index 100% rename from Session/Images.xcassets/file-black-40.imageset/file-black-40@1x.png rename to Session/Meta/Images.xcassets/file-black-40.imageset/file-black-40@1x.png diff --git a/Session/Images.xcassets/file-black-40.imageset/file-black-40@2x.png b/Session/Meta/Images.xcassets/file-black-40.imageset/file-black-40@2x.png similarity index 100% rename from Session/Images.xcassets/file-black-40.imageset/file-black-40@2x.png rename to Session/Meta/Images.xcassets/file-black-40.imageset/file-black-40@2x.png diff --git a/Session/Images.xcassets/file-black-40.imageset/file-black-40@3x.png b/Session/Meta/Images.xcassets/file-black-40.imageset/file-black-40@3x.png similarity index 100% rename from Session/Images.xcassets/file-black-40.imageset/file-black-40@3x.png rename to Session/Meta/Images.xcassets/file-black-40.imageset/file-black-40@3x.png diff --git a/Session/Images.xcassets/file-icon-large.imageset/Contents.json b/Session/Meta/Images.xcassets/file-icon-large.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/file-icon-large.imageset/Contents.json rename to Session/Meta/Images.xcassets/file-icon-large.imageset/Contents.json diff --git a/Session/Images.xcassets/file-icon-large.imageset/file-icon-large@1x.png b/Session/Meta/Images.xcassets/file-icon-large.imageset/file-icon-large@1x.png similarity index 100% rename from Session/Images.xcassets/file-icon-large.imageset/file-icon-large@1x.png rename to Session/Meta/Images.xcassets/file-icon-large.imageset/file-icon-large@1x.png diff --git a/Session/Images.xcassets/file-thin-black-filled-large.imageset/Contents.json b/Session/Meta/Images.xcassets/file-thin-black-filled-large.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/file-thin-black-filled-large.imageset/Contents.json rename to Session/Meta/Images.xcassets/file-thin-black-filled-large.imageset/Contents.json diff --git a/Session/Images.xcassets/file-thin-black-filled-large.imageset/file-thin-black-w-shadow-large.png b/Session/Meta/Images.xcassets/file-thin-black-filled-large.imageset/file-thin-black-w-shadow-large.png similarity index 100% rename from Session/Images.xcassets/file-thin-black-filled-large.imageset/file-thin-black-w-shadow-large.png rename to Session/Meta/Images.xcassets/file-thin-black-filled-large.imageset/file-thin-black-w-shadow-large.png diff --git a/Session/Images.xcassets/file-thin-black-large.imageset/Contents.json b/Session/Meta/Images.xcassets/file-thin-black-large.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/file-thin-black-large.imageset/Contents.json rename to Session/Meta/Images.xcassets/file-thin-black-large.imageset/Contents.json diff --git a/Session/Images.xcassets/file-thin-black-large.imageset/file-thin-black-large.png b/Session/Meta/Images.xcassets/file-thin-black-large.imageset/file-thin-black-large.png similarity index 100% rename from Session/Images.xcassets/file-thin-black-large.imageset/file-thin-black-large.png rename to Session/Meta/Images.xcassets/file-thin-black-large.imageset/file-thin-black-large.png diff --git a/Session/Images.xcassets/file-white-40.imageset/Contents.json b/Session/Meta/Images.xcassets/file-white-40.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/file-white-40.imageset/Contents.json rename to Session/Meta/Images.xcassets/file-white-40.imageset/Contents.json diff --git a/Session/Images.xcassets/file-white-40.imageset/file-white-40@1x.png b/Session/Meta/Images.xcassets/file-white-40.imageset/file-white-40@1x.png similarity index 100% rename from Session/Images.xcassets/file-white-40.imageset/file-white-40@1x.png rename to Session/Meta/Images.xcassets/file-white-40.imageset/file-white-40@1x.png diff --git a/Session/Images.xcassets/file-white-40.imageset/file-white-40@2x.png b/Session/Meta/Images.xcassets/file-white-40.imageset/file-white-40@2x.png similarity index 100% rename from Session/Images.xcassets/file-white-40.imageset/file-white-40@2x.png rename to Session/Meta/Images.xcassets/file-white-40.imageset/file-white-40@2x.png diff --git a/Session/Images.xcassets/file-white-40.imageset/file-white-40@3x.png b/Session/Meta/Images.xcassets/file-white-40.imageset/file-white-40@3x.png similarity index 100% rename from Session/Images.xcassets/file-white-40.imageset/file-white-40@3x.png rename to Session/Meta/Images.xcassets/file-white-40.imageset/file-white-40@3x.png diff --git a/Session/Images.xcassets/generic-attachment-small.imageset/Contents.json b/Session/Meta/Images.xcassets/generic-attachment-small.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/generic-attachment-small.imageset/Contents.json rename to Session/Meta/Images.xcassets/generic-attachment-small.imageset/Contents.json diff --git a/Session/Images.xcassets/generic-attachment-small.imageset/generic-attachment-small@1x.png b/Session/Meta/Images.xcassets/generic-attachment-small.imageset/generic-attachment-small@1x.png similarity index 100% rename from Session/Images.xcassets/generic-attachment-small.imageset/generic-attachment-small@1x.png rename to Session/Meta/Images.xcassets/generic-attachment-small.imageset/generic-attachment-small@1x.png diff --git a/Session/Images.xcassets/generic-attachment-small.imageset/generic-attachment-small@2x.png b/Session/Meta/Images.xcassets/generic-attachment-small.imageset/generic-attachment-small@2x.png similarity index 100% rename from Session/Images.xcassets/generic-attachment-small.imageset/generic-attachment-small@2x.png rename to Session/Meta/Images.xcassets/generic-attachment-small.imageset/generic-attachment-small@2x.png diff --git a/Session/Images.xcassets/generic-attachment-small.imageset/generic-attachment-small@3x.png b/Session/Meta/Images.xcassets/generic-attachment-small.imageset/generic-attachment-small@3x.png similarity index 100% rename from Session/Images.xcassets/generic-attachment-small.imageset/generic-attachment-small@3x.png rename to Session/Meta/Images.xcassets/generic-attachment-small.imageset/generic-attachment-small@3x.png diff --git a/Session/Images.xcassets/generic-attachment.imageset/Contents.json b/Session/Meta/Images.xcassets/generic-attachment.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/generic-attachment.imageset/Contents.json rename to Session/Meta/Images.xcassets/generic-attachment.imageset/Contents.json diff --git a/Session/Images.xcassets/generic-attachment.imageset/file-light-large@1x.png b/Session/Meta/Images.xcassets/generic-attachment.imageset/file-light-large@1x.png similarity index 100% rename from Session/Images.xcassets/generic-attachment.imageset/file-light-large@1x.png rename to Session/Meta/Images.xcassets/generic-attachment.imageset/file-light-large@1x.png diff --git a/Session/Images.xcassets/generic-attachment.imageset/file-light-large@2x.png b/Session/Meta/Images.xcassets/generic-attachment.imageset/file-light-large@2x.png similarity index 100% rename from Session/Images.xcassets/generic-attachment.imageset/file-light-large@2x.png rename to Session/Meta/Images.xcassets/generic-attachment.imageset/file-light-large@2x.png diff --git a/Session/Images.xcassets/generic-attachment.imageset/file-light-large@3x.png b/Session/Meta/Images.xcassets/generic-attachment.imageset/file-light-large@3x.png similarity index 100% rename from Session/Images.xcassets/generic-attachment.imageset/file-light-large@3x.png rename to Session/Meta/Images.xcassets/generic-attachment.imageset/file-light-large@3x.png diff --git a/Session/Images.xcassets/giphy_logo.imageset/Contents.json b/Session/Meta/Images.xcassets/giphy_logo.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/giphy_logo.imageset/Contents.json rename to Session/Meta/Images.xcassets/giphy_logo.imageset/Contents.json diff --git a/Session/Images.xcassets/giphy_logo.imageset/giphy_logo_2@1x.png b/Session/Meta/Images.xcassets/giphy_logo.imageset/giphy_logo_2@1x.png similarity index 100% rename from Session/Images.xcassets/giphy_logo.imageset/giphy_logo_2@1x.png rename to Session/Meta/Images.xcassets/giphy_logo.imageset/giphy_logo_2@1x.png diff --git a/Session/Images.xcassets/giphy_logo.imageset/giphy_logo_2@2x.png b/Session/Meta/Images.xcassets/giphy_logo.imageset/giphy_logo_2@2x.png similarity index 100% rename from Session/Images.xcassets/giphy_logo.imageset/giphy_logo_2@2x.png rename to Session/Meta/Images.xcassets/giphy_logo.imageset/giphy_logo_2@2x.png diff --git a/Session/Images.xcassets/giphy_logo.imageset/giphy_logo_2@3x.png b/Session/Meta/Images.xcassets/giphy_logo.imageset/giphy_logo_2@3x.png similarity index 100% rename from Session/Images.xcassets/giphy_logo.imageset/giphy_logo_2@3x.png rename to Session/Meta/Images.xcassets/giphy_logo.imageset/giphy_logo_2@3x.png diff --git a/Session/Images.xcassets/group-avatar.imageset/Contents.json b/Session/Meta/Images.xcassets/group-avatar.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/group-avatar.imageset/Contents.json rename to Session/Meta/Images.xcassets/group-avatar.imageset/Contents.json diff --git a/Session/Images.xcassets/group-avatar.imageset/group-28-white@1x.png b/Session/Meta/Images.xcassets/group-avatar.imageset/group-28-white@1x.png similarity index 100% rename from Session/Images.xcassets/group-avatar.imageset/group-28-white@1x.png rename to Session/Meta/Images.xcassets/group-avatar.imageset/group-28-white@1x.png diff --git a/Session/Images.xcassets/group-avatar.imageset/group-28-white@2x.png b/Session/Meta/Images.xcassets/group-avatar.imageset/group-28-white@2x.png similarity index 100% rename from Session/Images.xcassets/group-avatar.imageset/group-28-white@2x.png rename to Session/Meta/Images.xcassets/group-avatar.imageset/group-28-white@2x.png diff --git a/Session/Images.xcassets/group-avatar.imageset/group-28-white@3x.png b/Session/Meta/Images.xcassets/group-avatar.imageset/group-28-white@3x.png similarity index 100% rename from Session/Images.xcassets/group-avatar.imageset/group-28-white@3x.png rename to Session/Meta/Images.xcassets/group-avatar.imageset/group-28-white@3x.png diff --git a/Session/Images.xcassets/hangup-active-wide.imageset/Contents.json b/Session/Meta/Images.xcassets/hangup-active-wide.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/hangup-active-wide.imageset/Contents.json rename to Session/Meta/Images.xcassets/hangup-active-wide.imageset/Contents.json diff --git a/Session/Images.xcassets/hangup-active-wide.imageset/hangup-active-wide.png b/Session/Meta/Images.xcassets/hangup-active-wide.imageset/hangup-active-wide.png similarity index 100% rename from Session/Images.xcassets/hangup-active-wide.imageset/hangup-active-wide.png rename to Session/Meta/Images.xcassets/hangup-active-wide.imageset/hangup-active-wide.png diff --git a/Session/Images.xcassets/home_empty_splash_1.imageset/Contents.json b/Session/Meta/Images.xcassets/home_empty_splash_1.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/home_empty_splash_1.imageset/Contents.json rename to Session/Meta/Images.xcassets/home_empty_splash_1.imageset/Contents.json diff --git a/Session/Images.xcassets/home_empty_splash_1.imageset/human-1@3x.png b/Session/Meta/Images.xcassets/home_empty_splash_1.imageset/human-1@3x.png similarity index 100% rename from Session/Images.xcassets/home_empty_splash_1.imageset/human-1@3x.png rename to Session/Meta/Images.xcassets/home_empty_splash_1.imageset/human-1@3x.png diff --git a/Session/Images.xcassets/home_empty_splash_2.imageset/Contents.json b/Session/Meta/Images.xcassets/home_empty_splash_2.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/home_empty_splash_2.imageset/Contents.json rename to Session/Meta/Images.xcassets/home_empty_splash_2.imageset/Contents.json diff --git a/Session/Images.xcassets/home_empty_splash_2.imageset/human-2@3x.png b/Session/Meta/Images.xcassets/home_empty_splash_2.imageset/human-2@3x.png similarity index 100% rename from Session/Images.xcassets/home_empty_splash_2.imageset/human-2@3x.png rename to Session/Meta/Images.xcassets/home_empty_splash_2.imageset/human-2@3x.png diff --git a/Session/Images.xcassets/home_empty_splash_3.imageset/Contents.json b/Session/Meta/Images.xcassets/home_empty_splash_3.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/home_empty_splash_3.imageset/Contents.json rename to Session/Meta/Images.xcassets/home_empty_splash_3.imageset/Contents.json diff --git a/Session/Images.xcassets/home_empty_splash_3.imageset/human-3@3x.png b/Session/Meta/Images.xcassets/home_empty_splash_3.imageset/human-3@3x.png similarity index 100% rename from Session/Images.xcassets/home_empty_splash_3.imageset/human-3@3x.png rename to Session/Meta/Images.xcassets/home_empty_splash_3.imageset/human-3@3x.png diff --git a/Session/Images.xcassets/home_empty_splash_4.imageset/Contents.json b/Session/Meta/Images.xcassets/home_empty_splash_4.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/home_empty_splash_4.imageset/Contents.json rename to Session/Meta/Images.xcassets/home_empty_splash_4.imageset/Contents.json diff --git a/Session/Images.xcassets/home_empty_splash_4.imageset/human-4@3x.png b/Session/Meta/Images.xcassets/home_empty_splash_4.imageset/human-4@3x.png similarity index 100% rename from Session/Images.xcassets/home_empty_splash_4.imageset/human-4@3x.png rename to Session/Meta/Images.xcassets/home_empty_splash_4.imageset/human-4@3x.png diff --git a/Session/Images.xcassets/home_empty_splash_5.imageset/Contents.json b/Session/Meta/Images.xcassets/home_empty_splash_5.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/home_empty_splash_5.imageset/Contents.json rename to Session/Meta/Images.xcassets/home_empty_splash_5.imageset/Contents.json diff --git a/Session/Images.xcassets/home_empty_splash_5.imageset/human-5@3x.png b/Session/Meta/Images.xcassets/home_empty_splash_5.imageset/human-5@3x.png similarity index 100% rename from Session/Images.xcassets/home_empty_splash_5.imageset/human-5@3x.png rename to Session/Meta/Images.xcassets/home_empty_splash_5.imageset/human-5@3x.png diff --git a/Session/Images.xcassets/ic_add_caption.imageset/Contents.json b/Session/Meta/Images.xcassets/ic_add_caption.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/ic_add_caption.imageset/Contents.json rename to Session/Meta/Images.xcassets/ic_add_caption.imageset/Contents.json diff --git a/Session/Images.xcassets/ic_add_caption.imageset/add-caption-24@1x.png b/Session/Meta/Images.xcassets/ic_add_caption.imageset/add-caption-24@1x.png similarity index 100% rename from Session/Images.xcassets/ic_add_caption.imageset/add-caption-24@1x.png rename to Session/Meta/Images.xcassets/ic_add_caption.imageset/add-caption-24@1x.png diff --git a/Session/Images.xcassets/ic_add_caption.imageset/add-caption-24@2x.png b/Session/Meta/Images.xcassets/ic_add_caption.imageset/add-caption-24@2x.png similarity index 100% rename from Session/Images.xcassets/ic_add_caption.imageset/add-caption-24@2x.png rename to Session/Meta/Images.xcassets/ic_add_caption.imageset/add-caption-24@2x.png diff --git a/Session/Images.xcassets/ic_add_caption.imageset/add-caption-24@3x.png b/Session/Meta/Images.xcassets/ic_add_caption.imageset/add-caption-24@3x.png similarity index 100% rename from Session/Images.xcassets/ic_add_caption.imageset/add-caption-24@3x.png rename to Session/Meta/Images.xcassets/ic_add_caption.imageset/add-caption-24@3x.png diff --git a/Session/Images.xcassets/ic_block.imageset/Contents.json b/Session/Meta/Images.xcassets/ic_block.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/ic_block.imageset/Contents.json rename to Session/Meta/Images.xcassets/ic_block.imageset/Contents.json diff --git a/Session/Images.xcassets/ic_block.imageset/ic_block@1x.png b/Session/Meta/Images.xcassets/ic_block.imageset/ic_block@1x.png similarity index 100% rename from Session/Images.xcassets/ic_block.imageset/ic_block@1x.png rename to Session/Meta/Images.xcassets/ic_block.imageset/ic_block@1x.png diff --git a/Session/Images.xcassets/ic_block.imageset/ic_block@2x.png b/Session/Meta/Images.xcassets/ic_block.imageset/ic_block@2x.png similarity index 100% rename from Session/Images.xcassets/ic_block.imageset/ic_block@2x.png rename to Session/Meta/Images.xcassets/ic_block.imageset/ic_block@2x.png diff --git a/Session/Images.xcassets/ic_block.imageset/ic_block@3x.png b/Session/Meta/Images.xcassets/ic_block.imageset/ic_block@3x.png similarity index 100% rename from Session/Images.xcassets/ic_block.imageset/ic_block@3x.png rename to Session/Meta/Images.xcassets/ic_block.imageset/ic_block@3x.png diff --git a/Session/Images.xcassets/ic_broken_link.imageset/Contents.json b/Session/Meta/Images.xcassets/ic_broken_link.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/ic_broken_link.imageset/Contents.json rename to Session/Meta/Images.xcassets/ic_broken_link.imageset/Contents.json diff --git a/Session/Images.xcassets/ic_broken_link.imageset/broken-link-16@1x.png b/Session/Meta/Images.xcassets/ic_broken_link.imageset/broken-link-16@1x.png similarity index 100% rename from Session/Images.xcassets/ic_broken_link.imageset/broken-link-16@1x.png rename to Session/Meta/Images.xcassets/ic_broken_link.imageset/broken-link-16@1x.png diff --git a/Session/Images.xcassets/ic_broken_link.imageset/broken-link-16@2x.png b/Session/Meta/Images.xcassets/ic_broken_link.imageset/broken-link-16@2x.png similarity index 100% rename from Session/Images.xcassets/ic_broken_link.imageset/broken-link-16@2x.png rename to Session/Meta/Images.xcassets/ic_broken_link.imageset/broken-link-16@2x.png diff --git a/Session/Images.xcassets/ic_broken_link.imageset/broken-link-16@3x.png b/Session/Meta/Images.xcassets/ic_broken_link.imageset/broken-link-16@3x.png similarity index 100% rename from Session/Images.xcassets/ic_broken_link.imageset/broken-link-16@3x.png rename to Session/Meta/Images.xcassets/ic_broken_link.imageset/broken-link-16@3x.png diff --git a/Session/Images.xcassets/ic_chevron_down.imageset/Contents.json b/Session/Meta/Images.xcassets/ic_chevron_down.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/ic_chevron_down.imageset/Contents.json rename to Session/Meta/Images.xcassets/ic_chevron_down.imageset/Contents.json diff --git a/Session/Images.xcassets/ic_chevron_down.imageset/chevron-down-24@1x.png b/Session/Meta/Images.xcassets/ic_chevron_down.imageset/chevron-down-24@1x.png similarity index 100% rename from Session/Images.xcassets/ic_chevron_down.imageset/chevron-down-24@1x.png rename to Session/Meta/Images.xcassets/ic_chevron_down.imageset/chevron-down-24@1x.png diff --git a/Session/Images.xcassets/ic_chevron_down.imageset/chevron-down-24@2x.png b/Session/Meta/Images.xcassets/ic_chevron_down.imageset/chevron-down-24@2x.png similarity index 100% rename from Session/Images.xcassets/ic_chevron_down.imageset/chevron-down-24@2x.png rename to Session/Meta/Images.xcassets/ic_chevron_down.imageset/chevron-down-24@2x.png diff --git a/Session/Images.xcassets/ic_chevron_down.imageset/chevron-down-24@3x.png b/Session/Meta/Images.xcassets/ic_chevron_down.imageset/chevron-down-24@3x.png similarity index 100% rename from Session/Images.xcassets/ic_chevron_down.imageset/chevron-down-24@3x.png rename to Session/Meta/Images.xcassets/ic_chevron_down.imageset/chevron-down-24@3x.png diff --git a/Session/Images.xcassets/ic_chevron_up.imageset/Contents.json b/Session/Meta/Images.xcassets/ic_chevron_up.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/ic_chevron_up.imageset/Contents.json rename to Session/Meta/Images.xcassets/ic_chevron_up.imageset/Contents.json diff --git a/Session/Images.xcassets/ic_chevron_up.imageset/chevron-up-24@1x.png b/Session/Meta/Images.xcassets/ic_chevron_up.imageset/chevron-up-24@1x.png similarity index 100% rename from Session/Images.xcassets/ic_chevron_up.imageset/chevron-up-24@1x.png rename to Session/Meta/Images.xcassets/ic_chevron_up.imageset/chevron-up-24@1x.png diff --git a/Session/Images.xcassets/ic_chevron_up.imageset/chevron-up-24@2x.png b/Session/Meta/Images.xcassets/ic_chevron_up.imageset/chevron-up-24@2x.png similarity index 100% rename from Session/Images.xcassets/ic_chevron_up.imageset/chevron-up-24@2x.png rename to Session/Meta/Images.xcassets/ic_chevron_up.imageset/chevron-up-24@2x.png diff --git a/Session/Images.xcassets/ic_chevron_up.imageset/chevron-up-24@3x.png b/Session/Meta/Images.xcassets/ic_chevron_up.imageset/chevron-up-24@3x.png similarity index 100% rename from Session/Images.xcassets/ic_chevron_up.imageset/chevron-up-24@3x.png rename to Session/Meta/Images.xcassets/ic_chevron_up.imageset/chevron-up-24@3x.png diff --git a/Session/Images.xcassets/ic_circled_plus.imageset/Contents.json b/Session/Meta/Images.xcassets/ic_circled_plus.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/ic_circled_plus.imageset/Contents.json rename to Session/Meta/Images.xcassets/ic_circled_plus.imageset/Contents.json diff --git a/Session/Images.xcassets/ic_circled_plus.imageset/UIRemoveControlPlus_22x22_@1x.png b/Session/Meta/Images.xcassets/ic_circled_plus.imageset/UIRemoveControlPlus_22x22_@1x.png similarity index 100% rename from Session/Images.xcassets/ic_circled_plus.imageset/UIRemoveControlPlus_22x22_@1x.png rename to Session/Meta/Images.xcassets/ic_circled_plus.imageset/UIRemoveControlPlus_22x22_@1x.png diff --git a/Session/Images.xcassets/ic_circled_plus.imageset/UIRemoveControlPlus_22x22_@2x.png b/Session/Meta/Images.xcassets/ic_circled_plus.imageset/UIRemoveControlPlus_22x22_@2x.png similarity index 100% rename from Session/Images.xcassets/ic_circled_plus.imageset/UIRemoveControlPlus_22x22_@2x.png rename to Session/Meta/Images.xcassets/ic_circled_plus.imageset/UIRemoveControlPlus_22x22_@2x.png diff --git a/Session/Images.xcassets/ic_circled_plus.imageset/UIRemoveControlPlus_22x22_@3x.png b/Session/Meta/Images.xcassets/ic_circled_plus.imageset/UIRemoveControlPlus_22x22_@3x.png similarity index 100% rename from Session/Images.xcassets/ic_circled_plus.imageset/UIRemoveControlPlus_22x22_@3x.png rename to Session/Meta/Images.xcassets/ic_circled_plus.imageset/UIRemoveControlPlus_22x22_@3x.png diff --git a/Session/Images.xcassets/ic_circled_x.imageset/Contents.json b/Session/Meta/Images.xcassets/ic_circled_x.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/ic_circled_x.imageset/Contents.json rename to Session/Meta/Images.xcassets/ic_circled_x.imageset/Contents.json diff --git a/Session/Images.xcassets/ic_circled_x.imageset/x-circle-shadow-24@1x.png b/Session/Meta/Images.xcassets/ic_circled_x.imageset/x-circle-shadow-24@1x.png similarity index 100% rename from Session/Images.xcassets/ic_circled_x.imageset/x-circle-shadow-24@1x.png rename to Session/Meta/Images.xcassets/ic_circled_x.imageset/x-circle-shadow-24@1x.png diff --git a/Session/Images.xcassets/ic_circled_x.imageset/x-circle-shadow-24@2x.png b/Session/Meta/Images.xcassets/ic_circled_x.imageset/x-circle-shadow-24@2x.png similarity index 100% rename from Session/Images.xcassets/ic_circled_x.imageset/x-circle-shadow-24@2x.png rename to Session/Meta/Images.xcassets/ic_circled_x.imageset/x-circle-shadow-24@2x.png diff --git a/Session/Images.xcassets/ic_circled_x.imageset/x-circle-shadow-24@3x.png b/Session/Meta/Images.xcassets/ic_circled_x.imageset/x-circle-shadow-24@3x.png similarity index 100% rename from Session/Images.xcassets/ic_circled_x.imageset/x-circle-shadow-24@3x.png rename to Session/Meta/Images.xcassets/ic_circled_x.imageset/x-circle-shadow-24@3x.png diff --git a/Session/Images.xcassets/ic_color_palette.imageset/Contents.json b/Session/Meta/Images.xcassets/ic_color_palette.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/ic_color_palette.imageset/Contents.json rename to Session/Meta/Images.xcassets/ic_color_palette.imageset/Contents.json diff --git a/Session/Images.xcassets/ic_color_palette.imageset/color-palette-24@1x.png b/Session/Meta/Images.xcassets/ic_color_palette.imageset/color-palette-24@1x.png similarity index 100% rename from Session/Images.xcassets/ic_color_palette.imageset/color-palette-24@1x.png rename to Session/Meta/Images.xcassets/ic_color_palette.imageset/color-palette-24@1x.png diff --git a/Session/Images.xcassets/ic_color_palette.imageset/color-palette-24@2x.png b/Session/Meta/Images.xcassets/ic_color_palette.imageset/color-palette-24@2x.png similarity index 100% rename from Session/Images.xcassets/ic_color_palette.imageset/color-palette-24@2x.png rename to Session/Meta/Images.xcassets/ic_color_palette.imageset/color-palette-24@2x.png diff --git a/Session/Images.xcassets/ic_color_palette.imageset/color-palette-24@3x.png b/Session/Meta/Images.xcassets/ic_color_palette.imageset/color-palette-24@3x.png similarity index 100% rename from Session/Images.xcassets/ic_color_palette.imageset/color-palette-24@3x.png rename to Session/Meta/Images.xcassets/ic_color_palette.imageset/color-palette-24@3x.png diff --git a/Session/Images.xcassets/ic_copy.imageset/Contents.json b/Session/Meta/Images.xcassets/ic_copy.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/ic_copy.imageset/Contents.json rename to Session/Meta/Images.xcassets/ic_copy.imageset/Contents.json diff --git a/Session/Images.xcassets/ic_copy.imageset/Copy-24@1x.png b/Session/Meta/Images.xcassets/ic_copy.imageset/Copy-24@1x.png similarity index 100% rename from Session/Images.xcassets/ic_copy.imageset/Copy-24@1x.png rename to Session/Meta/Images.xcassets/ic_copy.imageset/Copy-24@1x.png diff --git a/Session/Images.xcassets/ic_copy.imageset/Copy-24@2x.png b/Session/Meta/Images.xcassets/ic_copy.imageset/Copy-24@2x.png similarity index 100% rename from Session/Images.xcassets/ic_copy.imageset/Copy-24@2x.png rename to Session/Meta/Images.xcassets/ic_copy.imageset/Copy-24@2x.png diff --git a/Session/Images.xcassets/ic_copy.imageset/Copy-24@3x.png b/Session/Meta/Images.xcassets/ic_copy.imageset/Copy-24@3x.png similarity index 100% rename from Session/Images.xcassets/ic_copy.imageset/Copy-24@3x.png rename to Session/Meta/Images.xcassets/ic_copy.imageset/Copy-24@3x.png diff --git a/Session/Images.xcassets/ic_dark_theme_off.imageset/Contents.json b/Session/Meta/Images.xcassets/ic_dark_theme_off.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/ic_dark_theme_off.imageset/Contents.json rename to Session/Meta/Images.xcassets/ic_dark_theme_off.imageset/Contents.json diff --git a/Session/Images.xcassets/ic_dark_theme_off.imageset/dark-theme-off-24@1x.png b/Session/Meta/Images.xcassets/ic_dark_theme_off.imageset/dark-theme-off-24@1x.png similarity index 100% rename from Session/Images.xcassets/ic_dark_theme_off.imageset/dark-theme-off-24@1x.png rename to Session/Meta/Images.xcassets/ic_dark_theme_off.imageset/dark-theme-off-24@1x.png diff --git a/Session/Images.xcassets/ic_dark_theme_off.imageset/dark-theme-off-24@2x.png b/Session/Meta/Images.xcassets/ic_dark_theme_off.imageset/dark-theme-off-24@2x.png similarity index 100% rename from Session/Images.xcassets/ic_dark_theme_off.imageset/dark-theme-off-24@2x.png rename to Session/Meta/Images.xcassets/ic_dark_theme_off.imageset/dark-theme-off-24@2x.png diff --git a/Session/Images.xcassets/ic_dark_theme_off.imageset/dark-theme-off-24@3x.png b/Session/Meta/Images.xcassets/ic_dark_theme_off.imageset/dark-theme-off-24@3x.png similarity index 100% rename from Session/Images.xcassets/ic_dark_theme_off.imageset/dark-theme-off-24@3x.png rename to Session/Meta/Images.xcassets/ic_dark_theme_off.imageset/dark-theme-off-24@3x.png diff --git a/Session/Images.xcassets/ic_dark_theme_on.imageset/Contents.json b/Session/Meta/Images.xcassets/ic_dark_theme_on.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/ic_dark_theme_on.imageset/Contents.json rename to Session/Meta/Images.xcassets/ic_dark_theme_on.imageset/Contents.json diff --git a/Session/Images.xcassets/ic_dark_theme_on.imageset/dark-theme-on-24@1x.png b/Session/Meta/Images.xcassets/ic_dark_theme_on.imageset/dark-theme-on-24@1x.png similarity index 100% rename from Session/Images.xcassets/ic_dark_theme_on.imageset/dark-theme-on-24@1x.png rename to Session/Meta/Images.xcassets/ic_dark_theme_on.imageset/dark-theme-on-24@1x.png diff --git a/Session/Images.xcassets/ic_dark_theme_on.imageset/dark-theme-on-24@2x.png b/Session/Meta/Images.xcassets/ic_dark_theme_on.imageset/dark-theme-on-24@2x.png similarity index 100% rename from Session/Images.xcassets/ic_dark_theme_on.imageset/dark-theme-on-24@2x.png rename to Session/Meta/Images.xcassets/ic_dark_theme_on.imageset/dark-theme-on-24@2x.png diff --git a/Session/Images.xcassets/ic_dark_theme_on.imageset/dark-theme-on-24@3x.png b/Session/Meta/Images.xcassets/ic_dark_theme_on.imageset/dark-theme-on-24@3x.png similarity index 100% rename from Session/Images.xcassets/ic_dark_theme_on.imageset/dark-theme-on-24@3x.png rename to Session/Meta/Images.xcassets/ic_dark_theme_on.imageset/dark-theme-on-24@3x.png diff --git a/Session/Images.xcassets/ic_devices_ios.imageset/Contents.json b/Session/Meta/Images.xcassets/ic_devices_ios.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/ic_devices_ios.imageset/Contents.json rename to Session/Meta/Images.xcassets/ic_devices_ios.imageset/Contents.json diff --git a/Session/Images.xcassets/ic_devices_ios.imageset/ic_devices_ios.png b/Session/Meta/Images.xcassets/ic_devices_ios.imageset/ic_devices_ios.png similarity index 100% rename from Session/Images.xcassets/ic_devices_ios.imageset/ic_devices_ios.png rename to Session/Meta/Images.xcassets/ic_devices_ios.imageset/ic_devices_ios.png diff --git a/Session/Images.xcassets/ic_devices_ios.imageset/ic_devices_ios@2x.png b/Session/Meta/Images.xcassets/ic_devices_ios.imageset/ic_devices_ios@2x.png similarity index 100% rename from Session/Images.xcassets/ic_devices_ios.imageset/ic_devices_ios@2x.png rename to Session/Meta/Images.xcassets/ic_devices_ios.imageset/ic_devices_ios@2x.png diff --git a/Session/Images.xcassets/ic_devices_ios.imageset/ic_devices_ios@3x.png b/Session/Meta/Images.xcassets/ic_devices_ios.imageset/ic_devices_ios@3x.png similarity index 100% rename from Session/Images.xcassets/ic_devices_ios.imageset/ic_devices_ios@3x.png rename to Session/Meta/Images.xcassets/ic_devices_ios.imageset/ic_devices_ios@3x.png diff --git a/Session/Images.xcassets/ic_download.imageset/Contents.json b/Session/Meta/Images.xcassets/ic_download.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/ic_download.imageset/Contents.json rename to Session/Meta/Images.xcassets/ic_download.imageset/Contents.json diff --git a/Session/Images.xcassets/ic_download.imageset/download-24@1x.png b/Session/Meta/Images.xcassets/ic_download.imageset/download-24@1x.png similarity index 100% rename from Session/Images.xcassets/ic_download.imageset/download-24@1x.png rename to Session/Meta/Images.xcassets/ic_download.imageset/download-24@1x.png diff --git a/Session/Images.xcassets/ic_download.imageset/download-24@2x.png b/Session/Meta/Images.xcassets/ic_download.imageset/download-24@2x.png similarity index 100% rename from Session/Images.xcassets/ic_download.imageset/download-24@2x.png rename to Session/Meta/Images.xcassets/ic_download.imageset/download-24@2x.png diff --git a/Session/Images.xcassets/ic_download.imageset/download-24@3x.png b/Session/Meta/Images.xcassets/ic_download.imageset/download-24@3x.png similarity index 100% rename from Session/Images.xcassets/ic_download.imageset/download-24@3x.png rename to Session/Meta/Images.xcassets/ic_download.imageset/download-24@3x.png diff --git a/Session/Images.xcassets/ic_flash_mode_auto.imageset/Contents.json b/Session/Meta/Images.xcassets/ic_flash_mode_auto.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/ic_flash_mode_auto.imageset/Contents.json rename to Session/Meta/Images.xcassets/ic_flash_mode_auto.imageset/Contents.json diff --git a/Session/Images.xcassets/ic_flash_mode_auto.imageset/flash-auto-32@1x.png b/Session/Meta/Images.xcassets/ic_flash_mode_auto.imageset/flash-auto-32@1x.png similarity index 100% rename from Session/Images.xcassets/ic_flash_mode_auto.imageset/flash-auto-32@1x.png rename to Session/Meta/Images.xcassets/ic_flash_mode_auto.imageset/flash-auto-32@1x.png diff --git a/Session/Images.xcassets/ic_flash_mode_auto.imageset/flash-auto-32@2x.png b/Session/Meta/Images.xcassets/ic_flash_mode_auto.imageset/flash-auto-32@2x.png similarity index 100% rename from Session/Images.xcassets/ic_flash_mode_auto.imageset/flash-auto-32@2x.png rename to Session/Meta/Images.xcassets/ic_flash_mode_auto.imageset/flash-auto-32@2x.png diff --git a/Session/Images.xcassets/ic_flash_mode_auto.imageset/flash-auto-32@3x.png b/Session/Meta/Images.xcassets/ic_flash_mode_auto.imageset/flash-auto-32@3x.png similarity index 100% rename from Session/Images.xcassets/ic_flash_mode_auto.imageset/flash-auto-32@3x.png rename to Session/Meta/Images.xcassets/ic_flash_mode_auto.imageset/flash-auto-32@3x.png diff --git a/Session/Images.xcassets/ic_flash_mode_off.imageset/Contents.json b/Session/Meta/Images.xcassets/ic_flash_mode_off.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/ic_flash_mode_off.imageset/Contents.json rename to Session/Meta/Images.xcassets/ic_flash_mode_off.imageset/Contents.json diff --git a/Session/Images.xcassets/ic_flash_mode_off.imageset/flash-off-32@1x.png b/Session/Meta/Images.xcassets/ic_flash_mode_off.imageset/flash-off-32@1x.png similarity index 100% rename from Session/Images.xcassets/ic_flash_mode_off.imageset/flash-off-32@1x.png rename to Session/Meta/Images.xcassets/ic_flash_mode_off.imageset/flash-off-32@1x.png diff --git a/Session/Images.xcassets/ic_flash_mode_off.imageset/flash-off-32@2x.png b/Session/Meta/Images.xcassets/ic_flash_mode_off.imageset/flash-off-32@2x.png similarity index 100% rename from Session/Images.xcassets/ic_flash_mode_off.imageset/flash-off-32@2x.png rename to Session/Meta/Images.xcassets/ic_flash_mode_off.imageset/flash-off-32@2x.png diff --git a/Session/Images.xcassets/ic_flash_mode_off.imageset/flash-off-32@3x.png b/Session/Meta/Images.xcassets/ic_flash_mode_off.imageset/flash-off-32@3x.png similarity index 100% rename from Session/Images.xcassets/ic_flash_mode_off.imageset/flash-off-32@3x.png rename to Session/Meta/Images.xcassets/ic_flash_mode_off.imageset/flash-off-32@3x.png diff --git a/Session/Images.xcassets/ic_flash_mode_on.imageset/Contents.json b/Session/Meta/Images.xcassets/ic_flash_mode_on.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/ic_flash_mode_on.imageset/Contents.json rename to Session/Meta/Images.xcassets/ic_flash_mode_on.imageset/Contents.json diff --git a/Session/Images.xcassets/ic_flash_mode_on.imageset/flash-on-32@1x.png b/Session/Meta/Images.xcassets/ic_flash_mode_on.imageset/flash-on-32@1x.png similarity index 100% rename from Session/Images.xcassets/ic_flash_mode_on.imageset/flash-on-32@1x.png rename to Session/Meta/Images.xcassets/ic_flash_mode_on.imageset/flash-on-32@1x.png diff --git a/Session/Images.xcassets/ic_flash_mode_on.imageset/flash-on-32@2x.png b/Session/Meta/Images.xcassets/ic_flash_mode_on.imageset/flash-on-32@2x.png similarity index 100% rename from Session/Images.xcassets/ic_flash_mode_on.imageset/flash-on-32@2x.png rename to Session/Meta/Images.xcassets/ic_flash_mode_on.imageset/flash-on-32@2x.png diff --git a/Session/Images.xcassets/ic_flash_mode_on.imageset/flash-on-32@3x.png b/Session/Meta/Images.xcassets/ic_flash_mode_on.imageset/flash-on-32@3x.png similarity index 100% rename from Session/Images.xcassets/ic_flash_mode_on.imageset/flash-on-32@3x.png rename to Session/Meta/Images.xcassets/ic_flash_mode_on.imageset/flash-on-32@3x.png diff --git a/Session/Images.xcassets/ic_gallery_badge_gif.imageset/Contents.json b/Session/Meta/Images.xcassets/ic_gallery_badge_gif.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/ic_gallery_badge_gif.imageset/Contents.json rename to Session/Meta/Images.xcassets/ic_gallery_badge_gif.imageset/Contents.json diff --git a/Session/Images.xcassets/ic_gallery_badge_gif.imageset/icon_GIF@1x.png b/Session/Meta/Images.xcassets/ic_gallery_badge_gif.imageset/icon_GIF@1x.png similarity index 100% rename from Session/Images.xcassets/ic_gallery_badge_gif.imageset/icon_GIF@1x.png rename to Session/Meta/Images.xcassets/ic_gallery_badge_gif.imageset/icon_GIF@1x.png diff --git a/Session/Images.xcassets/ic_gallery_badge_gif.imageset/icon_GIF@2x.png b/Session/Meta/Images.xcassets/ic_gallery_badge_gif.imageset/icon_GIF@2x.png similarity index 100% rename from Session/Images.xcassets/ic_gallery_badge_gif.imageset/icon_GIF@2x.png rename to Session/Meta/Images.xcassets/ic_gallery_badge_gif.imageset/icon_GIF@2x.png diff --git a/Session/Images.xcassets/ic_gallery_badge_gif.imageset/icon_GIF@3x.png b/Session/Meta/Images.xcassets/ic_gallery_badge_gif.imageset/icon_GIF@3x.png similarity index 100% rename from Session/Images.xcassets/ic_gallery_badge_gif.imageset/icon_GIF@3x.png rename to Session/Meta/Images.xcassets/ic_gallery_badge_gif.imageset/icon_GIF@3x.png diff --git a/Session/Images.xcassets/ic_gallery_badge_video.imageset/Contents.json b/Session/Meta/Images.xcassets/ic_gallery_badge_video.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/ic_gallery_badge_video.imageset/Contents.json rename to Session/Meta/Images.xcassets/ic_gallery_badge_video.imageset/Contents.json diff --git a/Session/Images.xcassets/ic_gallery_badge_video.imageset/icon_video@1x.png b/Session/Meta/Images.xcassets/ic_gallery_badge_video.imageset/icon_video@1x.png similarity index 100% rename from Session/Images.xcassets/ic_gallery_badge_video.imageset/icon_video@1x.png rename to Session/Meta/Images.xcassets/ic_gallery_badge_video.imageset/icon_video@1x.png diff --git a/Session/Images.xcassets/ic_gallery_badge_video.imageset/icon_video@2x.png b/Session/Meta/Images.xcassets/ic_gallery_badge_video.imageset/icon_video@2x.png similarity index 100% rename from Session/Images.xcassets/ic_gallery_badge_video.imageset/icon_video@2x.png rename to Session/Meta/Images.xcassets/ic_gallery_badge_video.imageset/icon_video@2x.png diff --git a/Session/Images.xcassets/ic_gallery_badge_video.imageset/icon_video@3x.png b/Session/Meta/Images.xcassets/ic_gallery_badge_video.imageset/icon_video@3x.png similarity index 100% rename from Session/Images.xcassets/ic_gallery_badge_video.imageset/icon_video@3x.png rename to Session/Meta/Images.xcassets/ic_gallery_badge_video.imageset/icon_video@3x.png diff --git a/Session/Images.xcassets/ic_info.imageset/Contents.json b/Session/Meta/Images.xcassets/ic_info.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/ic_info.imageset/Contents.json rename to Session/Meta/Images.xcassets/ic_info.imageset/Contents.json diff --git a/Session/Images.xcassets/ic_info.imageset/info-24@1x.png b/Session/Meta/Images.xcassets/ic_info.imageset/info-24@1x.png similarity index 100% rename from Session/Images.xcassets/ic_info.imageset/info-24@1x.png rename to Session/Meta/Images.xcassets/ic_info.imageset/info-24@1x.png diff --git a/Session/Images.xcassets/ic_info.imageset/info-24@2x.png b/Session/Meta/Images.xcassets/ic_info.imageset/info-24@2x.png similarity index 100% rename from Session/Images.xcassets/ic_info.imageset/info-24@2x.png rename to Session/Meta/Images.xcassets/ic_info.imageset/info-24@2x.png diff --git a/Session/Images.xcassets/ic_info.imageset/info-24@3x.png b/Session/Meta/Images.xcassets/ic_info.imageset/info-24@3x.png similarity index 100% rename from Session/Images.xcassets/ic_info.imageset/info-24@3x.png rename to Session/Meta/Images.xcassets/ic_info.imageset/info-24@3x.png diff --git a/Session/Images.xcassets/ic_lock_outline.imageset/Contents.json b/Session/Meta/Images.xcassets/ic_lock_outline.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/ic_lock_outline.imageset/Contents.json rename to Session/Meta/Images.xcassets/ic_lock_outline.imageset/Contents.json diff --git a/Session/Images.xcassets/ic_lock_outline.imageset/ic_lock_outline_white.png b/Session/Meta/Images.xcassets/ic_lock_outline.imageset/ic_lock_outline_white.png similarity index 100% rename from Session/Images.xcassets/ic_lock_outline.imageset/ic_lock_outline_white.png rename to Session/Meta/Images.xcassets/ic_lock_outline.imageset/ic_lock_outline_white.png diff --git a/Session/Images.xcassets/ic_lock_outline.imageset/ic_lock_outline_white@2x.png b/Session/Meta/Images.xcassets/ic_lock_outline.imageset/ic_lock_outline_white@2x.png similarity index 100% rename from Session/Images.xcassets/ic_lock_outline.imageset/ic_lock_outline_white@2x.png rename to Session/Meta/Images.xcassets/ic_lock_outline.imageset/ic_lock_outline_white@2x.png diff --git a/Session/Images.xcassets/ic_lock_outline.imageset/ic_lock_outline_white@3x.png b/Session/Meta/Images.xcassets/ic_lock_outline.imageset/ic_lock_outline_white@3x.png similarity index 100% rename from Session/Images.xcassets/ic_lock_outline.imageset/ic_lock_outline_white@3x.png rename to Session/Meta/Images.xcassets/ic_lock_outline.imageset/ic_lock_outline_white@3x.png diff --git a/Session/Images.xcassets/ic_mute_thread.imageset/Contents.json b/Session/Meta/Images.xcassets/ic_mute_thread.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/ic_mute_thread.imageset/Contents.json rename to Session/Meta/Images.xcassets/ic_mute_thread.imageset/Contents.json diff --git a/Session/Images.xcassets/ic_mute_thread.imageset/ic_mute_thread@1x.png b/Session/Meta/Images.xcassets/ic_mute_thread.imageset/ic_mute_thread@1x.png similarity index 100% rename from Session/Images.xcassets/ic_mute_thread.imageset/ic_mute_thread@1x.png rename to Session/Meta/Images.xcassets/ic_mute_thread.imageset/ic_mute_thread@1x.png diff --git a/Session/Images.xcassets/ic_mute_thread.imageset/ic_mute_thread@2x.png b/Session/Meta/Images.xcassets/ic_mute_thread.imageset/ic_mute_thread@2x.png similarity index 100% rename from Session/Images.xcassets/ic_mute_thread.imageset/ic_mute_thread@2x.png rename to Session/Meta/Images.xcassets/ic_mute_thread.imageset/ic_mute_thread@2x.png diff --git a/Session/Images.xcassets/ic_mute_thread.imageset/ic_mute_thread@3x.png b/Session/Meta/Images.xcassets/ic_mute_thread.imageset/ic_mute_thread@3x.png similarity index 100% rename from Session/Images.xcassets/ic_mute_thread.imageset/ic_mute_thread@3x.png rename to Session/Meta/Images.xcassets/ic_mute_thread.imageset/ic_mute_thread@3x.png diff --git a/Session/Images.xcassets/ic_plus_24.imageset/Contents.json b/Session/Meta/Images.xcassets/ic_plus_24.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/ic_plus_24.imageset/Contents.json rename to Session/Meta/Images.xcassets/ic_plus_24.imageset/Contents.json diff --git a/Session/Images.xcassets/ic_plus_24.imageset/plus-24@1x.png b/Session/Meta/Images.xcassets/ic_plus_24.imageset/plus-24@1x.png similarity index 100% rename from Session/Images.xcassets/ic_plus_24.imageset/plus-24@1x.png rename to Session/Meta/Images.xcassets/ic_plus_24.imageset/plus-24@1x.png diff --git a/Session/Images.xcassets/ic_plus_24.imageset/plus-24@2x.png b/Session/Meta/Images.xcassets/ic_plus_24.imageset/plus-24@2x.png similarity index 100% rename from Session/Images.xcassets/ic_plus_24.imageset/plus-24@2x.png rename to Session/Meta/Images.xcassets/ic_plus_24.imageset/plus-24@2x.png diff --git a/Session/Images.xcassets/ic_plus_24.imageset/plus-24@3x.png b/Session/Meta/Images.xcassets/ic_plus_24.imageset/plus-24@3x.png similarity index 100% rename from Session/Images.xcassets/ic_plus_24.imageset/plus-24@3x.png rename to Session/Meta/Images.xcassets/ic_plus_24.imageset/plus-24@3x.png diff --git a/Session/Images.xcassets/ic_reply.imageset/Contents.json b/Session/Meta/Images.xcassets/ic_reply.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/ic_reply.imageset/Contents.json rename to Session/Meta/Images.xcassets/ic_reply.imageset/Contents.json diff --git a/Session/Images.xcassets/ic_reply.imageset/reply-24@1x.png b/Session/Meta/Images.xcassets/ic_reply.imageset/reply-24@1x.png similarity index 100% rename from Session/Images.xcassets/ic_reply.imageset/reply-24@1x.png rename to Session/Meta/Images.xcassets/ic_reply.imageset/reply-24@1x.png diff --git a/Session/Images.xcassets/ic_reply.imageset/reply-24@2x.png b/Session/Meta/Images.xcassets/ic_reply.imageset/reply-24@2x.png similarity index 100% rename from Session/Images.xcassets/ic_reply.imageset/reply-24@2x.png rename to Session/Meta/Images.xcassets/ic_reply.imageset/reply-24@2x.png diff --git a/Session/Images.xcassets/ic_reply.imageset/reply-24@3x.png b/Session/Meta/Images.xcassets/ic_reply.imageset/reply-24@3x.png similarity index 100% rename from Session/Images.xcassets/ic_reply.imageset/reply-24@3x.png rename to Session/Meta/Images.xcassets/ic_reply.imageset/reply-24@3x.png diff --git a/Session/Images.xcassets/ic_secret_sender_indicator.imageset/Contents.json b/Session/Meta/Images.xcassets/ic_secret_sender_indicator.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/ic_secret_sender_indicator.imageset/Contents.json rename to Session/Meta/Images.xcassets/ic_secret_sender_indicator.imageset/Contents.json diff --git a/Session/Images.xcassets/ic_secret_sender_indicator.imageset/secret-sender-20@1x.png b/Session/Meta/Images.xcassets/ic_secret_sender_indicator.imageset/secret-sender-20@1x.png similarity index 100% rename from Session/Images.xcassets/ic_secret_sender_indicator.imageset/secret-sender-20@1x.png rename to Session/Meta/Images.xcassets/ic_secret_sender_indicator.imageset/secret-sender-20@1x.png diff --git a/Session/Images.xcassets/ic_secret_sender_indicator.imageset/secret-sender-20@2x.png b/Session/Meta/Images.xcassets/ic_secret_sender_indicator.imageset/secret-sender-20@2x.png similarity index 100% rename from Session/Images.xcassets/ic_secret_sender_indicator.imageset/secret-sender-20@2x.png rename to Session/Meta/Images.xcassets/ic_secret_sender_indicator.imageset/secret-sender-20@2x.png diff --git a/Session/Images.xcassets/ic_secret_sender_indicator.imageset/secret-sender-20@3x.png b/Session/Meta/Images.xcassets/ic_secret_sender_indicator.imageset/secret-sender-20@3x.png similarity index 100% rename from Session/Images.xcassets/ic_secret_sender_indicator.imageset/secret-sender-20@3x.png rename to Session/Meta/Images.xcassets/ic_secret_sender_indicator.imageset/secret-sender-20@3x.png diff --git a/Session/Images.xcassets/ic_speaker_bluetooth_inactive_audio_mode.imageset/Contents.json b/Session/Meta/Images.xcassets/ic_speaker_bluetooth_inactive_audio_mode.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/ic_speaker_bluetooth_inactive_audio_mode.imageset/Contents.json rename to Session/Meta/Images.xcassets/ic_speaker_bluetooth_inactive_audio_mode.imageset/Contents.json diff --git a/Session/Images.xcassets/ic_speaker_bluetooth_inactive_audio_mode.imageset/ic_speaker_bluetooth_inactive_audio_mode.png b/Session/Meta/Images.xcassets/ic_speaker_bluetooth_inactive_audio_mode.imageset/ic_speaker_bluetooth_inactive_audio_mode.png similarity index 100% rename from Session/Images.xcassets/ic_speaker_bluetooth_inactive_audio_mode.imageset/ic_speaker_bluetooth_inactive_audio_mode.png rename to Session/Meta/Images.xcassets/ic_speaker_bluetooth_inactive_audio_mode.imageset/ic_speaker_bluetooth_inactive_audio_mode.png diff --git a/Session/Images.xcassets/ic_speaker_bluetooth_inactive_video_mode.imageset/Contents.json b/Session/Meta/Images.xcassets/ic_speaker_bluetooth_inactive_video_mode.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/ic_speaker_bluetooth_inactive_video_mode.imageset/Contents.json rename to Session/Meta/Images.xcassets/ic_speaker_bluetooth_inactive_video_mode.imageset/Contents.json diff --git a/Session/Images.xcassets/ic_speaker_bluetooth_inactive_video_mode.imageset/ic_speaker_bluetooth_inactive_video_mode.png b/Session/Meta/Images.xcassets/ic_speaker_bluetooth_inactive_video_mode.imageset/ic_speaker_bluetooth_inactive_video_mode.png similarity index 100% rename from Session/Images.xcassets/ic_speaker_bluetooth_inactive_video_mode.imageset/ic_speaker_bluetooth_inactive_video_mode.png rename to Session/Meta/Images.xcassets/ic_speaker_bluetooth_inactive_video_mode.imageset/ic_speaker_bluetooth_inactive_video_mode.png diff --git a/Session/Images.xcassets/ic_switch_camera.imageset/Contents.json b/Session/Meta/Images.xcassets/ic_switch_camera.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/ic_switch_camera.imageset/Contents.json rename to Session/Meta/Images.xcassets/ic_switch_camera.imageset/Contents.json diff --git a/Session/Images.xcassets/ic_switch_camera.imageset/switch-camera-32@1x.png b/Session/Meta/Images.xcassets/ic_switch_camera.imageset/switch-camera-32@1x.png similarity index 100% rename from Session/Images.xcassets/ic_switch_camera.imageset/switch-camera-32@1x.png rename to Session/Meta/Images.xcassets/ic_switch_camera.imageset/switch-camera-32@1x.png diff --git a/Session/Images.xcassets/ic_switch_camera.imageset/switch-camera-32@2x.png b/Session/Meta/Images.xcassets/ic_switch_camera.imageset/switch-camera-32@2x.png similarity index 100% rename from Session/Images.xcassets/ic_switch_camera.imageset/switch-camera-32@2x.png rename to Session/Meta/Images.xcassets/ic_switch_camera.imageset/switch-camera-32@2x.png diff --git a/Session/Images.xcassets/ic_switch_camera.imageset/switch-camera-32@3x.png b/Session/Meta/Images.xcassets/ic_switch_camera.imageset/switch-camera-32@3x.png similarity index 100% rename from Session/Images.xcassets/ic_switch_camera.imageset/switch-camera-32@3x.png rename to Session/Meta/Images.xcassets/ic_switch_camera.imageset/switch-camera-32@3x.png diff --git a/Session/Images.xcassets/ic_timer.imageset/Contents.json b/Session/Meta/Images.xcassets/ic_timer.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/ic_timer.imageset/Contents.json rename to Session/Meta/Images.xcassets/ic_timer.imageset/Contents.json diff --git a/Session/Images.xcassets/ic_timer.imageset/timer-24@1x.png b/Session/Meta/Images.xcassets/ic_timer.imageset/timer-24@1x.png similarity index 100% rename from Session/Images.xcassets/ic_timer.imageset/timer-24@1x.png rename to Session/Meta/Images.xcassets/ic_timer.imageset/timer-24@1x.png diff --git a/Session/Images.xcassets/ic_timer.imageset/timer-24@2x.png b/Session/Meta/Images.xcassets/ic_timer.imageset/timer-24@2x.png similarity index 100% rename from Session/Images.xcassets/ic_timer.imageset/timer-24@2x.png rename to Session/Meta/Images.xcassets/ic_timer.imageset/timer-24@2x.png diff --git a/Session/Images.xcassets/ic_timer.imageset/timer-24@3x.png b/Session/Meta/Images.xcassets/ic_timer.imageset/timer-24@3x.png similarity index 100% rename from Session/Images.xcassets/ic_timer.imageset/timer-24@3x.png rename to Session/Meta/Images.xcassets/ic_timer.imageset/timer-24@3x.png diff --git a/Session/Images.xcassets/ic_timer_disabled.imageset/Contents.json b/Session/Meta/Images.xcassets/ic_timer_disabled.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/ic_timer_disabled.imageset/Contents.json rename to Session/Meta/Images.xcassets/ic_timer_disabled.imageset/Contents.json diff --git a/Session/Images.xcassets/ic_timer_disabled.imageset/timer-disabled-24@1x.png b/Session/Meta/Images.xcassets/ic_timer_disabled.imageset/timer-disabled-24@1x.png similarity index 100% rename from Session/Images.xcassets/ic_timer_disabled.imageset/timer-disabled-24@1x.png rename to Session/Meta/Images.xcassets/ic_timer_disabled.imageset/timer-disabled-24@1x.png diff --git a/Session/Images.xcassets/ic_timer_disabled.imageset/timer-disabled-24@2x.png b/Session/Meta/Images.xcassets/ic_timer_disabled.imageset/timer-disabled-24@2x.png similarity index 100% rename from Session/Images.xcassets/ic_timer_disabled.imageset/timer-disabled-24@2x.png rename to Session/Meta/Images.xcassets/ic_timer_disabled.imageset/timer-disabled-24@2x.png diff --git a/Session/Images.xcassets/ic_timer_disabled.imageset/timer-disabled-24@3x.png b/Session/Meta/Images.xcassets/ic_timer_disabled.imageset/timer-disabled-24@3x.png similarity index 100% rename from Session/Images.xcassets/ic_timer_disabled.imageset/timer-disabled-24@3x.png rename to Session/Meta/Images.xcassets/ic_timer_disabled.imageset/timer-disabled-24@3x.png diff --git a/Session/Images.xcassets/ic_trash.imageset/Contents.json b/Session/Meta/Images.xcassets/ic_trash.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/ic_trash.imageset/Contents.json rename to Session/Meta/Images.xcassets/ic_trash.imageset/Contents.json diff --git a/Session/Images.xcassets/ic_trash.imageset/trash-24@1x.png b/Session/Meta/Images.xcassets/ic_trash.imageset/trash-24@1x.png similarity index 100% rename from Session/Images.xcassets/ic_trash.imageset/trash-24@1x.png rename to Session/Meta/Images.xcassets/ic_trash.imageset/trash-24@1x.png diff --git a/Session/Images.xcassets/ic_trash.imageset/trash-24@2x.png b/Session/Meta/Images.xcassets/ic_trash.imageset/trash-24@2x.png similarity index 100% rename from Session/Images.xcassets/ic_trash.imageset/trash-24@2x.png rename to Session/Meta/Images.xcassets/ic_trash.imageset/trash-24@2x.png diff --git a/Session/Images.xcassets/ic_trash.imageset/trash-24@3x.png b/Session/Meta/Images.xcassets/ic_trash.imageset/trash-24@3x.png similarity index 100% rename from Session/Images.xcassets/ic_trash.imageset/trash-24@3x.png rename to Session/Meta/Images.xcassets/ic_trash.imageset/trash-24@3x.png diff --git a/Session/Images.xcassets/ic_x_with_shadow.imageset/Contents.json b/Session/Meta/Images.xcassets/ic_x_with_shadow.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/ic_x_with_shadow.imageset/Contents.json rename to Session/Meta/Images.xcassets/ic_x_with_shadow.imageset/Contents.json diff --git a/Session/Images.xcassets/ic_x_with_shadow.imageset/x-24@1x.png b/Session/Meta/Images.xcassets/ic_x_with_shadow.imageset/x-24@1x.png similarity index 100% rename from Session/Images.xcassets/ic_x_with_shadow.imageset/x-24@1x.png rename to Session/Meta/Images.xcassets/ic_x_with_shadow.imageset/x-24@1x.png diff --git a/Session/Images.xcassets/ic_x_with_shadow.imageset/x-24@2x.png b/Session/Meta/Images.xcassets/ic_x_with_shadow.imageset/x-24@2x.png similarity index 100% rename from Session/Images.xcassets/ic_x_with_shadow.imageset/x-24@2x.png rename to Session/Meta/Images.xcassets/ic_x_with_shadow.imageset/x-24@2x.png diff --git a/Session/Images.xcassets/ic_x_with_shadow.imageset/x-24@3x.png b/Session/Meta/Images.xcassets/ic_x_with_shadow.imageset/x-24@3x.png similarity index 100% rename from Session/Images.xcassets/ic_x_with_shadow.imageset/x-24@3x.png rename to Session/Meta/Images.xcassets/ic_x_with_shadow.imageset/x-24@3x.png diff --git a/Session/Images.xcassets/image_editor_brush.imageset/Contents.json b/Session/Meta/Images.xcassets/image_editor_brush.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/image_editor_brush.imageset/Contents.json rename to Session/Meta/Images.xcassets/image_editor_brush.imageset/Contents.json diff --git a/Session/Images.xcassets/image_editor_brush.imageset/marker-32@1x.png b/Session/Meta/Images.xcassets/image_editor_brush.imageset/marker-32@1x.png similarity index 100% rename from Session/Images.xcassets/image_editor_brush.imageset/marker-32@1x.png rename to Session/Meta/Images.xcassets/image_editor_brush.imageset/marker-32@1x.png diff --git a/Session/Images.xcassets/image_editor_brush.imageset/marker-32@2x.png b/Session/Meta/Images.xcassets/image_editor_brush.imageset/marker-32@2x.png similarity index 100% rename from Session/Images.xcassets/image_editor_brush.imageset/marker-32@2x.png rename to Session/Meta/Images.xcassets/image_editor_brush.imageset/marker-32@2x.png diff --git a/Session/Images.xcassets/image_editor_brush.imageset/marker-32@3x.png b/Session/Meta/Images.xcassets/image_editor_brush.imageset/marker-32@3x.png similarity index 100% rename from Session/Images.xcassets/image_editor_brush.imageset/marker-32@3x.png rename to Session/Meta/Images.xcassets/image_editor_brush.imageset/marker-32@3x.png diff --git a/Session/Images.xcassets/image_editor_caption.imageset/Contents.json b/Session/Meta/Images.xcassets/image_editor_caption.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/image_editor_caption.imageset/Contents.json rename to Session/Meta/Images.xcassets/image_editor_caption.imageset/Contents.json diff --git a/Session/Images.xcassets/image_editor_caption.imageset/caption-24@1x.png b/Session/Meta/Images.xcassets/image_editor_caption.imageset/caption-24@1x.png similarity index 100% rename from Session/Images.xcassets/image_editor_caption.imageset/caption-24@1x.png rename to Session/Meta/Images.xcassets/image_editor_caption.imageset/caption-24@1x.png diff --git a/Session/Images.xcassets/image_editor_caption.imageset/caption-24@2x.png b/Session/Meta/Images.xcassets/image_editor_caption.imageset/caption-24@2x.png similarity index 100% rename from Session/Images.xcassets/image_editor_caption.imageset/caption-24@2x.png rename to Session/Meta/Images.xcassets/image_editor_caption.imageset/caption-24@2x.png diff --git a/Session/Images.xcassets/image_editor_caption.imageset/caption-24@3x.png b/Session/Meta/Images.xcassets/image_editor_caption.imageset/caption-24@3x.png similarity index 100% rename from Session/Images.xcassets/image_editor_caption.imageset/caption-24@3x.png rename to Session/Meta/Images.xcassets/image_editor_caption.imageset/caption-24@3x.png diff --git a/Session/Images.xcassets/image_editor_checkmark_empty.imageset/Contents.json b/Session/Meta/Images.xcassets/image_editor_checkmark_empty.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/image_editor_checkmark_empty.imageset/Contents.json rename to Session/Meta/Images.xcassets/image_editor_checkmark_empty.imageset/Contents.json diff --git a/Session/Images.xcassets/image_editor_checkmark_empty.imageset/checkmark-circle-outline-32@1x.png b/Session/Meta/Images.xcassets/image_editor_checkmark_empty.imageset/checkmark-circle-outline-32@1x.png similarity index 100% rename from Session/Images.xcassets/image_editor_checkmark_empty.imageset/checkmark-circle-outline-32@1x.png rename to Session/Meta/Images.xcassets/image_editor_checkmark_empty.imageset/checkmark-circle-outline-32@1x.png diff --git a/Session/Images.xcassets/image_editor_checkmark_empty.imageset/checkmark-circle-outline-32@2x.png b/Session/Meta/Images.xcassets/image_editor_checkmark_empty.imageset/checkmark-circle-outline-32@2x.png similarity index 100% rename from Session/Images.xcassets/image_editor_checkmark_empty.imageset/checkmark-circle-outline-32@2x.png rename to Session/Meta/Images.xcassets/image_editor_checkmark_empty.imageset/checkmark-circle-outline-32@2x.png diff --git a/Session/Images.xcassets/image_editor_checkmark_empty.imageset/checkmark-circle-outline-32@3x.png b/Session/Meta/Images.xcassets/image_editor_checkmark_empty.imageset/checkmark-circle-outline-32@3x.png similarity index 100% rename from Session/Images.xcassets/image_editor_checkmark_empty.imageset/checkmark-circle-outline-32@3x.png rename to Session/Meta/Images.xcassets/image_editor_checkmark_empty.imageset/checkmark-circle-outline-32@3x.png diff --git a/Session/Images.xcassets/image_editor_checkmark_full.imageset/Contents.json b/Session/Meta/Images.xcassets/image_editor_checkmark_full.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/image_editor_checkmark_full.imageset/Contents.json rename to Session/Meta/Images.xcassets/image_editor_checkmark_full.imageset/Contents.json diff --git a/Session/Images.xcassets/image_editor_checkmark_full.imageset/checkmark-circle-filled-32@1x.png b/Session/Meta/Images.xcassets/image_editor_checkmark_full.imageset/checkmark-circle-filled-32@1x.png similarity index 100% rename from Session/Images.xcassets/image_editor_checkmark_full.imageset/checkmark-circle-filled-32@1x.png rename to Session/Meta/Images.xcassets/image_editor_checkmark_full.imageset/checkmark-circle-filled-32@1x.png diff --git a/Session/Images.xcassets/image_editor_checkmark_full.imageset/checkmark-circle-filled-32@2x.png b/Session/Meta/Images.xcassets/image_editor_checkmark_full.imageset/checkmark-circle-filled-32@2x.png similarity index 100% rename from Session/Images.xcassets/image_editor_checkmark_full.imageset/checkmark-circle-filled-32@2x.png rename to Session/Meta/Images.xcassets/image_editor_checkmark_full.imageset/checkmark-circle-filled-32@2x.png diff --git a/Session/Images.xcassets/image_editor_checkmark_full.imageset/checkmark-circle-filled-32@3x.png b/Session/Meta/Images.xcassets/image_editor_checkmark_full.imageset/checkmark-circle-filled-32@3x.png similarity index 100% rename from Session/Images.xcassets/image_editor_checkmark_full.imageset/checkmark-circle-filled-32@3x.png rename to Session/Meta/Images.xcassets/image_editor_checkmark_full.imageset/checkmark-circle-filled-32@3x.png diff --git a/Session/Images.xcassets/image_editor_crop.imageset/Contents.json b/Session/Meta/Images.xcassets/image_editor_crop.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/image_editor_crop.imageset/Contents.json rename to Session/Meta/Images.xcassets/image_editor_crop.imageset/Contents.json diff --git a/Session/Images.xcassets/image_editor_crop.imageset/crop-32@1x.png b/Session/Meta/Images.xcassets/image_editor_crop.imageset/crop-32@1x.png similarity index 100% rename from Session/Images.xcassets/image_editor_crop.imageset/crop-32@1x.png rename to Session/Meta/Images.xcassets/image_editor_crop.imageset/crop-32@1x.png diff --git a/Session/Images.xcassets/image_editor_crop.imageset/crop-32@2x.png b/Session/Meta/Images.xcassets/image_editor_crop.imageset/crop-32@2x.png similarity index 100% rename from Session/Images.xcassets/image_editor_crop.imageset/crop-32@2x.png rename to Session/Meta/Images.xcassets/image_editor_crop.imageset/crop-32@2x.png diff --git a/Session/Images.xcassets/image_editor_crop.imageset/crop-32@3x.png b/Session/Meta/Images.xcassets/image_editor_crop.imageset/crop-32@3x.png similarity index 100% rename from Session/Images.xcassets/image_editor_crop.imageset/crop-32@3x.png rename to Session/Meta/Images.xcassets/image_editor_crop.imageset/crop-32@3x.png diff --git a/Session/Images.xcassets/image_editor_crop_lock.imageset/Contents.json b/Session/Meta/Images.xcassets/image_editor_crop_lock.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/image_editor_crop_lock.imageset/Contents.json rename to Session/Meta/Images.xcassets/image_editor_crop_lock.imageset/Contents.json diff --git a/Session/Images.xcassets/image_editor_crop_lock.imageset/crop-lock-32@1x.png b/Session/Meta/Images.xcassets/image_editor_crop_lock.imageset/crop-lock-32@1x.png similarity index 100% rename from Session/Images.xcassets/image_editor_crop_lock.imageset/crop-lock-32@1x.png rename to Session/Meta/Images.xcassets/image_editor_crop_lock.imageset/crop-lock-32@1x.png diff --git a/Session/Images.xcassets/image_editor_crop_lock.imageset/crop-lock-32@2x.png b/Session/Meta/Images.xcassets/image_editor_crop_lock.imageset/crop-lock-32@2x.png similarity index 100% rename from Session/Images.xcassets/image_editor_crop_lock.imageset/crop-lock-32@2x.png rename to Session/Meta/Images.xcassets/image_editor_crop_lock.imageset/crop-lock-32@2x.png diff --git a/Session/Images.xcassets/image_editor_crop_lock.imageset/crop-lock-32@3x.png b/Session/Meta/Images.xcassets/image_editor_crop_lock.imageset/crop-lock-32@3x.png similarity index 100% rename from Session/Images.xcassets/image_editor_crop_lock.imageset/crop-lock-32@3x.png rename to Session/Meta/Images.xcassets/image_editor_crop_lock.imageset/crop-lock-32@3x.png diff --git a/Session/Images.xcassets/image_editor_crop_unlock.imageset/Contents.json b/Session/Meta/Images.xcassets/image_editor_crop_unlock.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/image_editor_crop_unlock.imageset/Contents.json rename to Session/Meta/Images.xcassets/image_editor_crop_unlock.imageset/Contents.json diff --git a/Session/Images.xcassets/image_editor_crop_unlock.imageset/crop-unlock-32@1x.png b/Session/Meta/Images.xcassets/image_editor_crop_unlock.imageset/crop-unlock-32@1x.png similarity index 100% rename from Session/Images.xcassets/image_editor_crop_unlock.imageset/crop-unlock-32@1x.png rename to Session/Meta/Images.xcassets/image_editor_crop_unlock.imageset/crop-unlock-32@1x.png diff --git a/Session/Images.xcassets/image_editor_crop_unlock.imageset/crop-unlock-32@2x.png b/Session/Meta/Images.xcassets/image_editor_crop_unlock.imageset/crop-unlock-32@2x.png similarity index 100% rename from Session/Images.xcassets/image_editor_crop_unlock.imageset/crop-unlock-32@2x.png rename to Session/Meta/Images.xcassets/image_editor_crop_unlock.imageset/crop-unlock-32@2x.png diff --git a/Session/Images.xcassets/image_editor_crop_unlock.imageset/crop-unlock-32@3x.png b/Session/Meta/Images.xcassets/image_editor_crop_unlock.imageset/crop-unlock-32@3x.png similarity index 100% rename from Session/Images.xcassets/image_editor_crop_unlock.imageset/crop-unlock-32@3x.png rename to Session/Meta/Images.xcassets/image_editor_crop_unlock.imageset/crop-unlock-32@3x.png diff --git a/Session/Images.xcassets/image_editor_flip.imageset/Contents.json b/Session/Meta/Images.xcassets/image_editor_flip.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/image_editor_flip.imageset/Contents.json rename to Session/Meta/Images.xcassets/image_editor_flip.imageset/Contents.json diff --git a/Session/Images.xcassets/image_editor_flip.imageset/flip-32@1x.png b/Session/Meta/Images.xcassets/image_editor_flip.imageset/flip-32@1x.png similarity index 100% rename from Session/Images.xcassets/image_editor_flip.imageset/flip-32@1x.png rename to Session/Meta/Images.xcassets/image_editor_flip.imageset/flip-32@1x.png diff --git a/Session/Images.xcassets/image_editor_flip.imageset/flip-32@2x.png b/Session/Meta/Images.xcassets/image_editor_flip.imageset/flip-32@2x.png similarity index 100% rename from Session/Images.xcassets/image_editor_flip.imageset/flip-32@2x.png rename to Session/Meta/Images.xcassets/image_editor_flip.imageset/flip-32@2x.png diff --git a/Session/Images.xcassets/image_editor_flip.imageset/flip-32@3x.png b/Session/Meta/Images.xcassets/image_editor_flip.imageset/flip-32@3x.png similarity index 100% rename from Session/Images.xcassets/image_editor_flip.imageset/flip-32@3x.png rename to Session/Meta/Images.xcassets/image_editor_flip.imageset/flip-32@3x.png diff --git a/Session/Images.xcassets/image_editor_rotate.imageset/Contents.json b/Session/Meta/Images.xcassets/image_editor_rotate.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/image_editor_rotate.imageset/Contents.json rename to Session/Meta/Images.xcassets/image_editor_rotate.imageset/Contents.json diff --git a/Session/Images.xcassets/image_editor_rotate.imageset/rotate-32@1x.png b/Session/Meta/Images.xcassets/image_editor_rotate.imageset/rotate-32@1x.png similarity index 100% rename from Session/Images.xcassets/image_editor_rotate.imageset/rotate-32@1x.png rename to Session/Meta/Images.xcassets/image_editor_rotate.imageset/rotate-32@1x.png diff --git a/Session/Images.xcassets/image_editor_rotate.imageset/rotate-32@2x.png b/Session/Meta/Images.xcassets/image_editor_rotate.imageset/rotate-32@2x.png similarity index 100% rename from Session/Images.xcassets/image_editor_rotate.imageset/rotate-32@2x.png rename to Session/Meta/Images.xcassets/image_editor_rotate.imageset/rotate-32@2x.png diff --git a/Session/Images.xcassets/image_editor_rotate.imageset/rotate-32@3x.png b/Session/Meta/Images.xcassets/image_editor_rotate.imageset/rotate-32@3x.png similarity index 100% rename from Session/Images.xcassets/image_editor_rotate.imageset/rotate-32@3x.png rename to Session/Meta/Images.xcassets/image_editor_rotate.imageset/rotate-32@3x.png diff --git a/Session/Images.xcassets/image_editor_text.imageset/Contents.json b/Session/Meta/Images.xcassets/image_editor_text.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/image_editor_text.imageset/Contents.json rename to Session/Meta/Images.xcassets/image_editor_text.imageset/Contents.json diff --git a/Session/Images.xcassets/image_editor_text.imageset/text-32@1x.png b/Session/Meta/Images.xcassets/image_editor_text.imageset/text-32@1x.png similarity index 100% rename from Session/Images.xcassets/image_editor_text.imageset/text-32@1x.png rename to Session/Meta/Images.xcassets/image_editor_text.imageset/text-32@1x.png diff --git a/Session/Images.xcassets/image_editor_text.imageset/text-32@2x.png b/Session/Meta/Images.xcassets/image_editor_text.imageset/text-32@2x.png similarity index 100% rename from Session/Images.xcassets/image_editor_text.imageset/text-32@2x.png rename to Session/Meta/Images.xcassets/image_editor_text.imageset/text-32@2x.png diff --git a/Session/Images.xcassets/image_editor_text.imageset/text-32@3x.png b/Session/Meta/Images.xcassets/image_editor_text.imageset/text-32@3x.png similarity index 100% rename from Session/Images.xcassets/image_editor_text.imageset/text-32@3x.png rename to Session/Meta/Images.xcassets/image_editor_text.imageset/text-32@3x.png diff --git a/Session/Images.xcassets/image_editor_undo.imageset/Contents.json b/Session/Meta/Images.xcassets/image_editor_undo.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/image_editor_undo.imageset/Contents.json rename to Session/Meta/Images.xcassets/image_editor_undo.imageset/Contents.json diff --git a/Session/Images.xcassets/image_editor_undo.imageset/undo-32@1x.png b/Session/Meta/Images.xcassets/image_editor_undo.imageset/undo-32@1x.png similarity index 100% rename from Session/Images.xcassets/image_editor_undo.imageset/undo-32@1x.png rename to Session/Meta/Images.xcassets/image_editor_undo.imageset/undo-32@1x.png diff --git a/Session/Images.xcassets/image_editor_undo.imageset/undo-32@2x.png b/Session/Meta/Images.xcassets/image_editor_undo.imageset/undo-32@2x.png similarity index 100% rename from Session/Images.xcassets/image_editor_undo.imageset/undo-32@2x.png rename to Session/Meta/Images.xcassets/image_editor_undo.imageset/undo-32@2x.png diff --git a/Session/Images.xcassets/image_editor_undo.imageset/undo-32@3x.png b/Session/Meta/Images.xcassets/image_editor_undo.imageset/undo-32@3x.png similarity index 100% rename from Session/Images.xcassets/image_editor_undo.imageset/undo-32@3x.png rename to Session/Meta/Images.xcassets/image_editor_undo.imageset/undo-32@3x.png diff --git a/Session/Images.xcassets/introducing-link-previews-dark.imageset/Contents.json b/Session/Meta/Images.xcassets/introducing-link-previews-dark.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/introducing-link-previews-dark.imageset/Contents.json rename to Session/Meta/Images.xcassets/introducing-link-previews-dark.imageset/Contents.json diff --git a/Session/Images.xcassets/introducing-link-previews-dark.imageset/ios-rick-roll-dark@1x.png b/Session/Meta/Images.xcassets/introducing-link-previews-dark.imageset/ios-rick-roll-dark@1x.png similarity index 100% rename from Session/Images.xcassets/introducing-link-previews-dark.imageset/ios-rick-roll-dark@1x.png rename to Session/Meta/Images.xcassets/introducing-link-previews-dark.imageset/ios-rick-roll-dark@1x.png diff --git a/Session/Images.xcassets/introducing-link-previews-dark.imageset/ios-rick-roll-dark@2x.png b/Session/Meta/Images.xcassets/introducing-link-previews-dark.imageset/ios-rick-roll-dark@2x.png similarity index 100% rename from Session/Images.xcassets/introducing-link-previews-dark.imageset/ios-rick-roll-dark@2x.png rename to Session/Meta/Images.xcassets/introducing-link-previews-dark.imageset/ios-rick-roll-dark@2x.png diff --git a/Session/Images.xcassets/introducing-link-previews-dark.imageset/ios-rick-roll-dark@3x.png b/Session/Meta/Images.xcassets/introducing-link-previews-dark.imageset/ios-rick-roll-dark@3x.png similarity index 100% rename from Session/Images.xcassets/introducing-link-previews-dark.imageset/ios-rick-roll-dark@3x.png rename to Session/Meta/Images.xcassets/introducing-link-previews-dark.imageset/ios-rick-roll-dark@3x.png diff --git a/Session/Images.xcassets/introducing-link-previews-light.imageset/Contents.json b/Session/Meta/Images.xcassets/introducing-link-previews-light.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/introducing-link-previews-light.imageset/Contents.json rename to Session/Meta/Images.xcassets/introducing-link-previews-light.imageset/Contents.json diff --git a/Session/Images.xcassets/introducing-link-previews-light.imageset/ios-rick-roll-light@1x.png b/Session/Meta/Images.xcassets/introducing-link-previews-light.imageset/ios-rick-roll-light@1x.png similarity index 100% rename from Session/Images.xcassets/introducing-link-previews-light.imageset/ios-rick-roll-light@1x.png rename to Session/Meta/Images.xcassets/introducing-link-previews-light.imageset/ios-rick-roll-light@1x.png diff --git a/Session/Images.xcassets/introducing-link-previews-light.imageset/ios-rick-roll-light@2x.png b/Session/Meta/Images.xcassets/introducing-link-previews-light.imageset/ios-rick-roll-light@2x.png similarity index 100% rename from Session/Images.xcassets/introducing-link-previews-light.imageset/ios-rick-roll-light@2x.png rename to Session/Meta/Images.xcassets/introducing-link-previews-light.imageset/ios-rick-roll-light@2x.png diff --git a/Session/Images.xcassets/introducing-link-previews-light.imageset/ios-rick-roll-light@3x.png b/Session/Meta/Images.xcassets/introducing-link-previews-light.imageset/ios-rick-roll-light@3x.png similarity index 100% rename from Session/Images.xcassets/introducing-link-previews-light.imageset/ios-rick-roll-light@3x.png rename to Session/Meta/Images.xcassets/introducing-link-previews-light.imageset/ios-rick-roll-light@3x.png diff --git a/Session/Images.xcassets/introductory_splash_callkit.imageset/Contents.json b/Session/Meta/Images.xcassets/introductory_splash_callkit.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/introductory_splash_callkit.imageset/Contents.json rename to Session/Meta/Images.xcassets/introductory_splash_callkit.imageset/Contents.json diff --git a/Session/Images.xcassets/introductory_splash_callkit.imageset/signal-answer.png b/Session/Meta/Images.xcassets/introductory_splash_callkit.imageset/signal-answer.png similarity index 100% rename from Session/Images.xcassets/introductory_splash_callkit.imageset/signal-answer.png rename to Session/Meta/Images.xcassets/introductory_splash_callkit.imageset/signal-answer.png diff --git a/Session/Images.xcassets/introductory_splash_callkit.imageset/signal-answer@2x.png b/Session/Meta/Images.xcassets/introductory_splash_callkit.imageset/signal-answer@2x.png similarity index 100% rename from Session/Images.xcassets/introductory_splash_callkit.imageset/signal-answer@2x.png rename to Session/Meta/Images.xcassets/introductory_splash_callkit.imageset/signal-answer@2x.png diff --git a/Session/Images.xcassets/introductory_splash_callkit.imageset/signal-answer@3x.png b/Session/Meta/Images.xcassets/introductory_splash_callkit.imageset/signal-answer@3x.png similarity index 100% rename from Session/Images.xcassets/introductory_splash_callkit.imageset/signal-answer@3x.png rename to Session/Meta/Images.xcassets/introductory_splash_callkit.imageset/signal-answer@3x.png diff --git a/Session/Images.xcassets/introductory_splash_custom_audio.imageset/Contents.json b/Session/Meta/Images.xcassets/introductory_splash_custom_audio.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/introductory_splash_custom_audio.imageset/Contents.json rename to Session/Meta/Images.xcassets/introductory_splash_custom_audio.imageset/Contents.json diff --git a/Session/Images.xcassets/introductory_splash_custom_audio.imageset/signal-possum-far-wclouds@1x.png b/Session/Meta/Images.xcassets/introductory_splash_custom_audio.imageset/signal-possum-far-wclouds@1x.png similarity index 100% rename from Session/Images.xcassets/introductory_splash_custom_audio.imageset/signal-possum-far-wclouds@1x.png rename to Session/Meta/Images.xcassets/introductory_splash_custom_audio.imageset/signal-possum-far-wclouds@1x.png diff --git a/Session/Images.xcassets/introductory_splash_custom_audio.imageset/signal-possum-far-wclouds@2x.png b/Session/Meta/Images.xcassets/introductory_splash_custom_audio.imageset/signal-possum-far-wclouds@2x.png similarity index 100% rename from Session/Images.xcassets/introductory_splash_custom_audio.imageset/signal-possum-far-wclouds@2x.png rename to Session/Meta/Images.xcassets/introductory_splash_custom_audio.imageset/signal-possum-far-wclouds@2x.png diff --git a/Session/Images.xcassets/introductory_splash_custom_audio.imageset/signal-possum-far-wclouds@3x.png b/Session/Meta/Images.xcassets/introductory_splash_custom_audio.imageset/signal-possum-far-wclouds@3x.png similarity index 100% rename from Session/Images.xcassets/introductory_splash_custom_audio.imageset/signal-possum-far-wclouds@3x.png rename to Session/Meta/Images.xcassets/introductory_splash_custom_audio.imageset/signal-possum-far-wclouds@3x.png diff --git a/Session/Images.xcassets/introductory_splash_profile.imageset/Contents.json b/Session/Meta/Images.xcassets/introductory_splash_profile.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/introductory_splash_profile.imageset/Contents.json rename to Session/Meta/Images.xcassets/introductory_splash_profile.imageset/Contents.json diff --git a/Session/Images.xcassets/introductory_splash_profile.imageset/introductory_splash_profile.png b/Session/Meta/Images.xcassets/introductory_splash_profile.imageset/introductory_splash_profile.png similarity index 100% rename from Session/Images.xcassets/introductory_splash_profile.imageset/introductory_splash_profile.png rename to Session/Meta/Images.xcassets/introductory_splash_profile.imageset/introductory_splash_profile.png diff --git a/Session/Images.xcassets/introductory_splash_profile.imageset/introductory_splash_profile@2x.png b/Session/Meta/Images.xcassets/introductory_splash_profile.imageset/introductory_splash_profile@2x.png similarity index 100% rename from Session/Images.xcassets/introductory_splash_profile.imageset/introductory_splash_profile@2x.png rename to Session/Meta/Images.xcassets/introductory_splash_profile.imageset/introductory_splash_profile@2x.png diff --git a/Session/Images.xcassets/introductory_splash_profile.imageset/introductory_splash_profile@3x.png b/Session/Meta/Images.xcassets/introductory_splash_profile.imageset/introductory_splash_profile@3x.png similarity index 100% rename from Session/Images.xcassets/introductory_splash_profile.imageset/introductory_splash_profile@3x.png rename to Session/Meta/Images.xcassets/introductory_splash_profile.imageset/introductory_splash_profile@3x.png diff --git a/Session/Images.xcassets/introductory_splash_read_receipts.imageset/Contents.json b/Session/Meta/Images.xcassets/introductory_splash_read_receipts.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/introductory_splash_read_receipts.imageset/Contents.json rename to Session/Meta/Images.xcassets/introductory_splash_read_receipts.imageset/Contents.json diff --git a/Session/Images.xcassets/introductory_splash_read_receipts.imageset/signal-penguin-letter@1x.png b/Session/Meta/Images.xcassets/introductory_splash_read_receipts.imageset/signal-penguin-letter@1x.png similarity index 100% rename from Session/Images.xcassets/introductory_splash_read_receipts.imageset/signal-penguin-letter@1x.png rename to Session/Meta/Images.xcassets/introductory_splash_read_receipts.imageset/signal-penguin-letter@1x.png diff --git a/Session/Images.xcassets/introductory_splash_read_receipts.imageset/signal-penguin-letter@2x.png b/Session/Meta/Images.xcassets/introductory_splash_read_receipts.imageset/signal-penguin-letter@2x.png similarity index 100% rename from Session/Images.xcassets/introductory_splash_read_receipts.imageset/signal-penguin-letter@2x.png rename to Session/Meta/Images.xcassets/introductory_splash_read_receipts.imageset/signal-penguin-letter@2x.png diff --git a/Session/Images.xcassets/introductory_splash_read_receipts.imageset/signal-penguin-letter@3x.png b/Session/Meta/Images.xcassets/introductory_splash_read_receipts.imageset/signal-penguin-letter@3x.png similarity index 100% rename from Session/Images.xcassets/introductory_splash_read_receipts.imageset/signal-penguin-letter@3x.png rename to Session/Meta/Images.xcassets/introductory_splash_read_receipts.imageset/signal-penguin-letter@3x.png diff --git a/Session/Images.xcassets/introductory_splash_video_calling.imageset/Contents.json b/Session/Meta/Images.xcassets/introductory_splash_video_calling.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/introductory_splash_video_calling.imageset/Contents.json rename to Session/Meta/Images.xcassets/introductory_splash_video_calling.imageset/Contents.json diff --git a/Session/Images.xcassets/introductory_splash_video_calling.imageset/signal-video-splash.png b/Session/Meta/Images.xcassets/introductory_splash_video_calling.imageset/signal-video-splash.png similarity index 100% rename from Session/Images.xcassets/introductory_splash_video_calling.imageset/signal-video-splash.png rename to Session/Meta/Images.xcassets/introductory_splash_video_calling.imageset/signal-video-splash.png diff --git a/Session/Images.xcassets/introductory_splash_video_calling.imageset/signal-video-splash@2x.png b/Session/Meta/Images.xcassets/introductory_splash_video_calling.imageset/signal-video-splash@2x.png similarity index 100% rename from Session/Images.xcassets/introductory_splash_video_calling.imageset/signal-video-splash@2x.png rename to Session/Meta/Images.xcassets/introductory_splash_video_calling.imageset/signal-video-splash@2x.png diff --git a/Session/Images.xcassets/introductory_splash_video_calling.imageset/signal-video-splash@3x.png b/Session/Meta/Images.xcassets/introductory_splash_video_calling.imageset/signal-video-splash@3x.png similarity index 100% rename from Session/Images.xcassets/introductory_splash_video_calling.imageset/signal-video-splash@3x.png rename to Session/Meta/Images.xcassets/introductory_splash_video_calling.imageset/signal-video-splash@3x.png diff --git a/Session/Images.xcassets/logoSignal.imageset/Contents.json b/Session/Meta/Images.xcassets/logoSignal.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/logoSignal.imageset/Contents.json rename to Session/Meta/Images.xcassets/logoSignal.imageset/Contents.json diff --git a/Session/Images.xcassets/logoSignal.imageset/logoSignal.pdf b/Session/Meta/Images.xcassets/logoSignal.imageset/logoSignal.pdf similarity index 100% rename from Session/Images.xcassets/logoSignal.imageset/logoSignal.pdf rename to Session/Meta/Images.xcassets/logoSignal.imageset/logoSignal.pdf diff --git a/Session/Images.xcassets/media_album_caption.imageset/Contents.json b/Session/Meta/Images.xcassets/media_album_caption.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/media_album_caption.imageset/Contents.json rename to Session/Meta/Images.xcassets/media_album_caption.imageset/Contents.json diff --git a/Session/Images.xcassets/media_album_caption.imageset/caption-shadow-24@1x.png b/Session/Meta/Images.xcassets/media_album_caption.imageset/caption-shadow-24@1x.png similarity index 100% rename from Session/Images.xcassets/media_album_caption.imageset/caption-shadow-24@1x.png rename to Session/Meta/Images.xcassets/media_album_caption.imageset/caption-shadow-24@1x.png diff --git a/Session/Images.xcassets/media_album_caption.imageset/caption-shadow-24@2x.png b/Session/Meta/Images.xcassets/media_album_caption.imageset/caption-shadow-24@2x.png similarity index 100% rename from Session/Images.xcassets/media_album_caption.imageset/caption-shadow-24@2x.png rename to Session/Meta/Images.xcassets/media_album_caption.imageset/caption-shadow-24@2x.png diff --git a/Session/Images.xcassets/media_album_caption.imageset/caption-shadow-24@3x.png b/Session/Meta/Images.xcassets/media_album_caption.imageset/caption-shadow-24@3x.png similarity index 100% rename from Session/Images.xcassets/media_album_caption.imageset/caption-shadow-24@3x.png rename to Session/Meta/Images.xcassets/media_album_caption.imageset/caption-shadow-24@3x.png diff --git a/Session/Images.xcassets/media_invalid.imageset/Contents.json b/Session/Meta/Images.xcassets/media_invalid.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/media_invalid.imageset/Contents.json rename to Session/Meta/Images.xcassets/media_invalid.imageset/Contents.json diff --git a/Session/Images.xcassets/media_invalid.imageset/photo-error-36.png b/Session/Meta/Images.xcassets/media_invalid.imageset/photo-error-36.png similarity index 100% rename from Session/Images.xcassets/media_invalid.imageset/photo-error-36.png rename to Session/Meta/Images.xcassets/media_invalid.imageset/photo-error-36.png diff --git a/Session/Images.xcassets/media_invalid.imageset/photo-error-36@2x.png b/Session/Meta/Images.xcassets/media_invalid.imageset/photo-error-36@2x.png similarity index 100% rename from Session/Images.xcassets/media_invalid.imageset/photo-error-36@2x.png rename to Session/Meta/Images.xcassets/media_invalid.imageset/photo-error-36@2x.png diff --git a/Session/Images.xcassets/media_invalid.imageset/photo-error-36@3x.png b/Session/Meta/Images.xcassets/media_invalid.imageset/photo-error-36@3x.png similarity index 100% rename from Session/Images.xcassets/media_invalid.imageset/photo-error-36@3x.png rename to Session/Meta/Images.xcassets/media_invalid.imageset/photo-error-36@3x.png diff --git a/Session/Images.xcassets/media_retry.imageset/Contents.json b/Session/Meta/Images.xcassets/media_retry.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/media_retry.imageset/Contents.json rename to Session/Meta/Images.xcassets/media_retry.imageset/Contents.json diff --git a/Session/Images.xcassets/media_retry.imageset/retry-36.png b/Session/Meta/Images.xcassets/media_retry.imageset/retry-36.png similarity index 100% rename from Session/Images.xcassets/media_retry.imageset/retry-36.png rename to Session/Meta/Images.xcassets/media_retry.imageset/retry-36.png diff --git a/Session/Images.xcassets/media_retry.imageset/retry-36@2x.png b/Session/Meta/Images.xcassets/media_retry.imageset/retry-36@2x.png similarity index 100% rename from Session/Images.xcassets/media_retry.imageset/retry-36@2x.png rename to Session/Meta/Images.xcassets/media_retry.imageset/retry-36@2x.png diff --git a/Session/Images.xcassets/media_retry.imageset/retry-36@3x.png b/Session/Meta/Images.xcassets/media_retry.imageset/retry-36@3x.png similarity index 100% rename from Session/Images.xcassets/media_retry.imageset/retry-36@3x.png rename to Session/Meta/Images.xcassets/media_retry.imageset/retry-36@3x.png diff --git a/Session/Images.xcassets/media_send_batch_mode_disabled.imageset/Contents.json b/Session/Meta/Images.xcassets/media_send_batch_mode_disabled.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/media_send_batch_mode_disabled.imageset/Contents.json rename to Session/Meta/Images.xcassets/media_send_batch_mode_disabled.imageset/Contents.json diff --git a/Session/Images.xcassets/media_send_batch_mode_disabled.imageset/create-album-outline-32@1x.png b/Session/Meta/Images.xcassets/media_send_batch_mode_disabled.imageset/create-album-outline-32@1x.png similarity index 100% rename from Session/Images.xcassets/media_send_batch_mode_disabled.imageset/create-album-outline-32@1x.png rename to Session/Meta/Images.xcassets/media_send_batch_mode_disabled.imageset/create-album-outline-32@1x.png diff --git a/Session/Images.xcassets/media_send_batch_mode_disabled.imageset/create-album-outline-32@2x.png b/Session/Meta/Images.xcassets/media_send_batch_mode_disabled.imageset/create-album-outline-32@2x.png similarity index 100% rename from Session/Images.xcassets/media_send_batch_mode_disabled.imageset/create-album-outline-32@2x.png rename to Session/Meta/Images.xcassets/media_send_batch_mode_disabled.imageset/create-album-outline-32@2x.png diff --git a/Session/Images.xcassets/media_send_batch_mode_disabled.imageset/create-album-outline-32@3x.png b/Session/Meta/Images.xcassets/media_send_batch_mode_disabled.imageset/create-album-outline-32@3x.png similarity index 100% rename from Session/Images.xcassets/media_send_batch_mode_disabled.imageset/create-album-outline-32@3x.png rename to Session/Meta/Images.xcassets/media_send_batch_mode_disabled.imageset/create-album-outline-32@3x.png diff --git a/Session/Images.xcassets/message-active-wide.imageset/Contents.json b/Session/Meta/Images.xcassets/message-active-wide.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/message-active-wide.imageset/Contents.json rename to Session/Meta/Images.xcassets/message-active-wide.imageset/Contents.json diff --git a/Session/Images.xcassets/message-active-wide.imageset/message-active-wide.png b/Session/Meta/Images.xcassets/message-active-wide.imageset/message-active-wide.png similarity index 100% rename from Session/Images.xcassets/message-active-wide.imageset/message-active-wide.png rename to Session/Meta/Images.xcassets/message-active-wide.imageset/message-active-wide.png diff --git a/Session/Images.xcassets/message_status_delivered.imageset/Contents.json b/Session/Meta/Images.xcassets/message_status_delivered.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/message_status_delivered.imageset/Contents.json rename to Session/Meta/Images.xcassets/message_status_delivered.imageset/Contents.json diff --git a/Session/Images.xcassets/message_status_delivered.imageset/delivered-18x12@1x.png b/Session/Meta/Images.xcassets/message_status_delivered.imageset/delivered-18x12@1x.png similarity index 100% rename from Session/Images.xcassets/message_status_delivered.imageset/delivered-18x12@1x.png rename to Session/Meta/Images.xcassets/message_status_delivered.imageset/delivered-18x12@1x.png diff --git a/Session/Images.xcassets/message_status_delivered.imageset/double check@2x.png b/Session/Meta/Images.xcassets/message_status_delivered.imageset/double check@2x.png similarity index 100% rename from Session/Images.xcassets/message_status_delivered.imageset/double check@2x.png rename to Session/Meta/Images.xcassets/message_status_delivered.imageset/double check@2x.png diff --git a/Session/Images.xcassets/message_status_delivered.imageset/double check@3x.png b/Session/Meta/Images.xcassets/message_status_delivered.imageset/double check@3x.png similarity index 100% rename from Session/Images.xcassets/message_status_delivered.imageset/double check@3x.png rename to Session/Meta/Images.xcassets/message_status_delivered.imageset/double check@3x.png diff --git a/Session/Images.xcassets/message_status_failed.imageset/Contents.json b/Session/Meta/Images.xcassets/message_status_failed.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/message_status_failed.imageset/Contents.json rename to Session/Meta/Images.xcassets/message_status_failed.imageset/Contents.json diff --git a/Session/Images.xcassets/message_status_failed.imageset/error-12@1x.png b/Session/Meta/Images.xcassets/message_status_failed.imageset/error-12@1x.png similarity index 100% rename from Session/Images.xcassets/message_status_failed.imageset/error-12@1x.png rename to Session/Meta/Images.xcassets/message_status_failed.imageset/error-12@1x.png diff --git a/Session/Images.xcassets/message_status_failed.imageset/error-12@2x.png b/Session/Meta/Images.xcassets/message_status_failed.imageset/error-12@2x.png similarity index 100% rename from Session/Images.xcassets/message_status_failed.imageset/error-12@2x.png rename to Session/Meta/Images.xcassets/message_status_failed.imageset/error-12@2x.png diff --git a/Session/Images.xcassets/message_status_failed.imageset/error-12@3x.png b/Session/Meta/Images.xcassets/message_status_failed.imageset/error-12@3x.png similarity index 100% rename from Session/Images.xcassets/message_status_failed.imageset/error-12@3x.png rename to Session/Meta/Images.xcassets/message_status_failed.imageset/error-12@3x.png diff --git a/Session/Images.xcassets/message_status_failed_large.imageset/Contents.json b/Session/Meta/Images.xcassets/message_status_failed_large.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/message_status_failed_large.imageset/Contents.json rename to Session/Meta/Images.xcassets/message_status_failed_large.imageset/Contents.json diff --git a/Session/Images.xcassets/message_status_failed_large.imageset/error-20@1x.png b/Session/Meta/Images.xcassets/message_status_failed_large.imageset/error-20@1x.png similarity index 100% rename from Session/Images.xcassets/message_status_failed_large.imageset/error-20@1x.png rename to Session/Meta/Images.xcassets/message_status_failed_large.imageset/error-20@1x.png diff --git a/Session/Images.xcassets/message_status_failed_large.imageset/error-20@2x.png b/Session/Meta/Images.xcassets/message_status_failed_large.imageset/error-20@2x.png similarity index 100% rename from Session/Images.xcassets/message_status_failed_large.imageset/error-20@2x.png rename to Session/Meta/Images.xcassets/message_status_failed_large.imageset/error-20@2x.png diff --git a/Session/Images.xcassets/message_status_failed_large.imageset/error-20@3x.png b/Session/Meta/Images.xcassets/message_status_failed_large.imageset/error-20@3x.png similarity index 100% rename from Session/Images.xcassets/message_status_failed_large.imageset/error-20@3x.png rename to Session/Meta/Images.xcassets/message_status_failed_large.imageset/error-20@3x.png diff --git a/Session/Images.xcassets/message_status_read.imageset/Contents.json b/Session/Meta/Images.xcassets/message_status_read.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/message_status_read.imageset/Contents.json rename to Session/Meta/Images.xcassets/message_status_read.imageset/Contents.json diff --git a/Session/Images.xcassets/message_status_read.imageset/read-18x12@1x.png b/Session/Meta/Images.xcassets/message_status_read.imageset/read-18x12@1x.png similarity index 100% rename from Session/Images.xcassets/message_status_read.imageset/read-18x12@1x.png rename to Session/Meta/Images.xcassets/message_status_read.imageset/read-18x12@1x.png diff --git a/Session/Images.xcassets/message_status_read.imageset/read-18x12@2x.png b/Session/Meta/Images.xcassets/message_status_read.imageset/read-18x12@2x.png similarity index 100% rename from Session/Images.xcassets/message_status_read.imageset/read-18x12@2x.png rename to Session/Meta/Images.xcassets/message_status_read.imageset/read-18x12@2x.png diff --git a/Session/Images.xcassets/message_status_read.imageset/read-18x12@3x.png b/Session/Meta/Images.xcassets/message_status_read.imageset/read-18x12@3x.png similarity index 100% rename from Session/Images.xcassets/message_status_read.imageset/read-18x12@3x.png rename to Session/Meta/Images.xcassets/message_status_read.imageset/read-18x12@3x.png diff --git a/Session/Images.xcassets/message_status_sending.imageset/Contents.json b/Session/Meta/Images.xcassets/message_status_sending.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/message_status_sending.imageset/Contents.json rename to Session/Meta/Images.xcassets/message_status_sending.imageset/Contents.json diff --git a/Session/Images.xcassets/message_status_sending.imageset/sending@1x.png b/Session/Meta/Images.xcassets/message_status_sending.imageset/sending@1x.png similarity index 100% rename from Session/Images.xcassets/message_status_sending.imageset/sending@1x.png rename to Session/Meta/Images.xcassets/message_status_sending.imageset/sending@1x.png diff --git a/Session/Images.xcassets/message_status_sending.imageset/sending@2x.png b/Session/Meta/Images.xcassets/message_status_sending.imageset/sending@2x.png similarity index 100% rename from Session/Images.xcassets/message_status_sending.imageset/sending@2x.png rename to Session/Meta/Images.xcassets/message_status_sending.imageset/sending@2x.png diff --git a/Session/Images.xcassets/message_status_sending.imageset/sending@3x.png b/Session/Meta/Images.xcassets/message_status_sending.imageset/sending@3x.png similarity index 100% rename from Session/Images.xcassets/message_status_sending.imageset/sending@3x.png rename to Session/Meta/Images.xcassets/message_status_sending.imageset/sending@3x.png diff --git a/Session/Images.xcassets/message_status_sent.imageset/Contents.json b/Session/Meta/Images.xcassets/message_status_sent.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/message_status_sent.imageset/Contents.json rename to Session/Meta/Images.xcassets/message_status_sent.imageset/Contents.json diff --git a/Session/Images.xcassets/message_status_sent.imageset/sent-12@1x.png b/Session/Meta/Images.xcassets/message_status_sent.imageset/sent-12@1x.png similarity index 100% rename from Session/Images.xcassets/message_status_sent.imageset/sent-12@1x.png rename to Session/Meta/Images.xcassets/message_status_sent.imageset/sent-12@1x.png diff --git a/Session/Images.xcassets/message_status_sent.imageset/sent-12@2x.png b/Session/Meta/Images.xcassets/message_status_sent.imageset/sent-12@2x.png similarity index 100% rename from Session/Images.xcassets/message_status_sent.imageset/sent-12@2x.png rename to Session/Meta/Images.xcassets/message_status_sent.imageset/sent-12@2x.png diff --git a/Session/Images.xcassets/message_status_sent.imageset/sent-12@3x.png b/Session/Meta/Images.xcassets/message_status_sent.imageset/sent-12@3x.png similarity index 100% rename from Session/Images.xcassets/message_status_sent.imageset/sent-12@3x.png rename to Session/Meta/Images.xcassets/message_status_sent.imageset/sent-12@3x.png diff --git a/Session/Images.xcassets/navbar_disclosure_down.imageset/Contents.json b/Session/Meta/Images.xcassets/navbar_disclosure_down.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/navbar_disclosure_down.imageset/Contents.json rename to Session/Meta/Images.xcassets/navbar_disclosure_down.imageset/Contents.json diff --git a/Session/Images.xcassets/navbar_disclosure_down.imageset/navbar_disclosure_down_small@1x.png b/Session/Meta/Images.xcassets/navbar_disclosure_down.imageset/navbar_disclosure_down_small@1x.png similarity index 100% rename from Session/Images.xcassets/navbar_disclosure_down.imageset/navbar_disclosure_down_small@1x.png rename to Session/Meta/Images.xcassets/navbar_disclosure_down.imageset/navbar_disclosure_down_small@1x.png diff --git a/Session/Images.xcassets/navbar_disclosure_down.imageset/navbar_disclosure_down_small@2x.png b/Session/Meta/Images.xcassets/navbar_disclosure_down.imageset/navbar_disclosure_down_small@2x.png similarity index 100% rename from Session/Images.xcassets/navbar_disclosure_down.imageset/navbar_disclosure_down_small@2x.png rename to Session/Meta/Images.xcassets/navbar_disclosure_down.imageset/navbar_disclosure_down_small@2x.png diff --git a/Session/Images.xcassets/navbar_disclosure_down.imageset/navbar_disclosure_down_small@3x.png b/Session/Meta/Images.xcassets/navbar_disclosure_down.imageset/navbar_disclosure_down_small@3x.png similarity index 100% rename from Session/Images.xcassets/navbar_disclosure_down.imageset/navbar_disclosure_down_small@3x.png rename to Session/Meta/Images.xcassets/navbar_disclosure_down.imageset/navbar_disclosure_down_small@3x.png diff --git a/Session/Images.xcassets/navbar_disclosure_up.imageset/Contents.json b/Session/Meta/Images.xcassets/navbar_disclosure_up.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/navbar_disclosure_up.imageset/Contents.json rename to Session/Meta/Images.xcassets/navbar_disclosure_up.imageset/Contents.json diff --git a/Session/Images.xcassets/navbar_disclosure_up.imageset/navbar_disclosure_up_small@1x.png b/Session/Meta/Images.xcassets/navbar_disclosure_up.imageset/navbar_disclosure_up_small@1x.png similarity index 100% rename from Session/Images.xcassets/navbar_disclosure_up.imageset/navbar_disclosure_up_small@1x.png rename to Session/Meta/Images.xcassets/navbar_disclosure_up.imageset/navbar_disclosure_up_small@1x.png diff --git a/Session/Images.xcassets/navbar_disclosure_up.imageset/navbar_disclosure_up_small@2x.png b/Session/Meta/Images.xcassets/navbar_disclosure_up.imageset/navbar_disclosure_up_small@2x.png similarity index 100% rename from Session/Images.xcassets/navbar_disclosure_up.imageset/navbar_disclosure_up_small@2x.png rename to Session/Meta/Images.xcassets/navbar_disclosure_up.imageset/navbar_disclosure_up_small@2x.png diff --git a/Session/Images.xcassets/navbar_disclosure_up.imageset/navbar_disclosure_up_small@3x.png b/Session/Meta/Images.xcassets/navbar_disclosure_up.imageset/navbar_disclosure_up_small@3x.png similarity index 100% rename from Session/Images.xcassets/navbar_disclosure_up.imageset/navbar_disclosure_up_small@3x.png rename to Session/Meta/Images.xcassets/navbar_disclosure_up.imageset/navbar_disclosure_up_small@3x.png diff --git a/Session/Images.xcassets/note-to-self-avatar.imageset/Contents.json b/Session/Meta/Images.xcassets/note-to-self-avatar.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/note-to-self-avatar.imageset/Contents.json rename to Session/Meta/Images.xcassets/note-to-self-avatar.imageset/Contents.json diff --git a/Session/Images.xcassets/note-to-self-avatar.imageset/note-24@1x.png b/Session/Meta/Images.xcassets/note-to-self-avatar.imageset/note-24@1x.png similarity index 100% rename from Session/Images.xcassets/note-to-self-avatar.imageset/note-24@1x.png rename to Session/Meta/Images.xcassets/note-to-self-avatar.imageset/note-24@1x.png diff --git a/Session/Images.xcassets/note-to-self-avatar.imageset/note-24@2x.png b/Session/Meta/Images.xcassets/note-to-self-avatar.imageset/note-24@2x.png similarity index 100% rename from Session/Images.xcassets/note-to-self-avatar.imageset/note-24@2x.png rename to Session/Meta/Images.xcassets/note-to-self-avatar.imageset/note-24@2x.png diff --git a/Session/Images.xcassets/note-to-self-avatar.imageset/note-24@3x.png b/Session/Meta/Images.xcassets/note-to-self-avatar.imageset/note-24@3x.png similarity index 100% rename from Session/Images.xcassets/note-to-self-avatar.imageset/note-24@3x.png rename to Session/Meta/Images.xcassets/note-to-self-avatar.imageset/note-24@3x.png diff --git a/Session/Images.xcassets/onboarding_splash_hero.imageset/Contents.json b/Session/Meta/Images.xcassets/onboarding_splash_hero.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/onboarding_splash_hero.imageset/Contents.json rename to Session/Meta/Images.xcassets/onboarding_splash_hero.imageset/Contents.json diff --git a/Session/Images.xcassets/onboarding_splash_hero.imageset/onboarding_splash.png b/Session/Meta/Images.xcassets/onboarding_splash_hero.imageset/onboarding_splash.png similarity index 100% rename from Session/Images.xcassets/onboarding_splash_hero.imageset/onboarding_splash.png rename to Session/Meta/Images.xcassets/onboarding_splash_hero.imageset/onboarding_splash.png diff --git a/Session/Images.xcassets/play_button.imageset/Contents.json b/Session/Meta/Images.xcassets/play_button.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/play_button.imageset/Contents.json rename to Session/Meta/Images.xcassets/play_button.imageset/Contents.json diff --git a/Session/Images.xcassets/play_button.imageset/play_button@2x.png b/Session/Meta/Images.xcassets/play_button.imageset/play_button@2x.png similarity index 100% rename from Session/Images.xcassets/play_button.imageset/play_button@2x.png rename to Session/Meta/Images.xcassets/play_button.imageset/play_button@2x.png diff --git a/Session/Images.xcassets/profile_avatar_default.imageset/Contents.json b/Session/Meta/Images.xcassets/profile_avatar_default.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/profile_avatar_default.imageset/Contents.json rename to Session/Meta/Images.xcassets/profile_avatar_default.imageset/Contents.json diff --git a/Session/Images.xcassets/profile_avatar_default.imageset/profile_avatar_default@1x.png b/Session/Meta/Images.xcassets/profile_avatar_default.imageset/profile_avatar_default@1x.png similarity index 100% rename from Session/Images.xcassets/profile_avatar_default.imageset/profile_avatar_default@1x.png rename to Session/Meta/Images.xcassets/profile_avatar_default.imageset/profile_avatar_default@1x.png diff --git a/Session/Images.xcassets/profile_avatar_default.imageset/profile_avatar_default@2x.png b/Session/Meta/Images.xcassets/profile_avatar_default.imageset/profile_avatar_default@2x.png similarity index 100% rename from Session/Images.xcassets/profile_avatar_default.imageset/profile_avatar_default@2x.png rename to Session/Meta/Images.xcassets/profile_avatar_default.imageset/profile_avatar_default@2x.png diff --git a/Session/Images.xcassets/profile_avatar_default.imageset/profile_avatar_default@3x.png b/Session/Meta/Images.xcassets/profile_avatar_default.imageset/profile_avatar_default@3x.png similarity index 100% rename from Session/Images.xcassets/profile_avatar_default.imageset/profile_avatar_default@3x.png rename to Session/Meta/Images.xcassets/profile_avatar_default.imageset/profile_avatar_default@3x.png diff --git a/Session/Images.xcassets/quoted-message-cancel.imageset/Contents.json b/Session/Meta/Images.xcassets/quoted-message-cancel.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/quoted-message-cancel.imageset/Contents.json rename to Session/Meta/Images.xcassets/quoted-message-cancel.imageset/Contents.json diff --git a/Session/Images.xcassets/quoted-message-cancel.imageset/quoted-message-cancel@1x.png b/Session/Meta/Images.xcassets/quoted-message-cancel.imageset/quoted-message-cancel@1x.png similarity index 100% rename from Session/Images.xcassets/quoted-message-cancel.imageset/quoted-message-cancel@1x.png rename to Session/Meta/Images.xcassets/quoted-message-cancel.imageset/quoted-message-cancel@1x.png diff --git a/Session/Images.xcassets/quoted-message-cancel.imageset/quoted-message-cancel@2x.png b/Session/Meta/Images.xcassets/quoted-message-cancel.imageset/quoted-message-cancel@2x.png similarity index 100% rename from Session/Images.xcassets/quoted-message-cancel.imageset/quoted-message-cancel@2x.png rename to Session/Meta/Images.xcassets/quoted-message-cancel.imageset/quoted-message-cancel@2x.png diff --git a/Session/Images.xcassets/quoted-message-cancel.imageset/quoted-message-cancel@3x.png b/Session/Meta/Images.xcassets/quoted-message-cancel.imageset/quoted-message-cancel@3x.png similarity index 100% rename from Session/Images.xcassets/quoted-message-cancel.imageset/quoted-message-cancel@3x.png rename to Session/Meta/Images.xcassets/quoted-message-cancel.imageset/quoted-message-cancel@3x.png diff --git a/Session/Images.xcassets/searchbar_clear.imageset/Contents.json b/Session/Meta/Images.xcassets/searchbar_clear.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/searchbar_clear.imageset/Contents.json rename to Session/Meta/Images.xcassets/searchbar_clear.imageset/Contents.json diff --git a/Session/Images.xcassets/searchbar_clear.imageset/Search-clear_17x17_@1x.png b/Session/Meta/Images.xcassets/searchbar_clear.imageset/Search-clear_17x17_@1x.png similarity index 100% rename from Session/Images.xcassets/searchbar_clear.imageset/Search-clear_17x17_@1x.png rename to Session/Meta/Images.xcassets/searchbar_clear.imageset/Search-clear_17x17_@1x.png diff --git a/Session/Images.xcassets/searchbar_clear.imageset/Search-clear_17x17_@2x.png b/Session/Meta/Images.xcassets/searchbar_clear.imageset/Search-clear_17x17_@2x.png similarity index 100% rename from Session/Images.xcassets/searchbar_clear.imageset/Search-clear_17x17_@2x.png rename to Session/Meta/Images.xcassets/searchbar_clear.imageset/Search-clear_17x17_@2x.png diff --git a/Session/Images.xcassets/searchbar_clear.imageset/Search-clear_17x17_@3x.png b/Session/Meta/Images.xcassets/searchbar_clear.imageset/Search-clear_17x17_@3x.png similarity index 100% rename from Session/Images.xcassets/searchbar_clear.imageset/Search-clear_17x17_@3x.png rename to Session/Meta/Images.xcassets/searchbar_clear.imageset/Search-clear_17x17_@3x.png diff --git a/Session/Images.xcassets/searchbar_search.imageset/Contents.json b/Session/Meta/Images.xcassets/searchbar_search.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/searchbar_search.imageset/Contents.json rename to Session/Meta/Images.xcassets/searchbar_search.imageset/Contents.json diff --git a/Session/Images.xcassets/searchbar_search.imageset/UIButtonBarSearch_18x18_@1x.png b/Session/Meta/Images.xcassets/searchbar_search.imageset/UIButtonBarSearch_18x18_@1x.png similarity index 100% rename from Session/Images.xcassets/searchbar_search.imageset/UIButtonBarSearch_18x18_@1x.png rename to Session/Meta/Images.xcassets/searchbar_search.imageset/UIButtonBarSearch_18x18_@1x.png diff --git a/Session/Images.xcassets/searchbar_search.imageset/UIButtonBarSearch_18x18_@2x.png b/Session/Meta/Images.xcassets/searchbar_search.imageset/UIButtonBarSearch_18x18_@2x.png similarity index 100% rename from Session/Images.xcassets/searchbar_search.imageset/UIButtonBarSearch_18x18_@2x.png rename to Session/Meta/Images.xcassets/searchbar_search.imageset/UIButtonBarSearch_18x18_@2x.png diff --git a/Session/Images.xcassets/searchbar_search.imageset/UIButtonBarSearch_18x18_@3x.png b/Session/Meta/Images.xcassets/searchbar_search.imageset/UIButtonBarSearch_18x18_@3x.png similarity index 100% rename from Session/Images.xcassets/searchbar_search.imageset/UIButtonBarSearch_18x18_@3x.png rename to Session/Meta/Images.xcassets/searchbar_search.imageset/UIButtonBarSearch_18x18_@3x.png diff --git a/Session/Images.xcassets/selected_blue_circle.imageset/BlueCheckSelected_31x31_@1x.png b/Session/Meta/Images.xcassets/selected_blue_circle.imageset/BlueCheckSelected_31x31_@1x.png similarity index 100% rename from Session/Images.xcassets/selected_blue_circle.imageset/BlueCheckSelected_31x31_@1x.png rename to Session/Meta/Images.xcassets/selected_blue_circle.imageset/BlueCheckSelected_31x31_@1x.png diff --git a/Session/Images.xcassets/selected_blue_circle.imageset/BlueCheckSelected_31x31_@2x.png b/Session/Meta/Images.xcassets/selected_blue_circle.imageset/BlueCheckSelected_31x31_@2x.png similarity index 100% rename from Session/Images.xcassets/selected_blue_circle.imageset/BlueCheckSelected_31x31_@2x.png rename to Session/Meta/Images.xcassets/selected_blue_circle.imageset/BlueCheckSelected_31x31_@2x.png diff --git a/Session/Images.xcassets/selected_blue_circle.imageset/BlueCheckSelected_31x31_@3x.png b/Session/Meta/Images.xcassets/selected_blue_circle.imageset/BlueCheckSelected_31x31_@3x.png similarity index 100% rename from Session/Images.xcassets/selected_blue_circle.imageset/BlueCheckSelected_31x31_@3x.png rename to Session/Meta/Images.xcassets/selected_blue_circle.imageset/BlueCheckSelected_31x31_@3x.png diff --git a/Session/Images.xcassets/selected_blue_circle.imageset/Contents.json b/Session/Meta/Images.xcassets/selected_blue_circle.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/selected_blue_circle.imageset/Contents.json rename to Session/Meta/Images.xcassets/selected_blue_circle.imageset/Contents.json diff --git a/Session/Images.xcassets/settings-avatar-camera-2.imageset/Contents.json b/Session/Meta/Images.xcassets/settings-avatar-camera-2.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/settings-avatar-camera-2.imageset/Contents.json rename to Session/Meta/Images.xcassets/settings-avatar-camera-2.imageset/Contents.json diff --git a/Session/Images.xcassets/settings-avatar-camera-2.imageset/camera-filled-24@1x.png b/Session/Meta/Images.xcassets/settings-avatar-camera-2.imageset/camera-filled-24@1x.png similarity index 100% rename from Session/Images.xcassets/settings-avatar-camera-2.imageset/camera-filled-24@1x.png rename to Session/Meta/Images.xcassets/settings-avatar-camera-2.imageset/camera-filled-24@1x.png diff --git a/Session/Images.xcassets/settings-avatar-camera-2.imageset/camera-filled-24@2x.png b/Session/Meta/Images.xcassets/settings-avatar-camera-2.imageset/camera-filled-24@2x.png similarity index 100% rename from Session/Images.xcassets/settings-avatar-camera-2.imageset/camera-filled-24@2x.png rename to Session/Meta/Images.xcassets/settings-avatar-camera-2.imageset/camera-filled-24@2x.png diff --git a/Session/Images.xcassets/settings-avatar-camera-2.imageset/camera-filled-24@3x.png b/Session/Meta/Images.xcassets/settings-avatar-camera-2.imageset/camera-filled-24@3x.png similarity index 100% rename from Session/Images.xcassets/settings-avatar-camera-2.imageset/camera-filled-24@3x.png rename to Session/Meta/Images.xcassets/settings-avatar-camera-2.imageset/camera-filled-24@3x.png diff --git a/Session/Images.xcassets/settings-avatar-camera.imageset/Contents.json b/Session/Meta/Images.xcassets/settings-avatar-camera.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/settings-avatar-camera.imageset/Contents.json rename to Session/Meta/Images.xcassets/settings-avatar-camera.imageset/Contents.json diff --git a/Session/Images.xcassets/settings-avatar-camera.imageset/settings-avatar-camera@1x.png b/Session/Meta/Images.xcassets/settings-avatar-camera.imageset/settings-avatar-camera@1x.png similarity index 100% rename from Session/Images.xcassets/settings-avatar-camera.imageset/settings-avatar-camera@1x.png rename to Session/Meta/Images.xcassets/settings-avatar-camera.imageset/settings-avatar-camera@1x.png diff --git a/Session/Images.xcassets/settings-avatar-camera.imageset/settings-avatar-camera@2x.png b/Session/Meta/Images.xcassets/settings-avatar-camera.imageset/settings-avatar-camera@2x.png similarity index 100% rename from Session/Images.xcassets/settings-avatar-camera.imageset/settings-avatar-camera@2x.png rename to Session/Meta/Images.xcassets/settings-avatar-camera.imageset/settings-avatar-camera@2x.png diff --git a/Session/Images.xcassets/settings-avatar-camera.imageset/settings-avatar-camera@3x.png b/Session/Meta/Images.xcassets/settings-avatar-camera.imageset/settings-avatar-camera@3x.png similarity index 100% rename from Session/Images.xcassets/settings-avatar-camera.imageset/settings-avatar-camera@3x.png rename to Session/Meta/Images.xcassets/settings-avatar-camera.imageset/settings-avatar-camera@3x.png diff --git a/Session/Images.xcassets/settings.imageset/Contents.json b/Session/Meta/Images.xcassets/settings.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/settings.imageset/Contents.json rename to Session/Meta/Images.xcassets/settings.imageset/Contents.json diff --git a/Session/Images.xcassets/settings.imageset/settings.pdf b/Session/Meta/Images.xcassets/settings.imageset/settings.pdf similarity index 100% rename from Session/Images.xcassets/settings.imageset/settings.pdf rename to Session/Meta/Images.xcassets/settings.imageset/settings.pdf diff --git a/Session/Images.xcassets/sliderProgressThumb.imageset/Contents.json b/Session/Meta/Images.xcassets/sliderProgressThumb.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/sliderProgressThumb.imageset/Contents.json rename to Session/Meta/Images.xcassets/sliderProgressThumb.imageset/Contents.json diff --git a/Session/Images.xcassets/sliderProgressThumb.imageset/VideoPlayer_Slider_Thumb_15x15_@1x.png b/Session/Meta/Images.xcassets/sliderProgressThumb.imageset/VideoPlayer_Slider_Thumb_15x15_@1x.png similarity index 100% rename from Session/Images.xcassets/sliderProgressThumb.imageset/VideoPlayer_Slider_Thumb_15x15_@1x.png rename to Session/Meta/Images.xcassets/sliderProgressThumb.imageset/VideoPlayer_Slider_Thumb_15x15_@1x.png diff --git a/Session/Images.xcassets/sliderProgressThumb.imageset/VideoPlayer_Slider_Thumb_15x15_@2x.png b/Session/Meta/Images.xcassets/sliderProgressThumb.imageset/VideoPlayer_Slider_Thumb_15x15_@2x.png similarity index 100% rename from Session/Images.xcassets/sliderProgressThumb.imageset/VideoPlayer_Slider_Thumb_15x15_@2x.png rename to Session/Meta/Images.xcassets/sliderProgressThumb.imageset/VideoPlayer_Slider_Thumb_15x15_@2x.png diff --git a/Session/Images.xcassets/sliderProgressThumb.imageset/VideoPlayer_Slider_Thumb_15x15_@3x.png b/Session/Meta/Images.xcassets/sliderProgressThumb.imageset/VideoPlayer_Slider_Thumb_15x15_@3x.png similarity index 100% rename from Session/Images.xcassets/sliderProgressThumb.imageset/VideoPlayer_Slider_Thumb_15x15_@3x.png rename to Session/Meta/Images.xcassets/sliderProgressThumb.imageset/VideoPlayer_Slider_Thumb_15x15_@3x.png diff --git a/Session/Images.xcassets/small_chevron_left.imageset/Contents.json b/Session/Meta/Images.xcassets/small_chevron_left.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/small_chevron_left.imageset/Contents.json rename to Session/Meta/Images.xcassets/small_chevron_left.imageset/Contents.json diff --git a/Session/Images.xcassets/small_chevron_left.imageset/chevron_left_16@1x.png b/Session/Meta/Images.xcassets/small_chevron_left.imageset/chevron_left_16@1x.png similarity index 100% rename from Session/Images.xcassets/small_chevron_left.imageset/chevron_left_16@1x.png rename to Session/Meta/Images.xcassets/small_chevron_left.imageset/chevron_left_16@1x.png diff --git a/Session/Images.xcassets/small_chevron_left.imageset/chevron_left_16@3x-1.png b/Session/Meta/Images.xcassets/small_chevron_left.imageset/chevron_left_16@3x-1.png similarity index 100% rename from Session/Images.xcassets/small_chevron_left.imageset/chevron_left_16@3x-1.png rename to Session/Meta/Images.xcassets/small_chevron_left.imageset/chevron_left_16@3x-1.png diff --git a/Session/Images.xcassets/small_chevron_left.imageset/chevron_left_16@3x.png b/Session/Meta/Images.xcassets/small_chevron_left.imageset/chevron_left_16@3x.png similarity index 100% rename from Session/Images.xcassets/small_chevron_left.imageset/chevron_left_16@3x.png rename to Session/Meta/Images.xcassets/small_chevron_left.imageset/chevron_left_16@3x.png diff --git a/Session/Images.xcassets/small_chevron_right.imageset/Contents.json b/Session/Meta/Images.xcassets/small_chevron_right.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/small_chevron_right.imageset/Contents.json rename to Session/Meta/Images.xcassets/small_chevron_right.imageset/Contents.json diff --git a/Session/Images.xcassets/small_chevron_right.imageset/chevron_right_16@1x.png b/Session/Meta/Images.xcassets/small_chevron_right.imageset/chevron_right_16@1x.png similarity index 100% rename from Session/Images.xcassets/small_chevron_right.imageset/chevron_right_16@1x.png rename to Session/Meta/Images.xcassets/small_chevron_right.imageset/chevron_right_16@1x.png diff --git a/Session/Images.xcassets/small_chevron_right.imageset/chevron_right_16@2x.png b/Session/Meta/Images.xcassets/small_chevron_right.imageset/chevron_right_16@2x.png similarity index 100% rename from Session/Images.xcassets/small_chevron_right.imageset/chevron_right_16@2x.png rename to Session/Meta/Images.xcassets/small_chevron_right.imageset/chevron_right_16@2x.png diff --git a/Session/Images.xcassets/small_chevron_right.imageset/chevron_right_16@3x.png b/Session/Meta/Images.xcassets/small_chevron_right.imageset/chevron_right_16@3x.png similarity index 100% rename from Session/Images.xcassets/small_chevron_right.imageset/chevron_right_16@3x.png rename to Session/Meta/Images.xcassets/small_chevron_right.imageset/chevron_right_16@3x.png diff --git a/Session/Images.xcassets/statJoinedGroup--blue.imageset/Contents.json b/Session/Meta/Images.xcassets/statJoinedGroup--blue.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/statJoinedGroup--blue.imageset/Contents.json rename to Session/Meta/Images.xcassets/statJoinedGroup--blue.imageset/Contents.json diff --git a/Session/Images.xcassets/statJoinedGroup--blue.imageset/statJoinedGroup--blue.pdf b/Session/Meta/Images.xcassets/statJoinedGroup--blue.imageset/statJoinedGroup--blue.pdf similarity index 100% rename from Session/Images.xcassets/statJoinedGroup--blue.imageset/statJoinedGroup--blue.pdf rename to Session/Meta/Images.xcassets/statJoinedGroup--blue.imageset/statJoinedGroup--blue.pdf diff --git a/Session/Images.xcassets/statLeftGroup--blue.imageset/Contents.json b/Session/Meta/Images.xcassets/statLeftGroup--blue.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/statLeftGroup--blue.imageset/Contents.json rename to Session/Meta/Images.xcassets/statLeftGroup--blue.imageset/Contents.json diff --git a/Session/Images.xcassets/statLeftGroup--blue.imageset/statLeftGroup--blue.pdf b/Session/Meta/Images.xcassets/statLeftGroup--blue.imageset/statLeftGroup--blue.pdf similarity index 100% rename from Session/Images.xcassets/statLeftGroup--blue.imageset/statLeftGroup--blue.pdf rename to Session/Meta/Images.xcassets/statLeftGroup--blue.imageset/statLeftGroup--blue.pdf diff --git a/Session/Images.xcassets/statRefreshedGroup--blue.imageset/Contents.json b/Session/Meta/Images.xcassets/statRefreshedGroup--blue.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/statRefreshedGroup--blue.imageset/Contents.json rename to Session/Meta/Images.xcassets/statRefreshedGroup--blue.imageset/Contents.json diff --git a/Session/Images.xcassets/statRefreshedGroup--blue.imageset/statRefreshedGroup--blue.pdf b/Session/Meta/Images.xcassets/statRefreshedGroup--blue.imageset/statRefreshedGroup--blue.pdf similarity index 100% rename from Session/Images.xcassets/statRefreshedGroup--blue.imageset/statRefreshedGroup--blue.pdf rename to Session/Meta/Images.xcassets/statRefreshedGroup--blue.imageset/statRefreshedGroup--blue.pdf diff --git a/Session/Images.xcassets/system_disclosure_indicator.imageset/Contents.json b/Session/Meta/Images.xcassets/system_disclosure_indicator.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/system_disclosure_indicator.imageset/Contents.json rename to Session/Meta/Images.xcassets/system_disclosure_indicator.imageset/Contents.json diff --git a/Session/Images.xcassets/system_disclosure_indicator.imageset/DisclosureIndicator@1x.png b/Session/Meta/Images.xcassets/system_disclosure_indicator.imageset/DisclosureIndicator@1x.png similarity index 100% rename from Session/Images.xcassets/system_disclosure_indicator.imageset/DisclosureIndicator@1x.png rename to Session/Meta/Images.xcassets/system_disclosure_indicator.imageset/DisclosureIndicator@1x.png diff --git a/Session/Images.xcassets/system_disclosure_indicator.imageset/DisclosureIndicator@2x.png b/Session/Meta/Images.xcassets/system_disclosure_indicator.imageset/DisclosureIndicator@2x.png similarity index 100% rename from Session/Images.xcassets/system_disclosure_indicator.imageset/DisclosureIndicator@2x.png rename to Session/Meta/Images.xcassets/system_disclosure_indicator.imageset/DisclosureIndicator@2x.png diff --git a/Session/Images.xcassets/system_disclosure_indicator.imageset/DisclosureIndicator@3x.png b/Session/Meta/Images.xcassets/system_disclosure_indicator.imageset/DisclosureIndicator@3x.png similarity index 100% rename from Session/Images.xcassets/system_disclosure_indicator.imageset/DisclosureIndicator@3x.png rename to Session/Meta/Images.xcassets/system_disclosure_indicator.imageset/DisclosureIndicator@3x.png diff --git a/Session/Images.xcassets/system_disclosure_indicator_rtl.imageset/Contents.json b/Session/Meta/Images.xcassets/system_disclosure_indicator_rtl.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/system_disclosure_indicator_rtl.imageset/Contents.json rename to Session/Meta/Images.xcassets/system_disclosure_indicator_rtl.imageset/Contents.json diff --git a/Session/Images.xcassets/system_disclosure_indicator_rtl.imageset/DisclosureIndicatorRTL@1x.png b/Session/Meta/Images.xcassets/system_disclosure_indicator_rtl.imageset/DisclosureIndicatorRTL@1x.png similarity index 100% rename from Session/Images.xcassets/system_disclosure_indicator_rtl.imageset/DisclosureIndicatorRTL@1x.png rename to Session/Meta/Images.xcassets/system_disclosure_indicator_rtl.imageset/DisclosureIndicatorRTL@1x.png diff --git a/Session/Images.xcassets/system_disclosure_indicator_rtl.imageset/DisclosureIndicatorRTL@2x.png b/Session/Meta/Images.xcassets/system_disclosure_indicator_rtl.imageset/DisclosureIndicatorRTL@2x.png similarity index 100% rename from Session/Images.xcassets/system_disclosure_indicator_rtl.imageset/DisclosureIndicatorRTL@2x.png rename to Session/Meta/Images.xcassets/system_disclosure_indicator_rtl.imageset/DisclosureIndicatorRTL@2x.png diff --git a/Session/Images.xcassets/system_disclosure_indicator_rtl.imageset/DisclosureIndicatorRTL@3x.png b/Session/Meta/Images.xcassets/system_disclosure_indicator_rtl.imageset/DisclosureIndicatorRTL@3x.png similarity index 100% rename from Session/Images.xcassets/system_disclosure_indicator_rtl.imageset/DisclosureIndicatorRTL@3x.png rename to Session/Meta/Images.xcassets/system_disclosure_indicator_rtl.imageset/DisclosureIndicatorRTL@3x.png diff --git a/Session/Images.xcassets/system_message_call.imageset/Contents.json b/Session/Meta/Images.xcassets/system_message_call.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/system_message_call.imageset/Contents.json rename to Session/Meta/Images.xcassets/system_message_call.imageset/Contents.json diff --git a/Session/Images.xcassets/system_message_call.imageset/system_message_call@1x.png b/Session/Meta/Images.xcassets/system_message_call.imageset/system_message_call@1x.png similarity index 100% rename from Session/Images.xcassets/system_message_call.imageset/system_message_call@1x.png rename to Session/Meta/Images.xcassets/system_message_call.imageset/system_message_call@1x.png diff --git a/Session/Images.xcassets/system_message_call.imageset/system_message_call@2x.png b/Session/Meta/Images.xcassets/system_message_call.imageset/system_message_call@2x.png similarity index 100% rename from Session/Images.xcassets/system_message_call.imageset/system_message_call@2x.png rename to Session/Meta/Images.xcassets/system_message_call.imageset/system_message_call@2x.png diff --git a/Session/Images.xcassets/system_message_call.imageset/system_message_call@3x.png b/Session/Meta/Images.xcassets/system_message_call.imageset/system_message_call@3x.png similarity index 100% rename from Session/Images.xcassets/system_message_call.imageset/system_message_call@3x.png rename to Session/Meta/Images.xcassets/system_message_call.imageset/system_message_call@3x.png diff --git a/Session/Images.xcassets/system_message_disappearing_messages.imageset/Contents.json b/Session/Meta/Images.xcassets/system_message_disappearing_messages.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/system_message_disappearing_messages.imageset/Contents.json rename to Session/Meta/Images.xcassets/system_message_disappearing_messages.imageset/Contents.json diff --git a/Session/Images.xcassets/system_message_disappearing_messages.imageset/timer-20@1x.png b/Session/Meta/Images.xcassets/system_message_disappearing_messages.imageset/timer-20@1x.png similarity index 100% rename from Session/Images.xcassets/system_message_disappearing_messages.imageset/timer-20@1x.png rename to Session/Meta/Images.xcassets/system_message_disappearing_messages.imageset/timer-20@1x.png diff --git a/Session/Images.xcassets/system_message_disappearing_messages.imageset/timer-20@2x.png b/Session/Meta/Images.xcassets/system_message_disappearing_messages.imageset/timer-20@2x.png similarity index 100% rename from Session/Images.xcassets/system_message_disappearing_messages.imageset/timer-20@2x.png rename to Session/Meta/Images.xcassets/system_message_disappearing_messages.imageset/timer-20@2x.png diff --git a/Session/Images.xcassets/system_message_disappearing_messages.imageset/timer-20@3x.png b/Session/Meta/Images.xcassets/system_message_disappearing_messages.imageset/timer-20@3x.png similarity index 100% rename from Session/Images.xcassets/system_message_disappearing_messages.imageset/timer-20@3x.png rename to Session/Meta/Images.xcassets/system_message_disappearing_messages.imageset/timer-20@3x.png diff --git a/Session/Images.xcassets/system_message_disappearing_messages_disabled.imageset/Contents.json b/Session/Meta/Images.xcassets/system_message_disappearing_messages_disabled.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/system_message_disappearing_messages_disabled.imageset/Contents.json rename to Session/Meta/Images.xcassets/system_message_disappearing_messages_disabled.imageset/Contents.json diff --git a/Session/Images.xcassets/system_message_disappearing_messages_disabled.imageset/timer-disabled-20@1x.png b/Session/Meta/Images.xcassets/system_message_disappearing_messages_disabled.imageset/timer-disabled-20@1x.png similarity index 100% rename from Session/Images.xcassets/system_message_disappearing_messages_disabled.imageset/timer-disabled-20@1x.png rename to Session/Meta/Images.xcassets/system_message_disappearing_messages_disabled.imageset/timer-disabled-20@1x.png diff --git a/Session/Images.xcassets/system_message_disappearing_messages_disabled.imageset/timer-disabled-20@2x.png b/Session/Meta/Images.xcassets/system_message_disappearing_messages_disabled.imageset/timer-disabled-20@2x.png similarity index 100% rename from Session/Images.xcassets/system_message_disappearing_messages_disabled.imageset/timer-disabled-20@2x.png rename to Session/Meta/Images.xcassets/system_message_disappearing_messages_disabled.imageset/timer-disabled-20@2x.png diff --git a/Session/Images.xcassets/system_message_disappearing_messages_disabled.imageset/timer-disabled-20@3x.png b/Session/Meta/Images.xcassets/system_message_disappearing_messages_disabled.imageset/timer-disabled-20@3x.png similarity index 100% rename from Session/Images.xcassets/system_message_disappearing_messages_disabled.imageset/timer-disabled-20@3x.png rename to Session/Meta/Images.xcassets/system_message_disappearing_messages_disabled.imageset/timer-disabled-20@3x.png diff --git a/Session/Images.xcassets/system_message_security.imageset/Contents.json b/Session/Meta/Images.xcassets/system_message_security.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/system_message_security.imageset/Contents.json rename to Session/Meta/Images.xcassets/system_message_security.imageset/Contents.json diff --git a/Session/Images.xcassets/system_message_security.imageset/system_message_security@1x.png b/Session/Meta/Images.xcassets/system_message_security.imageset/system_message_security@1x.png similarity index 100% rename from Session/Images.xcassets/system_message_security.imageset/system_message_security@1x.png rename to Session/Meta/Images.xcassets/system_message_security.imageset/system_message_security@1x.png diff --git a/Session/Images.xcassets/system_message_security.imageset/system_message_security@2x.png b/Session/Meta/Images.xcassets/system_message_security.imageset/system_message_security@2x.png similarity index 100% rename from Session/Images.xcassets/system_message_security.imageset/system_message_security@2x.png rename to Session/Meta/Images.xcassets/system_message_security.imageset/system_message_security@2x.png diff --git a/Session/Images.xcassets/system_message_security.imageset/system_message_security@3x.png b/Session/Meta/Images.xcassets/system_message_security.imageset/system_message_security@3x.png similarity index 100% rename from Session/Images.xcassets/system_message_security.imageset/system_message_security@3x.png rename to Session/Meta/Images.xcassets/system_message_security.imageset/system_message_security@3x.png diff --git a/Session/Images.xcassets/system_message_verified.imageset/Contents.json b/Session/Meta/Images.xcassets/system_message_verified.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/system_message_verified.imageset/Contents.json rename to Session/Meta/Images.xcassets/system_message_verified.imageset/Contents.json diff --git a/Session/Images.xcassets/system_message_verified.imageset/system_message_verified@1x.png b/Session/Meta/Images.xcassets/system_message_verified.imageset/system_message_verified@1x.png similarity index 100% rename from Session/Images.xcassets/system_message_verified.imageset/system_message_verified@1x.png rename to Session/Meta/Images.xcassets/system_message_verified.imageset/system_message_verified@1x.png diff --git a/Session/Images.xcassets/system_message_verified.imageset/system_message_verified@2x.png b/Session/Meta/Images.xcassets/system_message_verified.imageset/system_message_verified@2x.png similarity index 100% rename from Session/Images.xcassets/system_message_verified.imageset/system_message_verified@2x.png rename to Session/Meta/Images.xcassets/system_message_verified.imageset/system_message_verified@2x.png diff --git a/Session/Images.xcassets/system_message_verified.imageset/system_message_verified@3x.png b/Session/Meta/Images.xcassets/system_message_verified.imageset/system_message_verified@3x.png similarity index 100% rename from Session/Images.xcassets/system_message_verified.imageset/system_message_verified@3x.png rename to Session/Meta/Images.xcassets/system_message_verified.imageset/system_message_verified@3x.png diff --git a/Session/Images.xcassets/table_ic_add_to_existing_contact.imageset/Contents.json b/Session/Meta/Images.xcassets/table_ic_add_to_existing_contact.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/table_ic_add_to_existing_contact.imageset/Contents.json rename to Session/Meta/Images.xcassets/table_ic_add_to_existing_contact.imageset/Contents.json diff --git a/Session/Images.xcassets/table_ic_add_to_existing_contact.imageset/table_ic_add_to_existing_contact@1x.png b/Session/Meta/Images.xcassets/table_ic_add_to_existing_contact.imageset/table_ic_add_to_existing_contact@1x.png similarity index 100% rename from Session/Images.xcassets/table_ic_add_to_existing_contact.imageset/table_ic_add_to_existing_contact@1x.png rename to Session/Meta/Images.xcassets/table_ic_add_to_existing_contact.imageset/table_ic_add_to_existing_contact@1x.png diff --git a/Session/Images.xcassets/table_ic_add_to_existing_contact.imageset/table_ic_add_to_existing_contact@2x.png b/Session/Meta/Images.xcassets/table_ic_add_to_existing_contact.imageset/table_ic_add_to_existing_contact@2x.png similarity index 100% rename from Session/Images.xcassets/table_ic_add_to_existing_contact.imageset/table_ic_add_to_existing_contact@2x.png rename to Session/Meta/Images.xcassets/table_ic_add_to_existing_contact.imageset/table_ic_add_to_existing_contact@2x.png diff --git a/Session/Images.xcassets/table_ic_add_to_existing_contact.imageset/table_ic_add_to_existing_contact@3x.png b/Session/Meta/Images.xcassets/table_ic_add_to_existing_contact.imageset/table_ic_add_to_existing_contact@3x.png similarity index 100% rename from Session/Images.xcassets/table_ic_add_to_existing_contact.imageset/table_ic_add_to_existing_contact@3x.png rename to Session/Meta/Images.xcassets/table_ic_add_to_existing_contact.imageset/table_ic_add_to_existing_contact@3x.png diff --git a/Session/Images.xcassets/table_ic_block.imageset/Contents.json b/Session/Meta/Images.xcassets/table_ic_block.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/table_ic_block.imageset/Contents.json rename to Session/Meta/Images.xcassets/table_ic_block.imageset/Contents.json diff --git a/Session/Images.xcassets/table_ic_block.imageset/table_ic_block@1x.png b/Session/Meta/Images.xcassets/table_ic_block.imageset/table_ic_block@1x.png similarity index 100% rename from Session/Images.xcassets/table_ic_block.imageset/table_ic_block@1x.png rename to Session/Meta/Images.xcassets/table_ic_block.imageset/table_ic_block@1x.png diff --git a/Session/Images.xcassets/table_ic_block.imageset/table_ic_block@2x.png b/Session/Meta/Images.xcassets/table_ic_block.imageset/table_ic_block@2x.png similarity index 100% rename from Session/Images.xcassets/table_ic_block.imageset/table_ic_block@2x.png rename to Session/Meta/Images.xcassets/table_ic_block.imageset/table_ic_block@2x.png diff --git a/Session/Images.xcassets/table_ic_block.imageset/table_ic_block@3x.png b/Session/Meta/Images.xcassets/table_ic_block.imageset/table_ic_block@3x.png similarity index 100% rename from Session/Images.xcassets/table_ic_block.imageset/table_ic_block@3x.png rename to Session/Meta/Images.xcassets/table_ic_block.imageset/table_ic_block@3x.png diff --git a/Session/Images.xcassets/table_ic_group_edit.imageset/Contents.json b/Session/Meta/Images.xcassets/table_ic_group_edit.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/table_ic_group_edit.imageset/Contents.json rename to Session/Meta/Images.xcassets/table_ic_group_edit.imageset/Contents.json diff --git a/Session/Images.xcassets/table_ic_group_edit.imageset/table_ic_group_edit@1x.png b/Session/Meta/Images.xcassets/table_ic_group_edit.imageset/table_ic_group_edit@1x.png similarity index 100% rename from Session/Images.xcassets/table_ic_group_edit.imageset/table_ic_group_edit@1x.png rename to Session/Meta/Images.xcassets/table_ic_group_edit.imageset/table_ic_group_edit@1x.png diff --git a/Session/Images.xcassets/table_ic_group_edit.imageset/table_ic_group_edit@2x.png b/Session/Meta/Images.xcassets/table_ic_group_edit.imageset/table_ic_group_edit@2x.png similarity index 100% rename from Session/Images.xcassets/table_ic_group_edit.imageset/table_ic_group_edit@2x.png rename to Session/Meta/Images.xcassets/table_ic_group_edit.imageset/table_ic_group_edit@2x.png diff --git a/Session/Images.xcassets/table_ic_group_edit.imageset/table_ic_group_edit@3x.png b/Session/Meta/Images.xcassets/table_ic_group_edit.imageset/table_ic_group_edit@3x.png similarity index 100% rename from Session/Images.xcassets/table_ic_group_edit.imageset/table_ic_group_edit@3x.png rename to Session/Meta/Images.xcassets/table_ic_group_edit.imageset/table_ic_group_edit@3x.png diff --git a/Session/Images.xcassets/table_ic_group_leave.imageset/Contents.json b/Session/Meta/Images.xcassets/table_ic_group_leave.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/table_ic_group_leave.imageset/Contents.json rename to Session/Meta/Images.xcassets/table_ic_group_leave.imageset/Contents.json diff --git a/Session/Images.xcassets/table_ic_group_leave.imageset/table_ic_group_leave@1x.png b/Session/Meta/Images.xcassets/table_ic_group_leave.imageset/table_ic_group_leave@1x.png similarity index 100% rename from Session/Images.xcassets/table_ic_group_leave.imageset/table_ic_group_leave@1x.png rename to Session/Meta/Images.xcassets/table_ic_group_leave.imageset/table_ic_group_leave@1x.png diff --git a/Session/Images.xcassets/table_ic_group_leave.imageset/table_ic_group_leave@2x.png b/Session/Meta/Images.xcassets/table_ic_group_leave.imageset/table_ic_group_leave@2x.png similarity index 100% rename from Session/Images.xcassets/table_ic_group_leave.imageset/table_ic_group_leave@2x.png rename to Session/Meta/Images.xcassets/table_ic_group_leave.imageset/table_ic_group_leave@2x.png diff --git a/Session/Images.xcassets/table_ic_group_leave.imageset/table_ic_group_leave@3x.png b/Session/Meta/Images.xcassets/table_ic_group_leave.imageset/table_ic_group_leave@3x.png similarity index 100% rename from Session/Images.xcassets/table_ic_group_leave.imageset/table_ic_group_leave@3x.png rename to Session/Meta/Images.xcassets/table_ic_group_leave.imageset/table_ic_group_leave@3x.png diff --git a/Session/Images.xcassets/table_ic_group_members.imageset/Contents.json b/Session/Meta/Images.xcassets/table_ic_group_members.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/table_ic_group_members.imageset/Contents.json rename to Session/Meta/Images.xcassets/table_ic_group_members.imageset/Contents.json diff --git a/Session/Images.xcassets/table_ic_group_members.imageset/table_ic_group_members@1x.png b/Session/Meta/Images.xcassets/table_ic_group_members.imageset/table_ic_group_members@1x.png similarity index 100% rename from Session/Images.xcassets/table_ic_group_members.imageset/table_ic_group_members@1x.png rename to Session/Meta/Images.xcassets/table_ic_group_members.imageset/table_ic_group_members@1x.png diff --git a/Session/Images.xcassets/table_ic_group_members.imageset/table_ic_group_members@2x.png b/Session/Meta/Images.xcassets/table_ic_group_members.imageset/table_ic_group_members@2x.png similarity index 100% rename from Session/Images.xcassets/table_ic_group_members.imageset/table_ic_group_members@2x.png rename to Session/Meta/Images.xcassets/table_ic_group_members.imageset/table_ic_group_members@2x.png diff --git a/Session/Images.xcassets/table_ic_group_members.imageset/table_ic_group_members@3x.png b/Session/Meta/Images.xcassets/table_ic_group_members.imageset/table_ic_group_members@3x.png similarity index 100% rename from Session/Images.xcassets/table_ic_group_members.imageset/table_ic_group_members@3x.png rename to Session/Meta/Images.xcassets/table_ic_group_members.imageset/table_ic_group_members@3x.png diff --git a/Session/Images.xcassets/table_ic_mute_thread.imageset/Contents.json b/Session/Meta/Images.xcassets/table_ic_mute_thread.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/table_ic_mute_thread.imageset/Contents.json rename to Session/Meta/Images.xcassets/table_ic_mute_thread.imageset/Contents.json diff --git a/Session/Images.xcassets/table_ic_mute_thread.imageset/table_ic_mute_thread@1x.png b/Session/Meta/Images.xcassets/table_ic_mute_thread.imageset/table_ic_mute_thread@1x.png similarity index 100% rename from Session/Images.xcassets/table_ic_mute_thread.imageset/table_ic_mute_thread@1x.png rename to Session/Meta/Images.xcassets/table_ic_mute_thread.imageset/table_ic_mute_thread@1x.png diff --git a/Session/Images.xcassets/table_ic_mute_thread.imageset/table_ic_mute_thread@2x.png b/Session/Meta/Images.xcassets/table_ic_mute_thread.imageset/table_ic_mute_thread@2x.png similarity index 100% rename from Session/Images.xcassets/table_ic_mute_thread.imageset/table_ic_mute_thread@2x.png rename to Session/Meta/Images.xcassets/table_ic_mute_thread.imageset/table_ic_mute_thread@2x.png diff --git a/Session/Images.xcassets/table_ic_mute_thread.imageset/table_ic_mute_thread@3x.png b/Session/Meta/Images.xcassets/table_ic_mute_thread.imageset/table_ic_mute_thread@3x.png similarity index 100% rename from Session/Images.xcassets/table_ic_mute_thread.imageset/table_ic_mute_thread@3x.png rename to Session/Meta/Images.xcassets/table_ic_mute_thread.imageset/table_ic_mute_thread@3x.png diff --git a/Session/Images.xcassets/table_ic_new_contact.imageset/Contents.json b/Session/Meta/Images.xcassets/table_ic_new_contact.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/table_ic_new_contact.imageset/Contents.json rename to Session/Meta/Images.xcassets/table_ic_new_contact.imageset/Contents.json diff --git a/Session/Images.xcassets/table_ic_new_contact.imageset/table_ic_new_contact@1x.png b/Session/Meta/Images.xcassets/table_ic_new_contact.imageset/table_ic_new_contact@1x.png similarity index 100% rename from Session/Images.xcassets/table_ic_new_contact.imageset/table_ic_new_contact@1x.png rename to Session/Meta/Images.xcassets/table_ic_new_contact.imageset/table_ic_new_contact@1x.png diff --git a/Session/Images.xcassets/table_ic_new_contact.imageset/table_ic_new_contact@2x.png b/Session/Meta/Images.xcassets/table_ic_new_contact.imageset/table_ic_new_contact@2x.png similarity index 100% rename from Session/Images.xcassets/table_ic_new_contact.imageset/table_ic_new_contact@2x.png rename to Session/Meta/Images.xcassets/table_ic_new_contact.imageset/table_ic_new_contact@2x.png diff --git a/Session/Images.xcassets/table_ic_new_contact.imageset/table_ic_new_contact@3x.png b/Session/Meta/Images.xcassets/table_ic_new_contact.imageset/table_ic_new_contact@3x.png similarity index 100% rename from Session/Images.xcassets/table_ic_new_contact.imageset/table_ic_new_contact@3x.png rename to Session/Meta/Images.xcassets/table_ic_new_contact.imageset/table_ic_new_contact@3x.png diff --git a/Session/Images.xcassets/table_ic_not_verified.imageset/Contents.json b/Session/Meta/Images.xcassets/table_ic_not_verified.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/table_ic_not_verified.imageset/Contents.json rename to Session/Meta/Images.xcassets/table_ic_not_verified.imageset/Contents.json diff --git a/Session/Images.xcassets/table_ic_not_verified.imageset/table_ic_not_verified@1x.png b/Session/Meta/Images.xcassets/table_ic_not_verified.imageset/table_ic_not_verified@1x.png similarity index 100% rename from Session/Images.xcassets/table_ic_not_verified.imageset/table_ic_not_verified@1x.png rename to Session/Meta/Images.xcassets/table_ic_not_verified.imageset/table_ic_not_verified@1x.png diff --git a/Session/Images.xcassets/table_ic_not_verified.imageset/table_ic_not_verified@2x.png b/Session/Meta/Images.xcassets/table_ic_not_verified.imageset/table_ic_not_verified@2x.png similarity index 100% rename from Session/Images.xcassets/table_ic_not_verified.imageset/table_ic_not_verified@2x.png rename to Session/Meta/Images.xcassets/table_ic_not_verified.imageset/table_ic_not_verified@2x.png diff --git a/Session/Images.xcassets/table_ic_not_verified.imageset/table_ic_not_verified@3x.png b/Session/Meta/Images.xcassets/table_ic_not_verified.imageset/table_ic_not_verified@3x.png similarity index 100% rename from Session/Images.xcassets/table_ic_not_verified.imageset/table_ic_not_verified@3x.png rename to Session/Meta/Images.xcassets/table_ic_not_verified.imageset/table_ic_not_verified@3x.png diff --git a/Session/Images.xcassets/table_ic_notification_sound.imageset/Contents.json b/Session/Meta/Images.xcassets/table_ic_notification_sound.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/table_ic_notification_sound.imageset/Contents.json rename to Session/Meta/Images.xcassets/table_ic_notification_sound.imageset/Contents.json diff --git a/Session/Images.xcassets/table_ic_notification_sound.imageset/table_ic_notification_sound@1x.png b/Session/Meta/Images.xcassets/table_ic_notification_sound.imageset/table_ic_notification_sound@1x.png similarity index 100% rename from Session/Images.xcassets/table_ic_notification_sound.imageset/table_ic_notification_sound@1x.png rename to Session/Meta/Images.xcassets/table_ic_notification_sound.imageset/table_ic_notification_sound@1x.png diff --git a/Session/Images.xcassets/table_ic_notification_sound.imageset/table_ic_notification_sound@2x.png b/Session/Meta/Images.xcassets/table_ic_notification_sound.imageset/table_ic_notification_sound@2x.png similarity index 100% rename from Session/Images.xcassets/table_ic_notification_sound.imageset/table_ic_notification_sound@2x.png rename to Session/Meta/Images.xcassets/table_ic_notification_sound.imageset/table_ic_notification_sound@2x.png diff --git a/Session/Images.xcassets/table_ic_notification_sound.imageset/table_ic_notification_sound@3x.png b/Session/Meta/Images.xcassets/table_ic_notification_sound.imageset/table_ic_notification_sound@3x.png similarity index 100% rename from Session/Images.xcassets/table_ic_notification_sound.imageset/table_ic_notification_sound@3x.png rename to Session/Meta/Images.xcassets/table_ic_notification_sound.imageset/table_ic_notification_sound@3x.png diff --git a/Session/Images.xcassets/table_ic_share_profile.imageset/Contents.json b/Session/Meta/Images.xcassets/table_ic_share_profile.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/table_ic_share_profile.imageset/Contents.json rename to Session/Meta/Images.xcassets/table_ic_share_profile.imageset/Contents.json diff --git a/Session/Images.xcassets/table_ic_share_profile.imageset/table_ic_share_profile@1x.png b/Session/Meta/Images.xcassets/table_ic_share_profile.imageset/table_ic_share_profile@1x.png similarity index 100% rename from Session/Images.xcassets/table_ic_share_profile.imageset/table_ic_share_profile@1x.png rename to Session/Meta/Images.xcassets/table_ic_share_profile.imageset/table_ic_share_profile@1x.png diff --git a/Session/Images.xcassets/table_ic_share_profile.imageset/table_ic_share_profile@2x.png b/Session/Meta/Images.xcassets/table_ic_share_profile.imageset/table_ic_share_profile@2x.png similarity index 100% rename from Session/Images.xcassets/table_ic_share_profile.imageset/table_ic_share_profile@2x.png rename to Session/Meta/Images.xcassets/table_ic_share_profile.imageset/table_ic_share_profile@2x.png diff --git a/Session/Images.xcassets/table_ic_share_profile.imageset/table_ic_share_profile@3x.png b/Session/Meta/Images.xcassets/table_ic_share_profile.imageset/table_ic_share_profile@3x.png similarity index 100% rename from Session/Images.xcassets/table_ic_share_profile.imageset/table_ic_share_profile@3x.png rename to Session/Meta/Images.xcassets/table_ic_share_profile.imageset/table_ic_share_profile@3x.png diff --git a/Session/Images.xcassets/table_ic_verify.imageset/Contents.json b/Session/Meta/Images.xcassets/table_ic_verify.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/table_ic_verify.imageset/Contents.json rename to Session/Meta/Images.xcassets/table_ic_verify.imageset/Contents.json diff --git a/Session/Images.xcassets/table_ic_verify.imageset/table_ic_verify@1x.png b/Session/Meta/Images.xcassets/table_ic_verify.imageset/table_ic_verify@1x.png similarity index 100% rename from Session/Images.xcassets/table_ic_verify.imageset/table_ic_verify@1x.png rename to Session/Meta/Images.xcassets/table_ic_verify.imageset/table_ic_verify@1x.png diff --git a/Session/Images.xcassets/table_ic_verify.imageset/table_ic_verify@2x.png b/Session/Meta/Images.xcassets/table_ic_verify.imageset/table_ic_verify@2x.png similarity index 100% rename from Session/Images.xcassets/table_ic_verify.imageset/table_ic_verify@2x.png rename to Session/Meta/Images.xcassets/table_ic_verify.imageset/table_ic_verify@2x.png diff --git a/Session/Images.xcassets/table_ic_verify.imageset/table_ic_verify@3x.png b/Session/Meta/Images.xcassets/table_ic_verify.imageset/table_ic_verify@3x.png similarity index 100% rename from Session/Images.xcassets/table_ic_verify.imageset/table_ic_verify@3x.png rename to Session/Meta/Images.xcassets/table_ic_verify.imageset/table_ic_verify@3x.png diff --git a/Session/Images.xcassets/twitter_logo.imageset/Contents.json b/Session/Meta/Images.xcassets/twitter_logo.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/twitter_logo.imageset/Contents.json rename to Session/Meta/Images.xcassets/twitter_logo.imageset/Contents.json diff --git a/Session/Images.xcassets/twitter_logo.imageset/twitter_logo.pdf b/Session/Meta/Images.xcassets/twitter_logo.imageset/twitter_logo.pdf similarity index 100% rename from Session/Images.xcassets/twitter_logo.imageset/twitter_logo.pdf rename to Session/Meta/Images.xcassets/twitter_logo.imageset/twitter_logo.pdf diff --git a/Session/Images.xcassets/twitter_sharing_image.imageset/Contents.json b/Session/Meta/Images.xcassets/twitter_sharing_image.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/twitter_sharing_image.imageset/Contents.json rename to Session/Meta/Images.xcassets/twitter_sharing_image.imageset/Contents.json diff --git a/Session/Images.xcassets/twitter_sharing_image.imageset/logo_with_background.png b/Session/Meta/Images.xcassets/twitter_sharing_image.imageset/logo_with_background.png similarity index 100% rename from Session/Images.xcassets/twitter_sharing_image.imageset/logo_with_background.png rename to Session/Meta/Images.xcassets/twitter_sharing_image.imageset/logo_with_background.png diff --git a/Session/Images.xcassets/twitter_sharing_image.imageset/logo_with_background@2x.png b/Session/Meta/Images.xcassets/twitter_sharing_image.imageset/logo_with_background@2x.png similarity index 100% rename from Session/Images.xcassets/twitter_sharing_image.imageset/logo_with_background@2x.png rename to Session/Meta/Images.xcassets/twitter_sharing_image.imageset/logo_with_background@2x.png diff --git a/Session/Images.xcassets/twitter_sharing_image.imageset/logo_with_background@3x.png b/Session/Meta/Images.xcassets/twitter_sharing_image.imageset/logo_with_background@3x.png similarity index 100% rename from Session/Images.xcassets/twitter_sharing_image.imageset/logo_with_background@3x.png rename to Session/Meta/Images.xcassets/twitter_sharing_image.imageset/logo_with_background@3x.png diff --git a/Session/Images.xcassets/uiEmpty.imageset/Contents.json b/Session/Meta/Images.xcassets/uiEmpty.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/uiEmpty.imageset/Contents.json rename to Session/Meta/Images.xcassets/uiEmpty.imageset/Contents.json diff --git a/Session/Images.xcassets/uiEmpty.imageset/uiEmpty.pdf b/Session/Meta/Images.xcassets/uiEmpty.imageset/uiEmpty.pdf similarity index 100% rename from Session/Images.xcassets/uiEmpty.imageset/uiEmpty.pdf rename to Session/Meta/Images.xcassets/uiEmpty.imageset/uiEmpty.pdf diff --git a/Session/Images.xcassets/uiEmptyContact.imageset/Contents.json b/Session/Meta/Images.xcassets/uiEmptyContact.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/uiEmptyContact.imageset/Contents.json rename to Session/Meta/Images.xcassets/uiEmptyContact.imageset/Contents.json diff --git a/Session/Images.xcassets/uiEmptyContact.imageset/uiEmptyContact.pdf b/Session/Meta/Images.xcassets/uiEmptyContact.imageset/uiEmptyContact.pdf similarity index 100% rename from Session/Images.xcassets/uiEmptyContact.imageset/uiEmptyContact.pdf rename to Session/Meta/Images.xcassets/uiEmptyContact.imageset/uiEmptyContact.pdf diff --git a/Session/Images.xcassets/video-mute-selected.imageset/Contents.json b/Session/Meta/Images.xcassets/video-mute-selected.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/video-mute-selected.imageset/Contents.json rename to Session/Meta/Images.xcassets/video-mute-selected.imageset/Contents.json diff --git a/Session/Images.xcassets/video-mute-selected.imageset/video-mute-selected.png b/Session/Meta/Images.xcassets/video-mute-selected.imageset/video-mute-selected.png similarity index 100% rename from Session/Images.xcassets/video-mute-selected.imageset/video-mute-selected.png rename to Session/Meta/Images.xcassets/video-mute-selected.imageset/video-mute-selected.png diff --git a/Session/Images.xcassets/video-mute-unselected.imageset/Contents.json b/Session/Meta/Images.xcassets/video-mute-unselected.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/video-mute-unselected.imageset/Contents.json rename to Session/Meta/Images.xcassets/video-mute-unselected.imageset/Contents.json diff --git a/Session/Images.xcassets/video-mute-unselected.imageset/video-mute-unselected.png b/Session/Meta/Images.xcassets/video-mute-unselected.imageset/video-mute-unselected.png similarity index 100% rename from Session/Images.xcassets/video-mute-unselected.imageset/video-mute-unselected.png rename to Session/Meta/Images.xcassets/video-mute-unselected.imageset/video-mute-unselected.png diff --git a/Session/Images.xcassets/video-switch-camera-unselected.imageset/Contents.json b/Session/Meta/Images.xcassets/video-switch-camera-unselected.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/video-switch-camera-unselected.imageset/Contents.json rename to Session/Meta/Images.xcassets/video-switch-camera-unselected.imageset/Contents.json diff --git a/Session/Images.xcassets/video-switch-camera-unselected.imageset/switch_camera_large.png b/Session/Meta/Images.xcassets/video-switch-camera-unselected.imageset/switch_camera_large.png similarity index 100% rename from Session/Images.xcassets/video-switch-camera-unselected.imageset/switch_camera_large.png rename to Session/Meta/Images.xcassets/video-switch-camera-unselected.imageset/switch_camera_large.png diff --git a/Session/Images.xcassets/video-video-selected.imageset/Contents.json b/Session/Meta/Images.xcassets/video-video-selected.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/video-video-selected.imageset/Contents.json rename to Session/Meta/Images.xcassets/video-video-selected.imageset/Contents.json diff --git a/Session/Images.xcassets/video-video-selected.imageset/video-video-selected.png b/Session/Meta/Images.xcassets/video-video-selected.imageset/video-video-selected.png similarity index 100% rename from Session/Images.xcassets/video-video-selected.imageset/video-video-selected.png rename to Session/Meta/Images.xcassets/video-video-selected.imageset/video-video-selected.png diff --git a/Session/Images.xcassets/video-video-unselected.imageset/Contents.json b/Session/Meta/Images.xcassets/video-video-unselected.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/video-video-unselected.imageset/Contents.json rename to Session/Meta/Images.xcassets/video-video-unselected.imageset/Contents.json diff --git a/Session/Images.xcassets/video-video-unselected.imageset/video-video-unselected.png b/Session/Meta/Images.xcassets/video-video-unselected.imageset/video-video-unselected.png similarity index 100% rename from Session/Images.xcassets/video-video-unselected.imageset/video-video-unselected.png rename to Session/Meta/Images.xcassets/video-video-unselected.imageset/video-video-unselected.png diff --git a/Session/Images.xcassets/voice-memo-button.imageset/Contents.json b/Session/Meta/Images.xcassets/voice-memo-button.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/voice-memo-button.imageset/Contents.json rename to Session/Meta/Images.xcassets/voice-memo-button.imageset/Contents.json diff --git a/Session/Images.xcassets/voice-memo-button.imageset/voice-memo-button-32.png b/Session/Meta/Images.xcassets/voice-memo-button.imageset/voice-memo-button-32.png similarity index 100% rename from Session/Images.xcassets/voice-memo-button.imageset/voice-memo-button-32.png rename to Session/Meta/Images.xcassets/voice-memo-button.imageset/voice-memo-button-32.png diff --git a/Session/Images.xcassets/voice-memo-button.imageset/voice-memo-button-64.png b/Session/Meta/Images.xcassets/voice-memo-button.imageset/voice-memo-button-64.png similarity index 100% rename from Session/Images.xcassets/voice-memo-button.imageset/voice-memo-button-64.png rename to Session/Meta/Images.xcassets/voice-memo-button.imageset/voice-memo-button-64.png diff --git a/Session/Images.xcassets/voice-memo-button.imageset/voice-memo-button-96.png b/Session/Meta/Images.xcassets/voice-memo-button.imageset/voice-memo-button-96.png similarity index 100% rename from Session/Images.xcassets/voice-memo-button.imageset/voice-memo-button-96.png rename to Session/Meta/Images.xcassets/voice-memo-button.imageset/voice-memo-button-96.png diff --git a/Session/Images.xcassets/voice-message-large-white.imageset/Contents.json b/Session/Meta/Images.xcassets/voice-message-large-white.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/voice-message-large-white.imageset/Contents.json rename to Session/Meta/Images.xcassets/voice-message-large-white.imageset/Contents.json diff --git a/Session/Images.xcassets/voice-message-large-white.imageset/voice-message-large-white@1x.png b/Session/Meta/Images.xcassets/voice-message-large-white.imageset/voice-message-large-white@1x.png similarity index 100% rename from Session/Images.xcassets/voice-message-large-white.imageset/voice-message-large-white@1x.png rename to Session/Meta/Images.xcassets/voice-message-large-white.imageset/voice-message-large-white@1x.png diff --git a/Session/Images.xcassets/voice-message-large-white.imageset/voice-message-large-white@2x.png b/Session/Meta/Images.xcassets/voice-message-large-white.imageset/voice-message-large-white@2x.png similarity index 100% rename from Session/Images.xcassets/voice-message-large-white.imageset/voice-message-large-white@2x.png rename to Session/Meta/Images.xcassets/voice-message-large-white.imageset/voice-message-large-white@2x.png diff --git a/Session/Images.xcassets/voice-message-large-white.imageset/voice-message-large-white@3x.png b/Session/Meta/Images.xcassets/voice-message-large-white.imageset/voice-message-large-white@3x.png similarity index 100% rename from Session/Images.xcassets/voice-message-large-white.imageset/voice-message-large-white@3x.png rename to Session/Meta/Images.xcassets/voice-message-large-white.imageset/voice-message-large-white@3x.png diff --git a/Session/Images.xcassets/x-24.imageset/Contents.json b/Session/Meta/Images.xcassets/x-24.imageset/Contents.json similarity index 100% rename from Session/Images.xcassets/x-24.imageset/Contents.json rename to Session/Meta/Images.xcassets/x-24.imageset/Contents.json diff --git a/Session/Images.xcassets/x-24.imageset/x-24@1x.png b/Session/Meta/Images.xcassets/x-24.imageset/x-24@1x.png similarity index 100% rename from Session/Images.xcassets/x-24.imageset/x-24@1x.png rename to Session/Meta/Images.xcassets/x-24.imageset/x-24@1x.png diff --git a/Session/Images.xcassets/x-24.imageset/x-24@2x.png b/Session/Meta/Images.xcassets/x-24.imageset/x-24@2x.png similarity index 100% rename from Session/Images.xcassets/x-24.imageset/x-24@2x.png rename to Session/Meta/Images.xcassets/x-24.imageset/x-24@2x.png diff --git a/Session/Images.xcassets/x-24.imageset/x-24@3x.png b/Session/Meta/Images.xcassets/x-24.imageset/x-24@3x.png similarity index 100% rename from Session/Images.xcassets/x-24.imageset/x-24@3x.png rename to Session/Meta/Images.xcassets/x-24.imageset/x-24@3x.png diff --git a/Session/Images/audio_pause_button.png b/Session/Meta/Images/audio_pause_button.png similarity index 100% rename from Session/Images/audio_pause_button.png rename to Session/Meta/Images/audio_pause_button.png diff --git a/Session/Images/audio_pause_button@2x.png b/Session/Meta/Images/audio_pause_button@2x.png similarity index 100% rename from Session/Images/audio_pause_button@2x.png rename to Session/Meta/Images/audio_pause_button@2x.png diff --git a/Session/Images/audio_pause_button_blue.png b/Session/Meta/Images/audio_pause_button_blue.png similarity index 100% rename from Session/Images/audio_pause_button_blue.png rename to Session/Meta/Images/audio_pause_button_blue.png diff --git a/Session/Images/audio_pause_button_blue@2x.png b/Session/Meta/Images/audio_pause_button_blue@2x.png similarity index 100% rename from Session/Images/audio_pause_button_blue@2x.png rename to Session/Meta/Images/audio_pause_button_blue@2x.png diff --git a/Session/Images/audio_play_button.png b/Session/Meta/Images/audio_play_button.png similarity index 100% rename from Session/Images/audio_play_button.png rename to Session/Meta/Images/audio_play_button.png diff --git a/Session/Images/audio_play_button@2x.png b/Session/Meta/Images/audio_play_button@2x.png similarity index 100% rename from Session/Images/audio_play_button@2x.png rename to Session/Meta/Images/audio_play_button@2x.png diff --git a/Session/Images/audio_play_button_blue.png b/Session/Meta/Images/audio_play_button_blue.png similarity index 100% rename from Session/Images/audio_play_button_blue.png rename to Session/Meta/Images/audio_play_button_blue.png diff --git a/Session/Images/audio_play_button_blue@2x.png b/Session/Meta/Images/audio_play_button_blue@2x.png similarity index 100% rename from Session/Images/audio_play_button_blue@2x.png rename to Session/Meta/Images/audio_play_button_blue@2x.png diff --git a/Session/Images/call@2x.png b/Session/Meta/Images/call@2x.png similarity index 100% rename from Session/Images/call@2x.png rename to Session/Meta/Images/call@2x.png diff --git a/Session/Images/contact_default_feed.png b/Session/Meta/Images/contact_default_feed.png similarity index 100% rename from Session/Images/contact_default_feed.png rename to Session/Meta/Images/contact_default_feed.png diff --git a/Session/Images/endcall@2x.png b/Session/Meta/Images/endcall@2x.png similarity index 100% rename from Session/Images/endcall@2x.png rename to Session/Meta/Images/endcall@2x.png diff --git a/Session/Images/error_white@2x.png b/Session/Meta/Images/error_white@2x.png similarity index 100% rename from Session/Images/error_white@2x.png rename to Session/Meta/Images/error_white@2x.png diff --git a/Session/Images/mute_off@2x.png b/Session/Meta/Images/mute_off@2x.png similarity index 100% rename from Session/Images/mute_off@2x.png rename to Session/Meta/Images/mute_off@2x.png diff --git a/Session/Images/mute_on@2x.png b/Session/Meta/Images/mute_on@2x.png similarity index 100% rename from Session/Images/mute_on@2x.png rename to Session/Meta/Images/mute_on@2x.png diff --git a/Session/Images/pause_icon.png b/Session/Meta/Images/pause_icon.png similarity index 100% rename from Session/Images/pause_icon.png rename to Session/Meta/Images/pause_icon.png diff --git a/Session/Images/pause_icon@2x.png b/Session/Meta/Images/pause_icon@2x.png similarity index 100% rename from Session/Images/pause_icon@2x.png rename to Session/Meta/Images/pause_icon@2x.png diff --git a/Session/Images/play_icon.png b/Session/Meta/Images/play_icon.png similarity index 100% rename from Session/Images/play_icon.png rename to Session/Meta/Images/play_icon.png diff --git a/Session/Images/play_icon@2x.png b/Session/Meta/Images/play_icon@2x.png similarity index 100% rename from Session/Images/play_icon@2x.png rename to Session/Meta/Images/play_icon@2x.png diff --git a/Session/Images/qr@2x.png b/Session/Meta/Images/qr@2x.png similarity index 100% rename from Session/Images/qr@2x.png rename to Session/Meta/Images/qr@2x.png diff --git a/Session/Images/quit@2x.png b/Session/Meta/Images/quit@2x.png similarity index 100% rename from Session/Images/quit@2x.png rename to Session/Meta/Images/quit@2x.png diff --git a/Session/Images/savephoto@2x.png b/Session/Meta/Images/savephoto@2x.png similarity index 100% rename from Session/Images/savephoto@2x.png rename to Session/Meta/Images/savephoto@2x.png diff --git a/Session/Images/typing-animation-dark.gif b/Session/Meta/Images/typing-animation-dark.gif similarity index 100% rename from Session/Images/typing-animation-dark.gif rename to Session/Meta/Images/typing-animation-dark.gif diff --git a/Session/Images/typing-animation.gif b/Session/Meta/Images/typing-animation.gif similarity index 100% rename from Session/Images/typing-animation.gif rename to Session/Meta/Images/typing-animation.gif diff --git a/Session/Images/warning_white@2x.png b/Session/Meta/Images/warning_white@2x.png similarity index 100% rename from Session/Images/warning_white@2x.png rename to Session/Meta/Images/warning_white@2x.png diff --git a/SettingsBundle/Settings.bundle/Acknowledgements.plist b/Session/Meta/Settings.bundle/Acknowledgements.plist similarity index 100% rename from SettingsBundle/Settings.bundle/Acknowledgements.plist rename to Session/Meta/Settings.bundle/Acknowledgements.plist diff --git a/SettingsBundle/Settings.bundle/Root.plist b/Session/Meta/Settings.bundle/Root.plist similarity index 100% rename from SettingsBundle/Settings.bundle/Root.plist rename to Session/Meta/Settings.bundle/Root.plist diff --git a/SettingsBundle/Settings.bundle/en.lproj/Acknowledgements.strings b/Session/Meta/Settings.bundle/en.lproj/Acknowledgements.strings similarity index 100% rename from SettingsBundle/Settings.bundle/en.lproj/Acknowledgements.strings rename to Session/Meta/Settings.bundle/en.lproj/Acknowledgements.strings diff --git a/SettingsBundle/Settings.bundle/en.lproj/Root.strings b/Session/Meta/Settings.bundle/en.lproj/Root.strings similarity index 100% rename from SettingsBundle/Settings.bundle/en.lproj/Root.strings rename to Session/Meta/Settings.bundle/en.lproj/Root.strings diff --git a/Session/src/Signal-Bridging-Header.h b/Session/Meta/Signal-Bridging-Header.h similarity index 98% rename from Session/src/Signal-Bridging-Header.h rename to Session/Meta/Signal-Bridging-Header.h index 5ed1b41bf..517bbc064 100644 --- a/Session/src/Signal-Bridging-Header.h +++ b/Session/Meta/Signal-Bridging-Header.h @@ -16,8 +16,6 @@ #import "ConversationViewCell.h" #import "ConversationViewItem.h" #import "DateUtil.h" -#import "DebugUIPage.h" -#import "DebugUITableViewController.h" #import "FingerprintViewController.h" #import "MediaDetailViewController.h" #import "NotificationSettingsViewController.h" diff --git a/Session/Signal-Info.plist b/Session/Meta/Signal-Info.plist similarity index 100% rename from Session/Signal-Info.plist rename to Session/Meta/Signal-Info.plist diff --git a/Session/Signal-Prefix.pch b/Session/Meta/Signal-Prefix.pch similarity index 100% rename from Session/Signal-Prefix.pch rename to Session/Meta/Signal-Prefix.pch diff --git a/Session/Signal.entitlements b/Session/Meta/Signal.entitlements similarity index 100% rename from Session/Signal.entitlements rename to Session/Meta/Signal.entitlements diff --git a/Session/SignalTSan.supp b/Session/Meta/SignalTSan.supp similarity index 100% rename from Session/SignalTSan.supp rename to Session/Meta/SignalTSan.supp diff --git a/Session/SignalUBSan.supp b/Session/Meta/SignalUBSan.supp similarity index 100% rename from Session/SignalUBSan.supp rename to Session/Meta/SignalUBSan.supp diff --git a/Session/translations/.tx/config b/Session/Meta/Translations/.tx/config similarity index 100% rename from Session/translations/.tx/config rename to Session/Meta/Translations/.tx/config diff --git a/Session/translations/.tx/signal-ios.localizablestrings-30/an_translation b/Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/an_translation similarity index 100% rename from Session/translations/.tx/signal-ios.localizablestrings-30/an_translation rename to Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/an_translation diff --git a/Session/translations/.tx/signal-ios.localizablestrings-30/ar_translation b/Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/ar_translation similarity index 100% rename from Session/translations/.tx/signal-ios.localizablestrings-30/ar_translation rename to Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/ar_translation diff --git a/Session/translations/.tx/signal-ios.localizablestrings-30/bg_BG_translation b/Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/bg_BG_translation similarity index 100% rename from Session/translations/.tx/signal-ios.localizablestrings-30/bg_BG_translation rename to Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/bg_BG_translation diff --git a/Session/translations/.tx/signal-ios.localizablestrings-30/ca_translation b/Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/ca_translation similarity index 100% rename from Session/translations/.tx/signal-ios.localizablestrings-30/ca_translation rename to Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/ca_translation diff --git a/Session/translations/.tx/signal-ios.localizablestrings-30/cs_translation b/Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/cs_translation similarity index 100% rename from Session/translations/.tx/signal-ios.localizablestrings-30/cs_translation rename to Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/cs_translation diff --git a/Session/translations/.tx/signal-ios.localizablestrings-30/da_translation b/Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/da_translation similarity index 100% rename from Session/translations/.tx/signal-ios.localizablestrings-30/da_translation rename to Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/da_translation diff --git a/Session/translations/.tx/signal-ios.localizablestrings-30/de_translation b/Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/de_translation similarity index 100% rename from Session/translations/.tx/signal-ios.localizablestrings-30/de_translation rename to Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/de_translation diff --git a/Session/translations/.tx/signal-ios.localizablestrings-30/es_translation b/Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/es_translation similarity index 100% rename from Session/translations/.tx/signal-ios.localizablestrings-30/es_translation rename to Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/es_translation diff --git a/Session/translations/.tx/signal-ios.localizablestrings-30/eu_translation b/Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/eu_translation similarity index 100% rename from Session/translations/.tx/signal-ios.localizablestrings-30/eu_translation rename to Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/eu_translation diff --git a/Session/translations/.tx/signal-ios.localizablestrings-30/fa_IR_translation b/Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/fa_IR_translation similarity index 100% rename from Session/translations/.tx/signal-ios.localizablestrings-30/fa_IR_translation rename to Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/fa_IR_translation diff --git a/Session/translations/.tx/signal-ios.localizablestrings-30/fa_translation b/Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/fa_translation similarity index 100% rename from Session/translations/.tx/signal-ios.localizablestrings-30/fa_translation rename to Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/fa_translation diff --git a/Session/translations/.tx/signal-ios.localizablestrings-30/fi_translation b/Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/fi_translation similarity index 100% rename from Session/translations/.tx/signal-ios.localizablestrings-30/fi_translation rename to Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/fi_translation diff --git a/Session/translations/.tx/signal-ios.localizablestrings-30/fil_translation b/Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/fil_translation similarity index 100% rename from Session/translations/.tx/signal-ios.localizablestrings-30/fil_translation rename to Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/fil_translation diff --git a/Session/translations/.tx/signal-ios.localizablestrings-30/fr_translation b/Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/fr_translation similarity index 100% rename from Session/translations/.tx/signal-ios.localizablestrings-30/fr_translation rename to Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/fr_translation diff --git a/Session/translations/.tx/signal-ios.localizablestrings-30/he_translation b/Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/he_translation similarity index 100% rename from Session/translations/.tx/signal-ios.localizablestrings-30/he_translation rename to Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/he_translation diff --git a/Session/translations/.tx/signal-ios.localizablestrings-30/hu_translation b/Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/hu_translation similarity index 100% rename from Session/translations/.tx/signal-ios.localizablestrings-30/hu_translation rename to Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/hu_translation diff --git a/Session/translations/.tx/signal-ios.localizablestrings-30/it_IT_translation b/Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/it_IT_translation similarity index 100% rename from Session/translations/.tx/signal-ios.localizablestrings-30/it_IT_translation rename to Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/it_IT_translation diff --git a/Session/translations/.tx/signal-ios.localizablestrings-30/ja_JP_translation b/Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/ja_JP_translation similarity index 100% rename from Session/translations/.tx/signal-ios.localizablestrings-30/ja_JP_translation rename to Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/ja_JP_translation diff --git a/Session/translations/.tx/signal-ios.localizablestrings-30/lv_translation b/Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/lv_translation similarity index 100% rename from Session/translations/.tx/signal-ios.localizablestrings-30/lv_translation rename to Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/lv_translation diff --git a/Session/translations/.tx/signal-ios.localizablestrings-30/nb_translation b/Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/nb_translation similarity index 100% rename from Session/translations/.tx/signal-ios.localizablestrings-30/nb_translation rename to Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/nb_translation diff --git a/Session/translations/.tx/signal-ios.localizablestrings-30/nl_translation b/Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/nl_translation similarity index 100% rename from Session/translations/.tx/signal-ios.localizablestrings-30/nl_translation rename to Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/nl_translation diff --git a/Session/translations/.tx/signal-ios.localizablestrings-30/pl_translation b/Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/pl_translation similarity index 100% rename from Session/translations/.tx/signal-ios.localizablestrings-30/pl_translation rename to Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/pl_translation diff --git a/Session/translations/.tx/signal-ios.localizablestrings-30/pt_BR_translation b/Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/pt_BR_translation similarity index 100% rename from Session/translations/.tx/signal-ios.localizablestrings-30/pt_BR_translation rename to Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/pt_BR_translation diff --git a/Session/translations/.tx/signal-ios.localizablestrings-30/ro_translation b/Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/ro_translation similarity index 100% rename from Session/translations/.tx/signal-ios.localizablestrings-30/ro_translation rename to Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/ro_translation diff --git a/Session/translations/.tx/signal-ios.localizablestrings-30/ru_translation b/Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/ru_translation similarity index 100% rename from Session/translations/.tx/signal-ios.localizablestrings-30/ru_translation rename to Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/ru_translation diff --git a/Session/translations/.tx/signal-ios.localizablestrings-30/sl_translation b/Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/sl_translation similarity index 100% rename from Session/translations/.tx/signal-ios.localizablestrings-30/sl_translation rename to Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/sl_translation diff --git a/Session/translations/.tx/signal-ios.localizablestrings-30/sq_translation b/Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/sq_translation similarity index 100% rename from Session/translations/.tx/signal-ios.localizablestrings-30/sq_translation rename to Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/sq_translation diff --git a/Session/translations/.tx/signal-ios.localizablestrings-30/sv_SE_translation b/Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/sv_SE_translation similarity index 100% rename from Session/translations/.tx/signal-ios.localizablestrings-30/sv_SE_translation rename to Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/sv_SE_translation diff --git a/Session/translations/.tx/signal-ios.localizablestrings-30/ta_translation b/Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/ta_translation similarity index 100% rename from Session/translations/.tx/signal-ios.localizablestrings-30/ta_translation rename to Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/ta_translation diff --git a/Session/translations/.tx/signal-ios.localizablestrings-30/tr_TR_translation b/Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/tr_TR_translation similarity index 100% rename from Session/translations/.tx/signal-ios.localizablestrings-30/tr_TR_translation rename to Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/tr_TR_translation diff --git a/Session/translations/.tx/signal-ios.localizablestrings-30/uk_translation b/Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/uk_translation similarity index 100% rename from Session/translations/.tx/signal-ios.localizablestrings-30/uk_translation rename to Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/uk_translation diff --git a/Session/translations/.tx/signal-ios.localizablestrings-30/zh_CN_translation b/Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/zh_CN_translation similarity index 100% rename from Session/translations/.tx/signal-ios.localizablestrings-30/zh_CN_translation rename to Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/zh_CN_translation diff --git a/Session/translations/.tx/signal-ios.localizablestrings-30/zh_TW.Big5_translation b/Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/zh_TW.Big5_translation similarity index 100% rename from Session/translations/.tx/signal-ios.localizablestrings-30/zh_TW.Big5_translation rename to Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/zh_TW.Big5_translation diff --git a/Session/translations/.tx/signal-ios.localizablestrings-30/zh_TW_translation b/Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/zh_TW_translation similarity index 100% rename from Session/translations/.tx/signal-ios.localizablestrings-30/zh_TW_translation rename to Session/Meta/Translations/.tx/signal-ios.localizablestrings-30/zh_TW_translation diff --git a/Session/Migrating Translations from Android.md b/Session/Meta/Translations/Migrating Translations from Android.md similarity index 100% rename from Session/Migrating Translations from Android.md rename to Session/Meta/Translations/Migrating Translations from Android.md diff --git a/Session/translations/TRANSLATIONS.md b/Session/Meta/Translations/TRANSLATIONS.md similarity index 100% rename from Session/translations/TRANSLATIONS.md rename to Session/Meta/Translations/TRANSLATIONS.md diff --git a/Session/translations/bin/auto-genstrings b/Session/Meta/Translations/bin/auto-genstrings similarity index 100% rename from Session/translations/bin/auto-genstrings rename to Session/Meta/Translations/bin/auto-genstrings diff --git a/Session/translations/bin/pull-translations b/Session/Meta/Translations/bin/pull-translations similarity index 100% rename from Session/translations/bin/pull-translations rename to Session/Meta/Translations/bin/pull-translations diff --git a/Session/translations/bin/push-translation-source b/Session/Meta/Translations/bin/push-translation-source similarity index 100% rename from Session/translations/bin/push-translation-source rename to Session/Meta/Translations/bin/push-translation-source diff --git a/Session/translations/bin/sync-translations b/Session/Meta/Translations/bin/sync-translations similarity index 100% rename from Session/translations/bin/sync-translations rename to Session/Meta/Translations/bin/sync-translations diff --git a/Session/translations/de.lproj/Localizable.strings b/Session/Meta/Translations/de.lproj/Localizable.strings similarity index 100% rename from Session/translations/de.lproj/Localizable.strings rename to Session/Meta/Translations/de.lproj/Localizable.strings diff --git a/Session/translations/en.lproj/Localizable.strings b/Session/Meta/Translations/en.lproj/Localizable.strings similarity index 100% rename from Session/translations/en.lproj/Localizable.strings rename to Session/Meta/Translations/en.lproj/Localizable.strings diff --git a/Session/translations/es.lproj/Localizable.strings b/Session/Meta/Translations/es.lproj/Localizable.strings similarity index 100% rename from Session/translations/es.lproj/Localizable.strings rename to Session/Meta/Translations/es.lproj/Localizable.strings diff --git a/Session/translations/fa.lproj/Localizable.strings b/Session/Meta/Translations/fa.lproj/Localizable.strings similarity index 100% rename from Session/translations/fa.lproj/Localizable.strings rename to Session/Meta/Translations/fa.lproj/Localizable.strings diff --git a/Session/translations/fr.lproj/Localizable.strings b/Session/Meta/Translations/fr.lproj/Localizable.strings similarity index 100% rename from Session/translations/fr.lproj/Localizable.strings rename to Session/Meta/Translations/fr.lproj/Localizable.strings diff --git a/Session/translations/id-ID.lproj/Localizable.strings b/Session/Meta/Translations/id-ID.lproj/Localizable.strings similarity index 100% rename from Session/translations/id-ID.lproj/Localizable.strings rename to Session/Meta/Translations/id-ID.lproj/Localizable.strings diff --git a/Session/translations/it.lproj/Localizable.strings b/Session/Meta/Translations/it.lproj/Localizable.strings similarity index 100% rename from Session/translations/it.lproj/Localizable.strings rename to Session/Meta/Translations/it.lproj/Localizable.strings diff --git a/Session/translations/ja.lproj/Localizable.strings b/Session/Meta/Translations/ja.lproj/Localizable.strings similarity index 100% rename from Session/translations/ja.lproj/Localizable.strings rename to Session/Meta/Translations/ja.lproj/Localizable.strings diff --git a/Session/translations/pl.lproj/Localizable.strings b/Session/Meta/Translations/pl.lproj/Localizable.strings similarity index 100% rename from Session/translations/pl.lproj/Localizable.strings rename to Session/Meta/Translations/pl.lproj/Localizable.strings diff --git a/Session/translations/pt_BR.lproj/Localizable.strings b/Session/Meta/Translations/pt_BR.lproj/Localizable.strings similarity index 100% rename from Session/translations/pt_BR.lproj/Localizable.strings rename to Session/Meta/Translations/pt_BR.lproj/Localizable.strings diff --git a/Session/translations/ru.lproj/Localizable.strings b/Session/Meta/Translations/ru.lproj/Localizable.strings similarity index 100% rename from Session/translations/ru.lproj/Localizable.strings rename to Session/Meta/Translations/ru.lproj/Localizable.strings diff --git a/Session/translations/vi-VN.lproj/Localizable.strings b/Session/Meta/Translations/vi-VN.lproj/Localizable.strings similarity index 100% rename from Session/translations/vi-VN.lproj/Localizable.strings rename to Session/Meta/Translations/vi-VN.lproj/Localizable.strings diff --git a/Session/translations/zh_CN.lproj/Localizable.strings b/Session/Meta/Translations/zh_CN.lproj/Localizable.strings similarity index 100% rename from Session/translations/zh_CN.lproj/Localizable.strings rename to Session/Meta/Translations/zh_CN.lproj/Localizable.strings diff --git a/Session/main.m b/Session/Meta/main.m similarity index 100% rename from Session/main.m rename to Session/Meta/main.m diff --git a/Session/src/util/UI Categories/AVAudioSession+OWS.h b/Session/Signal/AVAudioSession+OWS.h similarity index 100% rename from Session/src/util/UI Categories/AVAudioSession+OWS.h rename to Session/Signal/AVAudioSession+OWS.h diff --git a/Session/src/util/UI Categories/AVAudioSession+OWS.m b/Session/Signal/AVAudioSession+OWS.m similarity index 100% rename from Session/src/util/UI Categories/AVAudioSession+OWS.m rename to Session/Signal/AVAudioSession+OWS.m diff --git a/Session/src/ViewControllers/AppSettings/AboutTableViewController.h b/Session/Signal/AboutTableViewController.h similarity index 100% rename from Session/src/ViewControllers/AppSettings/AboutTableViewController.h rename to Session/Signal/AboutTableViewController.h diff --git a/Session/src/ViewControllers/AppSettings/AboutTableViewController.m b/Session/Signal/AboutTableViewController.m similarity index 100% rename from Session/src/ViewControllers/AppSettings/AboutTableViewController.m rename to Session/Signal/AboutTableViewController.m diff --git a/Session/src/Models/AccountManager.swift b/Session/Signal/AccountManager.swift similarity index 100% rename from Session/src/Models/AccountManager.swift rename to Session/Signal/AccountManager.swift diff --git a/Session/src/ViewControllers/AddContactShareToExistingContactViewController.swift b/Session/Signal/AddContactShareToExistingContactViewController.swift similarity index 100% rename from Session/src/ViewControllers/AddContactShareToExistingContactViewController.swift rename to Session/Signal/AddContactShareToExistingContactViewController.swift diff --git a/Session/src/ViewControllers/AppSettings/AddToBlockListViewController.h b/Session/Signal/AddToBlockListViewController.h similarity index 100% rename from Session/src/ViewControllers/AppSettings/AddToBlockListViewController.h rename to Session/Signal/AddToBlockListViewController.h diff --git a/Session/src/ViewControllers/AppSettings/AddToBlockListViewController.m b/Session/Signal/AddToBlockListViewController.m similarity index 100% rename from Session/src/ViewControllers/AppSettings/AddToBlockListViewController.m rename to Session/Signal/AddToBlockListViewController.m diff --git a/Session/src/ViewControllers/ThreadSettings/AddToGroupViewController.h b/Session/Signal/AddToGroupViewController.h similarity index 100% rename from Session/src/ViewControllers/ThreadSettings/AddToGroupViewController.h rename to Session/Signal/AddToGroupViewController.h diff --git a/Session/src/ViewControllers/ThreadSettings/AddToGroupViewController.m b/Session/Signal/AddToGroupViewController.m similarity index 100% rename from Session/src/ViewControllers/ThreadSettings/AddToGroupViewController.m rename to Session/Signal/AddToGroupViewController.m diff --git a/Session/src/ViewControllers/AppSettings/AdvancedSettingsTableViewController.h b/Session/Signal/AdvancedSettingsTableViewController.h similarity index 100% rename from Session/src/ViewControllers/AppSettings/AdvancedSettingsTableViewController.h rename to Session/Signal/AdvancedSettingsTableViewController.h diff --git a/Session/src/ViewControllers/AppSettings/AdvancedSettingsTableViewController.m b/Session/Signal/AdvancedSettingsTableViewController.m similarity index 100% rename from Session/src/ViewControllers/AppSettings/AdvancedSettingsTableViewController.m rename to Session/Signal/AdvancedSettingsTableViewController.m diff --git a/Session/src/AppDelegate.h b/Session/Signal/AppDelegate.h similarity index 100% rename from Session/src/AppDelegate.h rename to Session/Signal/AppDelegate.h diff --git a/Session/src/AppDelegate.m b/Session/Signal/AppDelegate.m similarity index 100% rename from Session/src/AppDelegate.m rename to Session/Signal/AppDelegate.m diff --git a/Session/src/environment/AppEnvironment.swift b/Session/Signal/AppEnvironment.swift similarity index 100% rename from Session/src/environment/AppEnvironment.swift rename to Session/Signal/AppEnvironment.swift diff --git a/Session/src/UserInterface/Notifications/AppNotifications.swift b/Session/Signal/AppNotifications.swift similarity index 100% rename from Session/src/UserInterface/Notifications/AppNotifications.swift rename to Session/Signal/AppNotifications.swift diff --git a/Session/src/util/AppUpdateNag.swift b/Session/Signal/AppUpdateNag.swift similarity index 100% rename from Session/src/util/AppUpdateNag.swift rename to Session/Signal/AppUpdateNag.swift diff --git a/Session/src/views/AudioProgressView.swift b/Session/Signal/AudioProgressView.swift similarity index 100% rename from Session/src/views/AudioProgressView.swift rename to Session/Signal/AudioProgressView.swift diff --git a/Session/src/views/AvatarTableViewCell.swift b/Session/Signal/AvatarTableViewCell.swift similarity index 100% rename from Session/src/views/AvatarTableViewCell.swift rename to Session/Signal/AvatarTableViewCell.swift diff --git a/Session/src/ViewControllers/AvatarViewHelper.h b/Session/Signal/AvatarViewHelper.h similarity index 100% rename from Session/src/ViewControllers/AvatarViewHelper.h rename to Session/Signal/AvatarViewHelper.h diff --git a/Session/src/ViewControllers/AvatarViewHelper.m b/Session/Signal/AvatarViewHelper.m similarity index 100% rename from Session/src/ViewControllers/AvatarViewHelper.m rename to Session/Signal/AvatarViewHelper.m diff --git a/Session/src/ViewControllers/Registration/BackupRestoreViewController.swift b/Session/Signal/BackupRestoreViewController.swift similarity index 100% rename from Session/src/ViewControllers/Registration/BackupRestoreViewController.swift rename to Session/Signal/BackupRestoreViewController.swift diff --git a/Session/src/ViewControllers/AppSettings/BlockListViewController.h b/Session/Signal/BlockListViewController.h similarity index 100% rename from Session/src/ViewControllers/AppSettings/BlockListViewController.h rename to Session/Signal/BlockListViewController.h diff --git a/Session/src/ViewControllers/AppSettings/BlockListViewController.m b/Session/Signal/BlockListViewController.m similarity index 100% rename from Session/src/ViewControllers/AppSettings/BlockListViewController.m rename to Session/Signal/BlockListViewController.m diff --git a/Session/src/call/CallAudioService.swift b/Session/Signal/CallAudioService.swift similarity index 100% rename from Session/src/call/CallAudioService.swift rename to Session/Signal/CallAudioService.swift diff --git a/Session/src/call/Speakerbox/CallKitCallManager.swift b/Session/Signal/CallKitCallManager.swift similarity index 100% rename from Session/src/call/Speakerbox/CallKitCallManager.swift rename to Session/Signal/CallKitCallManager.swift diff --git a/Session/src/call/Speakerbox/CallKitCallUIAdaptee.swift b/Session/Signal/CallKitCallUIAdaptee.swift similarity index 100% rename from Session/src/call/Speakerbox/CallKitCallUIAdaptee.swift rename to Session/Signal/CallKitCallUIAdaptee.swift diff --git a/Session/src/call/CallService.swift b/Session/Signal/CallService.swift similarity index 100% rename from Session/src/call/CallService.swift rename to Session/Signal/CallService.swift diff --git a/Session/src/call/UserInterface/CallUIAdapter.swift b/Session/Signal/CallUIAdapter.swift similarity index 100% rename from Session/src/call/UserInterface/CallUIAdapter.swift rename to Session/Signal/CallUIAdapter.swift diff --git a/Session/src/ViewControllers/Call/CallVideoHintView.swift b/Session/Signal/CallVideoHintView.swift similarity index 98% rename from Session/src/ViewControllers/Call/CallVideoHintView.swift rename to Session/Signal/CallVideoHintView.swift index 4a6809e97..ba49030d0 100644 --- a/Session/src/ViewControllers/Call/CallVideoHintView.swift +++ b/Session/Signal/CallVideoHintView.swift @@ -23,7 +23,7 @@ class CallVideoHintView: UIView { tapGesture = UITapGestureRecognizer(target: self, action: #selector(didTap(tapGesture:))) addGestureRecognizer(tapGesture) - let layerView = OWSLayerView() + let layerView = OWSLayerView(frame: .zero) { _ in } let shapeLayer = CAShapeLayer() shapeLayer.fillColor = UIColor.ows_signalBlue.cgColor layerView.layer.addSublayer(shapeLayer) diff --git a/Session/src/ViewControllers/Call/CallViewController.swift b/Session/Signal/CallViewController.swift similarity index 100% rename from Session/src/ViewControllers/Call/CallViewController.swift rename to Session/Signal/CallViewController.swift diff --git a/Session/src/views/CaptionView.swift b/Session/Signal/CaptionView.swift similarity index 100% rename from Session/src/views/CaptionView.swift rename to Session/Signal/CaptionView.swift diff --git a/Session/src/ViewControllers/ColorPickerViewController.swift b/Session/Signal/ColorPickerViewController.swift similarity index 100% rename from Session/src/ViewControllers/ColorPickerViewController.swift rename to Session/Signal/ColorPickerViewController.swift diff --git a/Session/src/Models/CompareSafetyNumbersActivity.swift b/Session/Signal/CompareSafetyNumbersActivity.swift similarity index 100% rename from Session/src/Models/CompareSafetyNumbersActivity.swift rename to Session/Signal/CompareSafetyNumbersActivity.swift diff --git a/Session/src/views/ContactCell.swift b/Session/Signal/ContactCell.swift similarity index 100% rename from Session/src/views/ContactCell.swift rename to Session/Signal/ContactCell.swift diff --git a/Session/src/ViewControllers/ContactShareViewHelper.swift b/Session/Signal/ContactShareViewHelper.swift similarity index 100% rename from Session/src/ViewControllers/ContactShareViewHelper.swift rename to Session/Signal/ContactShareViewHelper.swift diff --git a/Session/src/ViewControllers/ContactViewController.swift b/Session/Signal/ContactViewController.swift similarity index 100% rename from Session/src/ViewControllers/ContactViewController.swift rename to Session/Signal/ContactViewController.swift diff --git a/Session/src/ViewControllers/ContactsPicker.swift b/Session/Signal/ContactsPicker.swift similarity index 100% rename from Session/src/ViewControllers/ContactsPicker.swift rename to Session/Signal/ContactsPicker.swift diff --git a/Session/src/Jobs/ConversationConfigurationSyncOperation.swift b/Session/Signal/ConversationConfigurationSyncOperation.swift similarity index 100% rename from Session/src/Jobs/ConversationConfigurationSyncOperation.swift rename to Session/Signal/ConversationConfigurationSyncOperation.swift diff --git a/Session/src/ConversationSearch.swift b/Session/Signal/ConversationSearch.swift similarity index 100% rename from Session/src/ConversationSearch.swift rename to Session/Signal/ConversationSearch.swift diff --git a/Session/src/ViewControllers/ConversationView/Cells/AttachmentUploadView.h b/Session/Signal/ConversationView/Cells/AttachmentUploadView.h similarity index 100% rename from Session/src/ViewControllers/ConversationView/Cells/AttachmentUploadView.h rename to Session/Signal/ConversationView/Cells/AttachmentUploadView.h diff --git a/Session/src/ViewControllers/ConversationView/Cells/AttachmentUploadView.m b/Session/Signal/ConversationView/Cells/AttachmentUploadView.m similarity index 100% rename from Session/src/ViewControllers/ConversationView/Cells/AttachmentUploadView.m rename to Session/Signal/ConversationView/Cells/AttachmentUploadView.m diff --git a/Session/src/ViewControllers/ConversationView/Cells/ConversationMediaView.swift b/Session/Signal/ConversationView/Cells/ConversationMediaView.swift similarity index 100% rename from Session/src/ViewControllers/ConversationView/Cells/ConversationMediaView.swift rename to Session/Signal/ConversationView/Cells/ConversationMediaView.swift diff --git a/Session/src/ViewControllers/ConversationView/Cells/ConversationViewCell.h b/Session/Signal/ConversationView/Cells/ConversationViewCell.h similarity index 100% rename from Session/src/ViewControllers/ConversationView/Cells/ConversationViewCell.h rename to Session/Signal/ConversationView/Cells/ConversationViewCell.h diff --git a/Session/src/ViewControllers/ConversationView/Cells/ConversationViewCell.m b/Session/Signal/ConversationView/Cells/ConversationViewCell.m similarity index 100% rename from Session/src/ViewControllers/ConversationView/Cells/ConversationViewCell.m rename to Session/Signal/ConversationView/Cells/ConversationViewCell.m diff --git a/Session/src/ViewControllers/ConversationView/Cells/MediaAlbumCellView.swift b/Session/Signal/ConversationView/Cells/MediaAlbumCellView.swift similarity index 100% rename from Session/src/ViewControllers/ConversationView/Cells/MediaAlbumCellView.swift rename to Session/Signal/ConversationView/Cells/MediaAlbumCellView.swift diff --git a/Session/src/ViewControllers/ConversationView/Cells/MediaDownloadView.swift b/Session/Signal/ConversationView/Cells/MediaDownloadView.swift similarity index 100% rename from Session/src/ViewControllers/ConversationView/Cells/MediaDownloadView.swift rename to Session/Signal/ConversationView/Cells/MediaDownloadView.swift diff --git a/Session/src/ViewControllers/ConversationView/Cells/MediaUploadView.swift b/Session/Signal/ConversationView/Cells/MediaUploadView.swift similarity index 100% rename from Session/src/ViewControllers/ConversationView/Cells/MediaUploadView.swift rename to Session/Signal/ConversationView/Cells/MediaUploadView.swift diff --git a/Session/src/ViewControllers/ConversationView/Cells/OWSBubbleShapeView.h b/Session/Signal/ConversationView/Cells/OWSBubbleShapeView.h similarity index 100% rename from Session/src/ViewControllers/ConversationView/Cells/OWSBubbleShapeView.h rename to Session/Signal/ConversationView/Cells/OWSBubbleShapeView.h diff --git a/Session/src/ViewControllers/ConversationView/Cells/OWSBubbleShapeView.m b/Session/Signal/ConversationView/Cells/OWSBubbleShapeView.m similarity index 100% rename from Session/src/ViewControllers/ConversationView/Cells/OWSBubbleShapeView.m rename to Session/Signal/ConversationView/Cells/OWSBubbleShapeView.m diff --git a/Session/src/ViewControllers/ConversationView/Cells/OWSBubbleView.h b/Session/Signal/ConversationView/Cells/OWSBubbleView.h similarity index 100% rename from Session/src/ViewControllers/ConversationView/Cells/OWSBubbleView.h rename to Session/Signal/ConversationView/Cells/OWSBubbleView.h diff --git a/Session/src/ViewControllers/ConversationView/Cells/OWSBubbleView.m b/Session/Signal/ConversationView/Cells/OWSBubbleView.m similarity index 100% rename from Session/src/ViewControllers/ConversationView/Cells/OWSBubbleView.m rename to Session/Signal/ConversationView/Cells/OWSBubbleView.m diff --git a/Session/src/ViewControllers/ConversationView/Cells/OWSContactOffersCell.h b/Session/Signal/ConversationView/Cells/OWSContactOffersCell.h similarity index 100% rename from Session/src/ViewControllers/ConversationView/Cells/OWSContactOffersCell.h rename to Session/Signal/ConversationView/Cells/OWSContactOffersCell.h diff --git a/Session/src/ViewControllers/ConversationView/Cells/OWSContactOffersCell.m b/Session/Signal/ConversationView/Cells/OWSContactOffersCell.m similarity index 100% rename from Session/src/ViewControllers/ConversationView/Cells/OWSContactOffersCell.m rename to Session/Signal/ConversationView/Cells/OWSContactOffersCell.m diff --git a/Session/src/ViewControllers/ConversationView/Cells/OWSContactShareButtonsView.h b/Session/Signal/ConversationView/Cells/OWSContactShareButtonsView.h similarity index 100% rename from Session/src/ViewControllers/ConversationView/Cells/OWSContactShareButtonsView.h rename to Session/Signal/ConversationView/Cells/OWSContactShareButtonsView.h diff --git a/Session/src/ViewControllers/ConversationView/Cells/OWSContactShareButtonsView.m b/Session/Signal/ConversationView/Cells/OWSContactShareButtonsView.m similarity index 100% rename from Session/src/ViewControllers/ConversationView/Cells/OWSContactShareButtonsView.m rename to Session/Signal/ConversationView/Cells/OWSContactShareButtonsView.m diff --git a/Session/src/ViewControllers/ConversationView/Cells/OWSContactShareView.h b/Session/Signal/ConversationView/Cells/OWSContactShareView.h similarity index 100% rename from Session/src/ViewControllers/ConversationView/Cells/OWSContactShareView.h rename to Session/Signal/ConversationView/Cells/OWSContactShareView.h diff --git a/Session/src/ViewControllers/ConversationView/Cells/OWSContactShareView.m b/Session/Signal/ConversationView/Cells/OWSContactShareView.m similarity index 100% rename from Session/src/ViewControllers/ConversationView/Cells/OWSContactShareView.m rename to Session/Signal/ConversationView/Cells/OWSContactShareView.m diff --git a/Session/src/ViewControllers/ConversationView/Cells/OWSGenericAttachmentView.h b/Session/Signal/ConversationView/Cells/OWSGenericAttachmentView.h similarity index 100% rename from Session/src/ViewControllers/ConversationView/Cells/OWSGenericAttachmentView.h rename to Session/Signal/ConversationView/Cells/OWSGenericAttachmentView.h diff --git a/Session/src/ViewControllers/ConversationView/Cells/OWSGenericAttachmentView.m b/Session/Signal/ConversationView/Cells/OWSGenericAttachmentView.m similarity index 100% rename from Session/src/ViewControllers/ConversationView/Cells/OWSGenericAttachmentView.m rename to Session/Signal/ConversationView/Cells/OWSGenericAttachmentView.m diff --git a/Session/src/ViewControllers/ConversationView/Cells/OWSLabel.h b/Session/Signal/ConversationView/Cells/OWSLabel.h similarity index 100% rename from Session/src/ViewControllers/ConversationView/Cells/OWSLabel.h rename to Session/Signal/ConversationView/Cells/OWSLabel.h diff --git a/Session/src/ViewControllers/ConversationView/Cells/OWSLabel.m b/Session/Signal/ConversationView/Cells/OWSLabel.m similarity index 100% rename from Session/src/ViewControllers/ConversationView/Cells/OWSLabel.m rename to Session/Signal/ConversationView/Cells/OWSLabel.m diff --git a/Session/src/ViewControllers/ConversationView/Cells/OWSMessageBubbleView.h b/Session/Signal/ConversationView/Cells/OWSMessageBubbleView.h similarity index 100% rename from Session/src/ViewControllers/ConversationView/Cells/OWSMessageBubbleView.h rename to Session/Signal/ConversationView/Cells/OWSMessageBubbleView.h diff --git a/Session/src/ViewControllers/ConversationView/Cells/OWSMessageBubbleView.m b/Session/Signal/ConversationView/Cells/OWSMessageBubbleView.m similarity index 100% rename from Session/src/ViewControllers/ConversationView/Cells/OWSMessageBubbleView.m rename to Session/Signal/ConversationView/Cells/OWSMessageBubbleView.m diff --git a/Session/src/ViewControllers/ConversationView/Cells/OWSMessageCell.h b/Session/Signal/ConversationView/Cells/OWSMessageCell.h similarity index 100% rename from Session/src/ViewControllers/ConversationView/Cells/OWSMessageCell.h rename to Session/Signal/ConversationView/Cells/OWSMessageCell.h diff --git a/Session/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m b/Session/Signal/ConversationView/Cells/OWSMessageCell.m similarity index 100% rename from Session/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m rename to Session/Signal/ConversationView/Cells/OWSMessageCell.m diff --git a/Session/src/ViewControllers/ConversationView/Cells/OWSMessageFooterView.h b/Session/Signal/ConversationView/Cells/OWSMessageFooterView.h similarity index 100% rename from Session/src/ViewControllers/ConversationView/Cells/OWSMessageFooterView.h rename to Session/Signal/ConversationView/Cells/OWSMessageFooterView.h diff --git a/Session/src/ViewControllers/ConversationView/Cells/OWSMessageFooterView.m b/Session/Signal/ConversationView/Cells/OWSMessageFooterView.m similarity index 100% rename from Session/src/ViewControllers/ConversationView/Cells/OWSMessageFooterView.m rename to Session/Signal/ConversationView/Cells/OWSMessageFooterView.m diff --git a/Session/src/ViewControllers/ConversationView/Cells/OWSMessageHeaderView.h b/Session/Signal/ConversationView/Cells/OWSMessageHeaderView.h similarity index 100% rename from Session/src/ViewControllers/ConversationView/Cells/OWSMessageHeaderView.h rename to Session/Signal/ConversationView/Cells/OWSMessageHeaderView.h diff --git a/Session/src/ViewControllers/ConversationView/Cells/OWSMessageHeaderView.m b/Session/Signal/ConversationView/Cells/OWSMessageHeaderView.m similarity index 100% rename from Session/src/ViewControllers/ConversationView/Cells/OWSMessageHeaderView.m rename to Session/Signal/ConversationView/Cells/OWSMessageHeaderView.m diff --git a/Session/src/ViewControllers/ConversationView/Cells/OWSMessageTextView.h b/Session/Signal/ConversationView/Cells/OWSMessageTextView.h similarity index 100% rename from Session/src/ViewControllers/ConversationView/Cells/OWSMessageTextView.h rename to Session/Signal/ConversationView/Cells/OWSMessageTextView.h diff --git a/Session/src/ViewControllers/ConversationView/Cells/OWSMessageTextView.m b/Session/Signal/ConversationView/Cells/OWSMessageTextView.m similarity index 100% rename from Session/src/ViewControllers/ConversationView/Cells/OWSMessageTextView.m rename to Session/Signal/ConversationView/Cells/OWSMessageTextView.m diff --git a/Session/src/ViewControllers/ConversationView/Cells/OWSMessageTimerView.h b/Session/Signal/ConversationView/Cells/OWSMessageTimerView.h similarity index 100% rename from Session/src/ViewControllers/ConversationView/Cells/OWSMessageTimerView.h rename to Session/Signal/ConversationView/Cells/OWSMessageTimerView.h diff --git a/Session/src/ViewControllers/ConversationView/Cells/OWSMessageTimerView.m b/Session/Signal/ConversationView/Cells/OWSMessageTimerView.m similarity index 100% rename from Session/src/ViewControllers/ConversationView/Cells/OWSMessageTimerView.m rename to Session/Signal/ConversationView/Cells/OWSMessageTimerView.m diff --git a/Session/src/ViewControllers/ConversationView/Cells/OWSQuotedMessageView.h b/Session/Signal/ConversationView/Cells/OWSQuotedMessageView.h similarity index 100% rename from Session/src/ViewControllers/ConversationView/Cells/OWSQuotedMessageView.h rename to Session/Signal/ConversationView/Cells/OWSQuotedMessageView.h diff --git a/Session/src/ViewControllers/ConversationView/Cells/OWSQuotedMessageView.m b/Session/Signal/ConversationView/Cells/OWSQuotedMessageView.m similarity index 100% rename from Session/src/ViewControllers/ConversationView/Cells/OWSQuotedMessageView.m rename to Session/Signal/ConversationView/Cells/OWSQuotedMessageView.m diff --git a/Session/src/ViewControllers/ConversationView/Cells/OWSSystemMessageCell.h b/Session/Signal/ConversationView/Cells/OWSSystemMessageCell.h similarity index 100% rename from Session/src/ViewControllers/ConversationView/Cells/OWSSystemMessageCell.h rename to Session/Signal/ConversationView/Cells/OWSSystemMessageCell.h diff --git a/Session/src/ViewControllers/ConversationView/Cells/OWSSystemMessageCell.m b/Session/Signal/ConversationView/Cells/OWSSystemMessageCell.m similarity index 100% rename from Session/src/ViewControllers/ConversationView/Cells/OWSSystemMessageCell.m rename to Session/Signal/ConversationView/Cells/OWSSystemMessageCell.m diff --git a/Session/src/ViewControllers/ConversationView/Cells/TypingIndicatorCell.swift b/Session/Signal/ConversationView/Cells/TypingIndicatorCell.swift similarity index 100% rename from Session/src/ViewControllers/ConversationView/Cells/TypingIndicatorCell.swift rename to Session/Signal/ConversationView/Cells/TypingIndicatorCell.swift diff --git a/Session/src/ViewControllers/ConversationView/ConversationCollectionView.h b/Session/Signal/ConversationView/ConversationCollectionView.h similarity index 100% rename from Session/src/ViewControllers/ConversationView/ConversationCollectionView.h rename to Session/Signal/ConversationView/ConversationCollectionView.h diff --git a/Session/src/ViewControllers/ConversationView/ConversationCollectionView.m b/Session/Signal/ConversationView/ConversationCollectionView.m similarity index 100% rename from Session/src/ViewControllers/ConversationView/ConversationCollectionView.m rename to Session/Signal/ConversationView/ConversationCollectionView.m diff --git a/Session/src/ViewControllers/ConversationView/ConversationHeaderView.swift b/Session/Signal/ConversationView/ConversationHeaderView.swift similarity index 100% rename from Session/src/ViewControllers/ConversationView/ConversationHeaderView.swift rename to Session/Signal/ConversationView/ConversationHeaderView.swift diff --git a/Session/src/ViewControllers/ConversationView/ConversationInputTextView.h b/Session/Signal/ConversationView/ConversationInputTextView.h similarity index 100% rename from Session/src/ViewControllers/ConversationView/ConversationInputTextView.h rename to Session/Signal/ConversationView/ConversationInputTextView.h diff --git a/Session/src/ViewControllers/ConversationView/ConversationInputTextView.m b/Session/Signal/ConversationView/ConversationInputTextView.m similarity index 100% rename from Session/src/ViewControllers/ConversationView/ConversationInputTextView.m rename to Session/Signal/ConversationView/ConversationInputTextView.m diff --git a/Session/src/ViewControllers/ConversationView/ConversationInputToolbar.h b/Session/Signal/ConversationView/ConversationInputToolbar.h similarity index 100% rename from Session/src/ViewControllers/ConversationView/ConversationInputToolbar.h rename to Session/Signal/ConversationView/ConversationInputToolbar.h diff --git a/Session/src/ViewControllers/ConversationView/ConversationInputToolbar.m b/Session/Signal/ConversationView/ConversationInputToolbar.m similarity index 100% rename from Session/src/ViewControllers/ConversationView/ConversationInputToolbar.m rename to Session/Signal/ConversationView/ConversationInputToolbar.m diff --git a/Session/src/ViewControllers/ConversationView/ConversationMessageMapping.swift b/Session/Signal/ConversationView/ConversationMessageMapping.swift similarity index 100% rename from Session/src/ViewControllers/ConversationView/ConversationMessageMapping.swift rename to Session/Signal/ConversationView/ConversationMessageMapping.swift diff --git a/Session/src/ViewControllers/ConversationView/ConversationScrollButton.h b/Session/Signal/ConversationView/ConversationScrollButton.h similarity index 100% rename from Session/src/ViewControllers/ConversationView/ConversationScrollButton.h rename to Session/Signal/ConversationView/ConversationScrollButton.h diff --git a/Session/src/ViewControllers/ConversationView/ConversationScrollButton.m b/Session/Signal/ConversationView/ConversationScrollButton.m similarity index 100% rename from Session/src/ViewControllers/ConversationView/ConversationScrollButton.m rename to Session/Signal/ConversationView/ConversationScrollButton.m diff --git a/Session/src/ViewControllers/ConversationView/ConversationViewController.h b/Session/Signal/ConversationView/ConversationViewController.h similarity index 100% rename from Session/src/ViewControllers/ConversationView/ConversationViewController.h rename to Session/Signal/ConversationView/ConversationViewController.h diff --git a/Session/src/ViewControllers/ConversationView/ConversationViewController.m b/Session/Signal/ConversationView/ConversationViewController.m similarity index 99% rename from Session/src/ViewControllers/ConversationView/ConversationViewController.m rename to Session/Signal/ConversationView/ConversationViewController.m index 43a93572b..4479d1eca 100644 --- a/Session/src/ViewControllers/ConversationView/ConversationViewController.m +++ b/Session/Signal/ConversationView/ConversationViewController.m @@ -16,7 +16,6 @@ #import "ConversationViewLayout.h" #import "ConversationViewModel.h" #import "DateUtil.h" -#import "DebugUITableViewController.h" #import "FingerprintViewController.h" #import #import "OWSAudioPlayer.h" diff --git a/Session/src/ViewControllers/ConversationView/ConversationViewItem.h b/Session/Signal/ConversationView/ConversationViewItem.h similarity index 100% rename from Session/src/ViewControllers/ConversationView/ConversationViewItem.h rename to Session/Signal/ConversationView/ConversationViewItem.h diff --git a/Session/src/ViewControllers/ConversationView/ConversationViewItem.m b/Session/Signal/ConversationView/ConversationViewItem.m similarity index 100% rename from Session/src/ViewControllers/ConversationView/ConversationViewItem.m rename to Session/Signal/ConversationView/ConversationViewItem.m diff --git a/Session/src/ViewControllers/ConversationView/ConversationViewLayout.h b/Session/Signal/ConversationView/ConversationViewLayout.h similarity index 100% rename from Session/src/ViewControllers/ConversationView/ConversationViewLayout.h rename to Session/Signal/ConversationView/ConversationViewLayout.h diff --git a/Session/src/ViewControllers/ConversationView/ConversationViewLayout.m b/Session/Signal/ConversationView/ConversationViewLayout.m similarity index 100% rename from Session/src/ViewControllers/ConversationView/ConversationViewLayout.m rename to Session/Signal/ConversationView/ConversationViewLayout.m diff --git a/Session/src/ViewControllers/ConversationView/ConversationViewModel.h b/Session/Signal/ConversationView/ConversationViewModel.h similarity index 100% rename from Session/src/ViewControllers/ConversationView/ConversationViewModel.h rename to Session/Signal/ConversationView/ConversationViewModel.h diff --git a/Session/src/ViewControllers/ConversationView/ConversationViewModel.m b/Session/Signal/ConversationView/ConversationViewModel.m similarity index 100% rename from Session/src/ViewControllers/ConversationView/ConversationViewModel.m rename to Session/Signal/ConversationView/ConversationViewModel.m diff --git a/Session/src/ViewControllers/ConversationView/TypingIndicatorInteraction.swift b/Session/Signal/ConversationView/TypingIndicatorInteraction.swift similarity index 100% rename from Session/src/ViewControllers/ConversationView/TypingIndicatorInteraction.swift rename to Session/Signal/ConversationView/TypingIndicatorInteraction.swift diff --git a/Session/src/ViewControllers/CropScaleImageViewController.swift b/Session/Signal/CropScaleImageViewController.swift similarity index 100% rename from Session/src/ViewControllers/CropScaleImageViewController.swift rename to Session/Signal/CropScaleImageViewController.swift diff --git a/Session/src/util/DateUtil.h b/Session/Signal/DateUtil.h similarity index 100% rename from Session/src/util/DateUtil.h rename to Session/Signal/DateUtil.h diff --git a/Session/src/util/DateUtil.m b/Session/Signal/DateUtil.m similarity index 100% rename from Session/src/util/DateUtil.m rename to Session/Signal/DateUtil.m diff --git a/Session/src/views/DismissableTextField.swift b/Session/Signal/DismissableTextField.swift similarity index 100% rename from Session/src/views/DismissableTextField.swift rename to Session/Signal/DismissableTextField.swift diff --git a/Session/src/ViewControllers/AppSettings/DomainFrontingCountryViewController.h b/Session/Signal/DomainFrontingCountryViewController.h similarity index 100% rename from Session/src/ViewControllers/AppSettings/DomainFrontingCountryViewController.h rename to Session/Signal/DomainFrontingCountryViewController.h diff --git a/Session/src/ViewControllers/AppSettings/DomainFrontingCountryViewController.m b/Session/Signal/DomainFrontingCountryViewController.m similarity index 100% rename from Session/src/ViewControllers/AppSettings/DomainFrontingCountryViewController.m rename to Session/Signal/DomainFrontingCountryViewController.m diff --git a/Session/src/environment/ExperienceUpgrades/ExperienceUpgrade.swift b/Session/Signal/ExperienceUpgrade.swift similarity index 100% rename from Session/src/environment/ExperienceUpgrades/ExperienceUpgrade.swift rename to Session/Signal/ExperienceUpgrade.swift diff --git a/Session/src/environment/ExperienceUpgrades/ExperienceUpgradeFinder.swift b/Session/Signal/ExperienceUpgradeFinder.swift similarity index 100% rename from Session/src/environment/ExperienceUpgrades/ExperienceUpgradeFinder.swift rename to Session/Signal/ExperienceUpgradeFinder.swift diff --git a/Session/src/ViewControllers/ThreadSettings/FingerprintViewController.h b/Session/Signal/FingerprintViewController.h similarity index 100% rename from Session/src/ViewControllers/ThreadSettings/FingerprintViewController.h rename to Session/Signal/FingerprintViewController.h diff --git a/Session/src/ViewControllers/ThreadSettings/FingerprintViewController.m b/Session/Signal/FingerprintViewController.m similarity index 100% rename from Session/src/ViewControllers/ThreadSettings/FingerprintViewController.m rename to Session/Signal/FingerprintViewController.m diff --git a/Session/src/ViewControllers/ThreadSettings/FingerprintViewScanController.h b/Session/Signal/FingerprintViewScanController.h similarity index 100% rename from Session/src/ViewControllers/ThreadSettings/FingerprintViewScanController.h rename to Session/Signal/FingerprintViewScanController.h diff --git a/Session/src/ViewControllers/ThreadSettings/FingerprintViewScanController.m b/Session/Signal/FingerprintViewScanController.m similarity index 100% rename from Session/src/ViewControllers/ThreadSettings/FingerprintViewScanController.m rename to Session/Signal/FingerprintViewScanController.m diff --git a/Session/src/ViewControllers/GifPicker/GifPickerCell.swift b/Session/Signal/GifPickerCell.swift similarity index 100% rename from Session/src/ViewControllers/GifPicker/GifPickerCell.swift rename to Session/Signal/GifPickerCell.swift diff --git a/Session/src/ViewControllers/GifPicker/GifPickerLayout.swift b/Session/Signal/GifPickerLayout.swift similarity index 100% rename from Session/src/ViewControllers/GifPicker/GifPickerLayout.swift rename to Session/Signal/GifPickerLayout.swift diff --git a/Session/src/ViewControllers/GifPicker/GifPickerViewController.swift b/Session/Signal/GifPickerViewController.swift similarity index 100% rename from Session/src/ViewControllers/GifPicker/GifPickerViewController.swift rename to Session/Signal/GifPickerViewController.swift diff --git a/Session/src/network/GiphyAPI.swift b/Session/Signal/GiphyAPI.swift similarity index 100% rename from Session/src/network/GiphyAPI.swift rename to Session/Signal/GiphyAPI.swift diff --git a/Session/src/network/GiphyDownloader.swift b/Session/Signal/GiphyDownloader.swift similarity index 100% rename from Session/src/network/GiphyDownloader.swift rename to Session/Signal/GiphyDownloader.swift diff --git a/Session/src/views/GroupTableViewCell.swift b/Session/Signal/GroupTableViewCell.swift similarity index 100% rename from Session/src/views/GroupTableViewCell.swift rename to Session/Signal/GroupTableViewCell.swift diff --git a/Session/src/UserInterface/HapticFeedback.swift b/Session/Signal/HapticFeedback.swift similarity index 100% rename from Session/src/UserInterface/HapticFeedback.swift rename to Session/Signal/HapticFeedback.swift diff --git a/Session/src/ViewControllers/Photos/ImagePickerController.swift b/Session/Signal/ImagePickerController.swift similarity index 100% rename from Session/src/ViewControllers/Photos/ImagePickerController.swift rename to Session/Signal/ImagePickerController.swift diff --git a/Session/src/ViewControllers/InviteFlow.swift b/Session/Signal/InviteFlow.swift similarity index 100% rename from Session/src/ViewControllers/InviteFlow.swift rename to Session/Signal/InviteFlow.swift diff --git a/Session/src/util/Launch Screen.storyboard b/Session/Signal/Launch Screen.storyboard similarity index 100% rename from Session/src/util/Launch Screen.storyboard rename to Session/Signal/Launch Screen.storyboard diff --git a/Session/src/UserInterface/Notifications/LegacyNotificationsAdaptee.swift b/Session/Signal/LegacyNotificationsAdaptee.swift similarity index 100% rename from Session/src/UserInterface/Notifications/LegacyNotificationsAdaptee.swift rename to Session/Signal/LegacyNotificationsAdaptee.swift diff --git a/Session/src/views/LinkPreviewView.swift b/Session/Signal/LinkPreviewView.swift similarity index 100% rename from Session/src/views/LinkPreviewView.swift rename to Session/Signal/LinkPreviewView.swift diff --git a/Session/src/ViewControllers/LoadingViewController.swift b/Session/Signal/LoadingViewController.swift similarity index 100% rename from Session/src/ViewControllers/LoadingViewController.swift rename to Session/Signal/LoadingViewController.swift diff --git a/Session/src/ViewControllers/LongTextViewController.swift b/Session/Signal/LongTextViewController.swift similarity index 100% rename from Session/src/ViewControllers/LongTextViewController.swift rename to Session/Signal/LongTextViewController.swift diff --git a/Session/src/Storyboard/Main.storyboard b/Session/Signal/Main.storyboard similarity index 100% rename from Session/src/Storyboard/Main.storyboard rename to Session/Signal/Main.storyboard diff --git a/Session/src/util/MainAppContext.h b/Session/Signal/MainAppContext.h similarity index 100% rename from Session/src/util/MainAppContext.h rename to Session/Signal/MainAppContext.h diff --git a/Session/src/util/MainAppContext.m b/Session/Signal/MainAppContext.m similarity index 100% rename from Session/src/util/MainAppContext.m rename to Session/Signal/MainAppContext.m diff --git a/Session/src/views/MarqueeLabel.swift b/Session/Signal/MarqueeLabel.swift similarity index 100% rename from Session/src/views/MarqueeLabel.swift rename to Session/Signal/MarqueeLabel.swift diff --git a/Session/src/ViewControllers/MediaDetailViewController.h b/Session/Signal/MediaDetailViewController.h similarity index 100% rename from Session/src/ViewControllers/MediaDetailViewController.h rename to Session/Signal/MediaDetailViewController.h diff --git a/Session/src/ViewControllers/MediaDetailViewController.m b/Session/Signal/MediaDetailViewController.m similarity index 100% rename from Session/src/ViewControllers/MediaDetailViewController.m rename to Session/Signal/MediaDetailViewController.m diff --git a/Session/src/ViewControllers/MediaGalleryViewController.swift b/Session/Signal/MediaGalleryViewController.swift similarity index 100% rename from Session/src/ViewControllers/MediaGalleryViewController.swift rename to Session/Signal/MediaGalleryViewController.swift diff --git a/Session/src/ViewControllers/MediaPageViewController.swift b/Session/Signal/MediaPageViewController.swift similarity index 100% rename from Session/src/ViewControllers/MediaPageViewController.swift rename to Session/Signal/MediaPageViewController.swift diff --git a/Session/src/ViewControllers/MediaTileViewController.swift b/Session/Signal/MediaTileViewController.swift similarity index 100% rename from Session/src/ViewControllers/MediaTileViewController.swift rename to Session/Signal/MediaTileViewController.swift diff --git a/Session/src/ViewControllers/MenuActionsViewController.swift b/Session/Signal/MenuActionsViewController.swift similarity index 100% rename from Session/src/ViewControllers/MenuActionsViewController.swift rename to Session/Signal/MenuActionsViewController.swift diff --git a/Session/src/Models/MessageActions.swift b/Session/Signal/MessageActions.swift similarity index 100% rename from Session/src/Models/MessageActions.swift rename to Session/Signal/MessageActions.swift diff --git a/Session/src/ViewControllers/MessageDetailViewController.swift b/Session/Signal/MessageDetailViewController.swift similarity index 100% rename from Session/src/ViewControllers/MessageDetailViewController.swift rename to Session/Signal/MessageDetailViewController.swift diff --git a/Session/src/Jobs/MessageFetcherJob.swift b/Session/Signal/MessageFetcherJob.swift similarity index 100% rename from Session/src/Jobs/MessageFetcherJob.swift rename to Session/Signal/MessageFetcherJob.swift diff --git a/Session/src/ViewControllers/Utils/MessageRecipientStatusUtils.swift b/Session/Signal/MessageRecipientStatusUtils.swift similarity index 100% rename from Session/src/ViewControllers/Utils/MessageRecipientStatusUtils.swift rename to Session/Signal/MessageRecipientStatusUtils.swift diff --git a/Session/src/views/NeverClearView.swift b/Session/Signal/NeverClearView.swift similarity index 100% rename from Session/src/views/NeverClearView.swift rename to Session/Signal/NeverClearView.swift diff --git a/Session/src/call/NonCallKitCallUIAdaptee.swift b/Session/Signal/NonCallKitCallUIAdaptee.swift similarity index 100% rename from Session/src/call/NonCallKitCallUIAdaptee.swift rename to Session/Signal/NonCallKitCallUIAdaptee.swift diff --git a/Session/src/ViewControllers/AppSettings/NotificationSettingsOptionsViewController.h b/Session/Signal/NotificationSettingsOptionsViewController.h similarity index 100% rename from Session/src/ViewControllers/AppSettings/NotificationSettingsOptionsViewController.h rename to Session/Signal/NotificationSettingsOptionsViewController.h diff --git a/Session/src/ViewControllers/AppSettings/NotificationSettingsOptionsViewController.m b/Session/Signal/NotificationSettingsOptionsViewController.m similarity index 100% rename from Session/src/ViewControllers/AppSettings/NotificationSettingsOptionsViewController.m rename to Session/Signal/NotificationSettingsOptionsViewController.m diff --git a/Session/src/ViewControllers/AppSettings/NotificationSettingsViewController.h b/Session/Signal/NotificationSettingsViewController.h similarity index 100% rename from Session/src/ViewControllers/AppSettings/NotificationSettingsViewController.h rename to Session/Signal/NotificationSettingsViewController.h diff --git a/Session/src/ViewControllers/AppSettings/NotificationSettingsViewController.m b/Session/Signal/NotificationSettingsViewController.m similarity index 100% rename from Session/src/ViewControllers/AppSettings/NotificationSettingsViewController.m rename to Session/Signal/NotificationSettingsViewController.m diff --git a/Session/src/ViewControllers/ThreadSettings/OWSAddToContactViewController.h b/Session/Signal/OWSAddToContactViewController.h similarity index 100% rename from Session/src/ViewControllers/ThreadSettings/OWSAddToContactViewController.h rename to Session/Signal/OWSAddToContactViewController.h diff --git a/Session/src/ViewControllers/ThreadSettings/OWSAddToContactViewController.m b/Session/Signal/OWSAddToContactViewController.m similarity index 100% rename from Session/src/ViewControllers/ThreadSettings/OWSAddToContactViewController.m rename to Session/Signal/OWSAddToContactViewController.m diff --git a/Session/src/util/OWSAnalytics.swift b/Session/Signal/OWSAnalytics.swift similarity index 100% rename from Session/src/util/OWSAnalytics.swift rename to Session/Signal/OWSAnalytics.swift diff --git a/Session/src/util/Backup/OWSBackup.h b/Session/Signal/OWSBackup.h similarity index 100% rename from Session/src/util/Backup/OWSBackup.h rename to Session/Signal/OWSBackup.h diff --git a/Session/src/util/Backup/OWSBackup.m b/Session/Signal/OWSBackup.m similarity index 100% rename from Session/src/util/Backup/OWSBackup.m rename to Session/Signal/OWSBackup.m diff --git a/Session/src/util/Backup/OWSBackupAPI.swift b/Session/Signal/OWSBackupAPI.swift similarity index 100% rename from Session/src/util/Backup/OWSBackupAPI.swift rename to Session/Signal/OWSBackupAPI.swift diff --git a/Session/src/util/Backup/OWSBackupExportJob.h b/Session/Signal/OWSBackupExportJob.h similarity index 100% rename from Session/src/util/Backup/OWSBackupExportJob.h rename to Session/Signal/OWSBackupExportJob.h diff --git a/Session/src/util/Backup/OWSBackupExportJob.m b/Session/Signal/OWSBackupExportJob.m similarity index 100% rename from Session/src/util/Backup/OWSBackupExportJob.m rename to Session/Signal/OWSBackupExportJob.m diff --git a/Session/src/util/Backup/OWSBackupIO.h b/Session/Signal/OWSBackupIO.h similarity index 100% rename from Session/src/util/Backup/OWSBackupIO.h rename to Session/Signal/OWSBackupIO.h diff --git a/Session/src/util/Backup/OWSBackupIO.m b/Session/Signal/OWSBackupIO.m similarity index 100% rename from Session/src/util/Backup/OWSBackupIO.m rename to Session/Signal/OWSBackupIO.m diff --git a/Session/src/util/Backup/OWSBackupImportJob.h b/Session/Signal/OWSBackupImportJob.h similarity index 100% rename from Session/src/util/Backup/OWSBackupImportJob.h rename to Session/Signal/OWSBackupImportJob.h diff --git a/Session/src/util/Backup/OWSBackupImportJob.m b/Session/Signal/OWSBackupImportJob.m similarity index 100% rename from Session/src/util/Backup/OWSBackupImportJob.m rename to Session/Signal/OWSBackupImportJob.m diff --git a/Session/src/util/Backup/OWSBackupJob.h b/Session/Signal/OWSBackupJob.h similarity index 100% rename from Session/src/util/Backup/OWSBackupJob.h rename to Session/Signal/OWSBackupJob.h diff --git a/Session/src/util/Backup/OWSBackupJob.m b/Session/Signal/OWSBackupJob.m similarity index 100% rename from Session/src/util/Backup/OWSBackupJob.m rename to Session/Signal/OWSBackupJob.m diff --git a/Session/src/util/Backup/OWSBackupLazyRestore.swift b/Session/Signal/OWSBackupLazyRestore.swift similarity index 100% rename from Session/src/util/Backup/OWSBackupLazyRestore.swift rename to Session/Signal/OWSBackupLazyRestore.swift diff --git a/Session/src/ViewControllers/AppSettings/OWSBackupSettingsViewController.h b/Session/Signal/OWSBackupSettingsViewController.h similarity index 100% rename from Session/src/ViewControllers/AppSettings/OWSBackupSettingsViewController.h rename to Session/Signal/OWSBackupSettingsViewController.h diff --git a/Session/src/ViewControllers/AppSettings/OWSBackupSettingsViewController.m b/Session/Signal/OWSBackupSettingsViewController.m similarity index 100% rename from Session/src/ViewControllers/AppSettings/OWSBackupSettingsViewController.m rename to Session/Signal/OWSBackupSettingsViewController.m diff --git a/Session/src/views/OWSBezierPathView.h b/Session/Signal/OWSBezierPathView.h similarity index 100% rename from Session/src/views/OWSBezierPathView.h rename to Session/Signal/OWSBezierPathView.h diff --git a/Session/src/views/OWSBezierPathView.m b/Session/Signal/OWSBezierPathView.m similarity index 100% rename from Session/src/views/OWSBezierPathView.m rename to Session/Signal/OWSBezierPathView.m diff --git a/Session/src/ViewControllers/ThreadSettings/OWSConversationSettingsViewController.h b/Session/Signal/OWSConversationSettingsViewController.h similarity index 100% rename from Session/src/ViewControllers/ThreadSettings/OWSConversationSettingsViewController.h rename to Session/Signal/OWSConversationSettingsViewController.h diff --git a/Session/src/ViewControllers/ThreadSettings/OWSConversationSettingsViewController.m b/Session/Signal/OWSConversationSettingsViewController.m similarity index 100% rename from Session/src/ViewControllers/ThreadSettings/OWSConversationSettingsViewController.m rename to Session/Signal/OWSConversationSettingsViewController.m diff --git a/Session/src/ViewControllers/ThreadSettings/OWSConversationSettingsViewDelegate.h b/Session/Signal/OWSConversationSettingsViewDelegate.h similarity index 100% rename from Session/src/ViewControllers/ThreadSettings/OWSConversationSettingsViewDelegate.h rename to Session/Signal/OWSConversationSettingsViewDelegate.h diff --git a/Session/src/Models/OWSDeviceProvisioningURLParser.h b/Session/Signal/OWSDeviceProvisioningURLParser.h similarity index 100% rename from Session/src/Models/OWSDeviceProvisioningURLParser.h rename to Session/Signal/OWSDeviceProvisioningURLParser.h diff --git a/Session/src/Models/OWSDeviceProvisioningURLParser.m b/Session/Signal/OWSDeviceProvisioningURLParser.m similarity index 100% rename from Session/src/Models/OWSDeviceProvisioningURLParser.m rename to Session/Signal/OWSDeviceProvisioningURLParser.m diff --git a/Session/src/views/OWSDeviceTableViewCell.h b/Session/Signal/OWSDeviceTableViewCell.h similarity index 100% rename from Session/src/views/OWSDeviceTableViewCell.h rename to Session/Signal/OWSDeviceTableViewCell.h diff --git a/Session/src/views/OWSDeviceTableViewCell.m b/Session/Signal/OWSDeviceTableViewCell.m similarity index 100% rename from Session/src/views/OWSDeviceTableViewCell.m rename to Session/Signal/OWSDeviceTableViewCell.m diff --git a/Session/src/ViewControllers/OWSImagePickerController.swift b/Session/Signal/OWSImagePickerController.swift similarity index 100% rename from Session/src/ViewControllers/OWSImagePickerController.swift rename to Session/Signal/OWSImagePickerController.swift diff --git a/Session/src/util/OWSOrphanDataCleaner.h b/Session/Signal/OWSOrphanDataCleaner.h similarity index 100% rename from Session/src/util/OWSOrphanDataCleaner.h rename to Session/Signal/OWSOrphanDataCleaner.h diff --git a/Session/src/util/OWSOrphanDataCleaner.m b/Session/Signal/OWSOrphanDataCleaner.m similarity index 100% rename from Session/src/util/OWSOrphanDataCleaner.m rename to Session/Signal/OWSOrphanDataCleaner.m diff --git a/Session/src/views/OWSProgressView.h b/Session/Signal/OWSProgressView.h similarity index 100% rename from Session/src/views/OWSProgressView.h rename to Session/Signal/OWSProgressView.h diff --git a/Session/src/views/OWSProgressView.m b/Session/Signal/OWSProgressView.m similarity index 100% rename from Session/src/views/OWSProgressView.m rename to Session/Signal/OWSProgressView.m diff --git a/Session/src/ViewControllers/AppSettings/OWSQRCodeScanningViewController.h b/Session/Signal/OWSQRCodeScanningViewController.h similarity index 100% rename from Session/src/ViewControllers/AppSettings/OWSQRCodeScanningViewController.h rename to Session/Signal/OWSQRCodeScanningViewController.h diff --git a/Session/src/ViewControllers/AppSettings/OWSQRCodeScanningViewController.m b/Session/Signal/OWSQRCodeScanningViewController.m similarity index 100% rename from Session/src/ViewControllers/AppSettings/OWSQRCodeScanningViewController.m rename to Session/Signal/OWSQRCodeScanningViewController.m diff --git a/Session/src/util/OWSScreenLockUI.h b/Session/Signal/OWSScreenLockUI.h similarity index 100% rename from Session/src/util/OWSScreenLockUI.h rename to Session/Signal/OWSScreenLockUI.h diff --git a/Session/src/util/OWSScreenLockUI.m b/Session/Signal/OWSScreenLockUI.m similarity index 100% rename from Session/src/util/OWSScreenLockUI.m rename to Session/Signal/OWSScreenLockUI.m diff --git a/Session/src/Jobs/OWSSessionResetJobRecord.h b/Session/Signal/OWSSessionResetJobRecord.h similarity index 100% rename from Session/src/Jobs/OWSSessionResetJobRecord.h rename to Session/Signal/OWSSessionResetJobRecord.h diff --git a/Session/src/Jobs/OWSSessionResetJobRecord.m b/Session/Signal/OWSSessionResetJobRecord.m similarity index 100% rename from Session/src/Jobs/OWSSessionResetJobRecord.m rename to Session/Signal/OWSSessionResetJobRecord.m diff --git a/Session/src/ViewControllers/AppSettings/OWSSoundSettingsViewController.h b/Session/Signal/OWSSoundSettingsViewController.h similarity index 100% rename from Session/src/ViewControllers/AppSettings/OWSSoundSettingsViewController.h rename to Session/Signal/OWSSoundSettingsViewController.h diff --git a/Session/src/ViewControllers/AppSettings/OWSSoundSettingsViewController.m b/Session/Signal/OWSSoundSettingsViewController.m similarity index 100% rename from Session/src/ViewControllers/AppSettings/OWSSoundSettingsViewController.m rename to Session/Signal/OWSSoundSettingsViewController.m diff --git a/Session/src/Generated/OWSWebRTCDataProtos.pb.swift b/Session/Signal/OWSWebRTCDataProtos.pb.swift similarity index 100% rename from Session/src/Generated/OWSWebRTCDataProtos.pb.swift rename to Session/Signal/OWSWebRTCDataProtos.pb.swift diff --git a/Session/src/ViewControllers/Registration/OnboardingCaptchaViewController.swift b/Session/Signal/OnboardingCaptchaViewController.swift similarity index 100% rename from Session/src/ViewControllers/Registration/OnboardingCaptchaViewController.swift rename to Session/Signal/OnboardingCaptchaViewController.swift diff --git a/Session/src/call/OutboundCallInitiator.swift b/Session/Signal/OutboundCallInitiator.swift similarity index 100% rename from Session/src/call/OutboundCallInitiator.swift rename to Session/Signal/OutboundCallInitiator.swift diff --git a/Session/src/util/Pastelog.h b/Session/Signal/Pastelog.h similarity index 100% rename from Session/src/util/Pastelog.h rename to Session/Signal/Pastelog.h diff --git a/Session/src/util/Pastelog.m b/Session/Signal/Pastelog.m similarity index 100% rename from Session/src/util/Pastelog.m rename to Session/Signal/Pastelog.m diff --git a/Session/src/call/PeerConnectionClient.swift b/Session/Signal/PeerConnectionClient.swift similarity index 100% rename from Session/src/call/PeerConnectionClient.swift rename to Session/Signal/PeerConnectionClient.swift diff --git a/Session/src/ViewControllers/Photos/PhotoCapture.swift b/Session/Signal/PhotoCapture.swift similarity index 100% rename from Session/src/ViewControllers/Photos/PhotoCapture.swift rename to Session/Signal/PhotoCapture.swift diff --git a/Session/src/ViewControllers/Photos/PhotoCaptureViewController.swift b/Session/Signal/PhotoCaptureViewController.swift similarity index 100% rename from Session/src/ViewControllers/Photos/PhotoCaptureViewController.swift rename to Session/Signal/PhotoCaptureViewController.swift diff --git a/Session/src/ViewControllers/Photos/PhotoCollectionPickerController.swift b/Session/Signal/PhotoCollectionPickerController.swift similarity index 100% rename from Session/src/ViewControllers/Photos/PhotoCollectionPickerController.swift rename to Session/Signal/PhotoCollectionPickerController.swift diff --git a/Session/src/views/PhotoGridViewCell.swift b/Session/Signal/PhotoGridViewCell.swift similarity index 100% rename from Session/src/views/PhotoGridViewCell.swift rename to Session/Signal/PhotoGridViewCell.swift diff --git a/Session/src/ViewControllers/Photos/PhotoLibrary.swift b/Session/Signal/PhotoLibrary.swift similarity index 100% rename from Session/src/ViewControllers/Photos/PhotoLibrary.swift rename to Session/Signal/PhotoLibrary.swift diff --git a/Session/src/views/PinEntryView.h b/Session/Signal/PinEntryView.h similarity index 100% rename from Session/src/views/PinEntryView.h rename to Session/Signal/PinEntryView.h diff --git a/Session/src/views/PinEntryView.m b/Session/Signal/PinEntryView.m similarity index 100% rename from Session/src/views/PinEntryView.m rename to Session/Signal/PinEntryView.m diff --git a/Session/src/util/Platform.swift b/Session/Signal/Platform.swift similarity index 100% rename from Session/src/util/Platform.swift rename to Session/Signal/Platform.swift diff --git a/Session/src/ViewControllers/AppSettings/PrivacySettingsTableViewController.h b/Session/Signal/PrivacySettingsTableViewController.h similarity index 100% rename from Session/src/ViewControllers/AppSettings/PrivacySettingsTableViewController.h rename to Session/Signal/PrivacySettingsTableViewController.h diff --git a/Session/src/ViewControllers/AppSettings/PrivacySettingsTableViewController.m b/Session/Signal/PrivacySettingsTableViewController.m similarity index 100% rename from Session/src/ViewControllers/AppSettings/PrivacySettingsTableViewController.m rename to Session/Signal/PrivacySettingsTableViewController.m diff --git a/Session/src/environment/PushRegistrationManager.swift b/Session/Signal/PushRegistrationManager.swift similarity index 100% rename from Session/src/environment/PushRegistrationManager.swift rename to Session/Signal/PushRegistrationManager.swift diff --git a/Session/src/views/QuotedReplyPreview.swift b/Session/Signal/QuotedReplyPreview.swift similarity index 100% rename from Session/src/views/QuotedReplyPreview.swift rename to Session/Signal/QuotedReplyPreview.swift diff --git a/Session/src/views/ReminderView.swift b/Session/Signal/ReminderView.swift similarity index 100% rename from Session/src/views/ReminderView.swift rename to Session/Signal/ReminderView.swift diff --git a/Session/src/views/RemoteVideoView.h b/Session/Signal/RemoteVideoView.h similarity index 100% rename from Session/src/views/RemoteVideoView.h rename to Session/Signal/RemoteVideoView.h diff --git a/Session/src/views/RemoteVideoView.m b/Session/Signal/RemoteVideoView.m similarity index 100% rename from Session/src/views/RemoteVideoView.m rename to Session/Signal/RemoteVideoView.m diff --git a/Session/src/ViewControllers/SafetyNumberConfirmationAlert.swift b/Session/Signal/SafetyNumberConfirmationAlert.swift similarity index 100% rename from Session/src/ViewControllers/SafetyNumberConfirmationAlert.swift rename to Session/Signal/SafetyNumberConfirmationAlert.swift diff --git a/Session/src/ViewControllers/Photos/SendMediaNavigationController.swift b/Session/Signal/SendMediaNavigationController.swift similarity index 100% rename from Session/src/ViewControllers/Photos/SendMediaNavigationController.swift rename to Session/Signal/SendMediaNavigationController.swift diff --git a/Session/src/Jobs/SessionResetJob.swift b/Session/Signal/SessionResetJob.swift similarity index 100% rename from Session/src/Jobs/SessionResetJob.swift rename to Session/Signal/SessionResetJob.swift diff --git a/Session/src/ViewControllers/ThreadSettings/ShowGroupMembersViewController.h b/Session/Signal/ShowGroupMembersViewController.h similarity index 100% rename from Session/src/ViewControllers/ThreadSettings/ShowGroupMembersViewController.h rename to Session/Signal/ShowGroupMembersViewController.h diff --git a/Session/src/ViewControllers/ThreadSettings/ShowGroupMembersViewController.m b/Session/Signal/ShowGroupMembersViewController.m similarity index 100% rename from Session/src/ViewControllers/ThreadSettings/ShowGroupMembersViewController.m rename to Session/Signal/ShowGroupMembersViewController.m diff --git a/Session/src/environment/SignalApp.h b/Session/Signal/SignalApp.h similarity index 100% rename from Session/src/environment/SignalApp.h rename to Session/Signal/SignalApp.h diff --git a/Session/src/environment/SignalApp.m b/Session/Signal/SignalApp.m similarity index 100% rename from Session/src/environment/SignalApp.m rename to Session/Signal/SignalApp.m diff --git a/Session/src/call/SignalCall.swift b/Session/Signal/SignalCall.swift similarity index 100% rename from Session/src/call/SignalCall.swift rename to Session/Signal/SignalCall.swift diff --git a/Session/src/ViewControllers/SignalsNavigationController.h b/Session/Signal/SignalsNavigationController.h similarity index 100% rename from Session/src/ViewControllers/SignalsNavigationController.h rename to Session/Signal/SignalsNavigationController.h diff --git a/Session/src/ViewControllers/SignalsNavigationController.m b/Session/Signal/SignalsNavigationController.m similarity index 100% rename from Session/src/ViewControllers/SignalsNavigationController.m rename to Session/Signal/SignalsNavigationController.m diff --git a/Session/src/Jobs/SyncPushTokensJob.swift b/Session/Signal/SyncPushTokensJob.swift similarity index 100% rename from Session/src/Jobs/SyncPushTokensJob.swift rename to Session/Signal/SyncPushTokensJob.swift diff --git a/Session/src/util/TextFieldHelper.swift b/Session/Signal/TextFieldHelper.swift similarity index 100% rename from Session/src/util/TextFieldHelper.swift rename to Session/Signal/TextFieldHelper.swift diff --git a/Session/src/call/TurnServerInfo.swift b/Session/Signal/TurnServerInfo.swift similarity index 100% rename from Session/src/call/TurnServerInfo.swift rename to Session/Signal/TurnServerInfo.swift diff --git a/Session/src/views/TypingIndicatorView.swift b/Session/Signal/TypingIndicatorView.swift similarity index 100% rename from Session/src/views/TypingIndicatorView.swift rename to Session/Signal/TypingIndicatorView.swift diff --git a/Session/src/UIAlerts+iOS9.m b/Session/Signal/UIAlerts+iOS9.m similarity index 100% rename from Session/src/UIAlerts+iOS9.m rename to Session/Signal/UIAlerts+iOS9.m diff --git a/Session/src/UIApplication+OWS.swift b/Session/Signal/UIApplication+OWS.swift similarity index 100% rename from Session/src/UIApplication+OWS.swift rename to Session/Signal/UIApplication+OWS.swift diff --git a/Session/src/util/UI Categories/UIResponder+OWS.swift b/Session/Signal/UIResponder+OWS.swift similarity index 100% rename from Session/src/util/UI Categories/UIResponder+OWS.swift rename to Session/Signal/UIResponder+OWS.swift diff --git a/Session/src/UIStoryboard+OWS.swift b/Session/Signal/UIStoryboard+OWS.swift similarity index 100% rename from Session/src/UIStoryboard+OWS.swift rename to Session/Signal/UIStoryboard+OWS.swift diff --git a/Session/src/util/UIViewController+CameraPermissions.h b/Session/Signal/UIViewController+CameraPermissions.h similarity index 100% rename from Session/src/util/UIViewController+CameraPermissions.h rename to Session/Signal/UIViewController+CameraPermissions.h diff --git a/Session/src/util/UIViewController+Permissions.h b/Session/Signal/UIViewController+Permissions.h similarity index 100% rename from Session/src/util/UIViewController+Permissions.h rename to Session/Signal/UIViewController+Permissions.h diff --git a/Session/src/util/UIViewController+Permissions.m b/Session/Signal/UIViewController+Permissions.m similarity index 100% rename from Session/src/util/UIViewController+Permissions.m rename to Session/Signal/UIViewController+Permissions.m diff --git a/Session/src/ViewControllers/ThreadSettings/UpdateGroupViewController.h b/Session/Signal/UpdateGroupViewController.h similarity index 100% rename from Session/src/ViewControllers/ThreadSettings/UpdateGroupViewController.h rename to Session/Signal/UpdateGroupViewController.h diff --git a/Session/src/ViewControllers/ThreadSettings/UpdateGroupViewController.m b/Session/Signal/UpdateGroupViewController.m similarity index 100% rename from Session/src/ViewControllers/ThreadSettings/UpdateGroupViewController.m rename to Session/Signal/UpdateGroupViewController.m diff --git a/Session/src/UserInterface/Notifications/UserNotificationsAdaptee.swift b/Session/Signal/UserNotificationsAdaptee.swift similarity index 100% rename from Session/src/UserInterface/Notifications/UserNotificationsAdaptee.swift rename to Session/Signal/UserNotificationsAdaptee.swift diff --git a/Session/src/views/VoiceNoteLock.swift b/Session/Signal/VoiceNoteLock.swift similarity index 100% rename from Session/src/views/VoiceNoteLock.swift rename to Session/Signal/VoiceNoteLock.swift diff --git a/Session/src/call/WebRTCCallMessageHandler.swift b/Session/Signal/WebRTCCallMessageHandler.swift similarity index 100% rename from Session/src/call/WebRTCCallMessageHandler.swift rename to Session/Signal/WebRTCCallMessageHandler.swift diff --git a/Session/src/Generated/WebRTCProto.swift b/Session/Signal/WebRTCProto.swift similarity index 100% rename from Session/src/Generated/WebRTCProto.swift rename to Session/Signal/WebRTCProto.swift diff --git a/Session/src/Loki/Utilities/AppearanceUtilities.swift b/Session/Utilities/AppearanceUtilities.swift similarity index 100% rename from Session/src/Loki/Utilities/AppearanceUtilities.swift rename to Session/Utilities/AppearanceUtilities.swift diff --git a/Session/src/Loki/Utilities/AudioUtilities.swift b/Session/Utilities/AudioUtilities.swift similarity index 100% rename from Session/src/Loki/Utilities/AudioUtilities.swift rename to Session/Utilities/AudioUtilities.swift diff --git a/Session/src/Loki/Utilities/BackgroundPoller.swift b/Session/Utilities/BackgroundPoller.swift similarity index 100% rename from Session/src/Loki/Utilities/BackgroundPoller.swift rename to Session/Utilities/BackgroundPoller.swift diff --git a/Session/src/Loki/Utilities/CGRect+Utilities.swift b/Session/Utilities/CGRect+Utilities.swift similarity index 100% rename from Session/src/Loki/Utilities/CGRect+Utilities.swift rename to Session/Utilities/CGRect+Utilities.swift diff --git a/Session/src/Loki/Utilities/ContactUtilities.swift b/Session/Utilities/ContactUtilities.swift similarity index 100% rename from Session/src/Loki/Utilities/ContactUtilities.swift rename to Session/Utilities/ContactUtilities.swift diff --git a/Session/src/Loki/Utilities/IP2Country.swift b/Session/Utilities/IP2Country.swift similarity index 100% rename from Session/src/Loki/Utilities/IP2Country.swift rename to Session/Utilities/IP2Country.swift diff --git a/Session/src/Loki/Utilities/KeyPairGeneration.swift b/Session/Utilities/KeyPairGeneration.swift similarity index 100% rename from Session/src/Loki/Utilities/KeyPairGeneration.swift rename to Session/Utilities/KeyPairGeneration.swift diff --git a/Session/src/Loki/Utilities/KeyPairUtilities.swift b/Session/Utilities/KeyPairUtilities.swift similarity index 100% rename from Session/src/Loki/Utilities/KeyPairUtilities.swift rename to Session/Utilities/KeyPairUtilities.swift diff --git a/Session/src/Loki/Utilities/MentionUtilities.swift b/Session/Utilities/MentionUtilities.swift similarity index 100% rename from Session/src/Loki/Utilities/MentionUtilities.swift rename to Session/Utilities/MentionUtilities.swift diff --git a/Session/src/Loki/Utilities/QRCode.swift b/Session/Utilities/QRCode.swift similarity index 100% rename from Session/src/Loki/Utilities/QRCode.swift rename to Session/Utilities/QRCode.swift diff --git a/Session/src/Loki/Utilities/Sodium+Conversion.swift b/Session/Utilities/Sodium+Conversion.swift similarity index 100% rename from Session/src/Loki/Utilities/Sodium+Conversion.swift rename to Session/Utilities/Sodium+Conversion.swift diff --git a/Session/src/Loki/Utilities/UIImage+Scaling.swift b/Session/Utilities/UIImage+Scaling.swift similarity index 100% rename from Session/src/Loki/Utilities/UIImage+Scaling.swift rename to Session/Utilities/UIImage+Scaling.swift diff --git a/Session/src/Loki/Utilities/UILabel+Interaction.swift b/Session/Utilities/UILabel+Interaction.swift similarity index 100% rename from Session/src/Loki/Utilities/UILabel+Interaction.swift rename to Session/Utilities/UILabel+Interaction.swift diff --git a/Session/src/Loki/Utilities/UIView+Glow.swift b/Session/Utilities/UIView+Glow.swift similarity index 100% rename from Session/src/Loki/Utilities/UIView+Glow.swift rename to Session/Utilities/UIView+Glow.swift diff --git a/Session/src/Loki/Utilities/UIView+Wrapping.swift b/Session/Utilities/UIView+Wrapping.swift similarity index 100% rename from Session/src/Loki/Utilities/UIView+Wrapping.swift rename to Session/Utilities/UIView+Wrapping.swift diff --git a/Session/src/Loki/View Controllers/BaseVC.swift b/Session/View Controllers/BaseVC.swift similarity index 100% rename from Session/src/Loki/View Controllers/BaseVC.swift rename to Session/View Controllers/BaseVC.swift diff --git a/Session/src/Loki/View Controllers/DeviceLinkingModal.swift b/Session/View Controllers/DeviceLinkingModal.swift similarity index 100% rename from Session/src/Loki/View Controllers/DeviceLinkingModal.swift rename to Session/View Controllers/DeviceLinkingModal.swift diff --git a/Session/src/Loki/View Controllers/DeviceLinkingModalDelegate.swift b/Session/View Controllers/DeviceLinkingModalDelegate.swift similarity index 100% rename from Session/src/Loki/View Controllers/DeviceLinkingModalDelegate.swift rename to Session/View Controllers/DeviceLinkingModalDelegate.swift diff --git a/Session/src/Loki/View Controllers/DeviceLinksVC.swift b/Session/View Controllers/DeviceLinksVC.swift similarity index 100% rename from Session/src/Loki/View Controllers/DeviceLinksVC.swift rename to Session/View Controllers/DeviceLinksVC.swift diff --git a/Session/src/Loki/View Controllers/DeviceNameModal.swift b/Session/View Controllers/DeviceNameModal.swift similarity index 100% rename from Session/src/Loki/View Controllers/DeviceNameModal.swift rename to Session/View Controllers/DeviceNameModal.swift diff --git a/Session/src/Loki/View Controllers/DeviceNameModalDelegate.swift b/Session/View Controllers/DeviceNameModalDelegate.swift similarity index 100% rename from Session/src/Loki/View Controllers/DeviceNameModalDelegate.swift rename to Session/View Controllers/DeviceNameModalDelegate.swift diff --git a/Session/src/Loki/View Controllers/DisplayNameVC.swift b/Session/View Controllers/DisplayNameVC.swift similarity index 100% rename from Session/src/Loki/View Controllers/DisplayNameVC.swift rename to Session/View Controllers/DisplayNameVC.swift diff --git a/Session/src/Loki/View Controllers/EditClosedGroupVC.swift b/Session/View Controllers/EditClosedGroupVC.swift similarity index 100% rename from Session/src/Loki/View Controllers/EditClosedGroupVC.swift rename to Session/View Controllers/EditClosedGroupVC.swift diff --git a/Session/src/Loki/View Controllers/GroupMembersVC.swift b/Session/View Controllers/GroupMembersVC.swift similarity index 100% rename from Session/src/Loki/View Controllers/GroupMembersVC.swift rename to Session/View Controllers/GroupMembersVC.swift diff --git a/Session/src/Loki/View Controllers/HomeVC.swift b/Session/View Controllers/HomeVC.swift similarity index 100% rename from Session/src/Loki/View Controllers/HomeVC.swift rename to Session/View Controllers/HomeVC.swift diff --git a/Session/src/Loki/View Controllers/JoinPublicChatVC.swift b/Session/View Controllers/JoinPublicChatVC.swift similarity index 100% rename from Session/src/Loki/View Controllers/JoinPublicChatVC.swift rename to Session/View Controllers/JoinPublicChatVC.swift diff --git a/Session/src/Loki/View Controllers/LandingVC.swift b/Session/View Controllers/LandingVC.swift similarity index 100% rename from Session/src/Loki/View Controllers/LandingVC.swift rename to Session/View Controllers/LandingVC.swift diff --git a/Session/src/Loki/View Controllers/LightModeSheet.swift b/Session/View Controllers/LightModeSheet.swift similarity index 100% rename from Session/src/Loki/View Controllers/LightModeSheet.swift rename to Session/View Controllers/LightModeSheet.swift diff --git a/Session/src/Loki/View Controllers/LinkDeviceVC.swift b/Session/View Controllers/LinkDeviceVC.swift similarity index 100% rename from Session/src/Loki/View Controllers/LinkDeviceVC.swift rename to Session/View Controllers/LinkDeviceVC.swift diff --git a/Session/src/Loki/View Controllers/LinkDeviceVCDelegate.swift b/Session/View Controllers/LinkDeviceVCDelegate.swift similarity index 100% rename from Session/src/Loki/View Controllers/LinkDeviceVCDelegate.swift rename to Session/View Controllers/LinkDeviceVCDelegate.swift diff --git a/Session/src/Loki/View Controllers/Modal.swift b/Session/View Controllers/Modal.swift similarity index 100% rename from Session/src/Loki/View Controllers/Modal.swift rename to Session/View Controllers/Modal.swift diff --git a/Session/src/Loki/View Controllers/MultiDeviceRemovalSheet.swift b/Session/View Controllers/MultiDeviceRemovalSheet.swift similarity index 100% rename from Session/src/Loki/View Controllers/MultiDeviceRemovalSheet.swift rename to Session/View Controllers/MultiDeviceRemovalSheet.swift diff --git a/Session/src/Loki/View Controllers/NewClosedGroupVC.swift b/Session/View Controllers/NewClosedGroupVC.swift similarity index 100% rename from Session/src/Loki/View Controllers/NewClosedGroupVC.swift rename to Session/View Controllers/NewClosedGroupVC.swift diff --git a/Session/src/Loki/View Controllers/NewPrivateChatVC.swift b/Session/View Controllers/NewPrivateChatVC.swift similarity index 100% rename from Session/src/Loki/View Controllers/NewPrivateChatVC.swift rename to Session/View Controllers/NewPrivateChatVC.swift diff --git a/Session/src/Loki/View Controllers/NukeDataModal.swift b/Session/View Controllers/NukeDataModal.swift similarity index 100% rename from Session/src/Loki/View Controllers/NukeDataModal.swift rename to Session/View Controllers/NukeDataModal.swift diff --git a/Session/src/Loki/View Controllers/OpenGroupSuggestionSheet.swift b/Session/View Controllers/OpenGroupSuggestionSheet.swift similarity index 100% rename from Session/src/Loki/View Controllers/OpenGroupSuggestionSheet.swift rename to Session/View Controllers/OpenGroupSuggestionSheet.swift diff --git a/Session/src/Loki/View Controllers/PNModeVC.swift b/Session/View Controllers/PNModeVC.swift similarity index 100% rename from Session/src/Loki/View Controllers/PNModeVC.swift rename to Session/View Controllers/PNModeVC.swift diff --git a/Session/src/Loki/View Controllers/PathVC.swift b/Session/View Controllers/PathVC.swift similarity index 100% rename from Session/src/Loki/View Controllers/PathVC.swift rename to Session/View Controllers/PathVC.swift diff --git a/Session/src/Loki/View Controllers/QRCodeVC.swift b/Session/View Controllers/QRCodeVC.swift similarity index 100% rename from Session/src/Loki/View Controllers/QRCodeVC.swift rename to Session/View Controllers/QRCodeVC.swift diff --git a/Session/src/Loki/View Controllers/RegisterVC.swift b/Session/View Controllers/RegisterVC.swift similarity index 100% rename from Session/src/Loki/View Controllers/RegisterVC.swift rename to Session/View Controllers/RegisterVC.swift diff --git a/Session/src/Loki/View Controllers/RestoreVC.swift b/Session/View Controllers/RestoreVC.swift similarity index 100% rename from Session/src/Loki/View Controllers/RestoreVC.swift rename to Session/View Controllers/RestoreVC.swift diff --git a/Session/src/Loki/View Controllers/ScanQRCodeWrapperVC.swift b/Session/View Controllers/ScanQRCodeWrapperVC.swift similarity index 100% rename from Session/src/Loki/View Controllers/ScanQRCodeWrapperVC.swift rename to Session/View Controllers/ScanQRCodeWrapperVC.swift diff --git a/Session/src/Loki/View Controllers/SeedModal.swift b/Session/View Controllers/SeedModal.swift similarity index 100% rename from Session/src/Loki/View Controllers/SeedModal.swift rename to Session/View Controllers/SeedModal.swift diff --git a/Session/src/Loki/View Controllers/SeedVC.swift b/Session/View Controllers/SeedVC.swift similarity index 100% rename from Session/src/Loki/View Controllers/SeedVC.swift rename to Session/View Controllers/SeedVC.swift diff --git a/Session/src/Loki/View Controllers/SettingsVC.swift b/Session/View Controllers/SettingsVC.swift similarity index 100% rename from Session/src/Loki/View Controllers/SettingsVC.swift rename to Session/View Controllers/SettingsVC.swift diff --git a/Session/src/Loki/View Controllers/Sheet.swift b/Session/View Controllers/Sheet.swift similarity index 100% rename from Session/src/Loki/View Controllers/Sheet.swift rename to Session/View Controllers/Sheet.swift diff --git a/Session/src/Loki/View Controllers/UserSelectionVC.swift b/Session/View Controllers/UserSelectionVC.swift similarity index 100% rename from Session/src/Loki/View Controllers/UserSelectionVC.swift rename to Session/View Controllers/UserSelectionVC.swift diff --git a/Session/iTunesArtwork@3x.png b/Session/iTunesArtwork@3x.png deleted file mode 100644 index 1ebe90b71..000000000 Binary files a/Session/iTunesArtwork@3x.png and /dev/null differ diff --git a/Session/src/UserInterface/OWSLayerView.swift b/Session/src/UserInterface/OWSLayerView.swift deleted file mode 100644 index d1bbbfd05..000000000 --- a/Session/src/UserInterface/OWSLayerView.swift +++ /dev/null @@ -1,50 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -import Foundation - -@objc -class OWSLayerView: UIView { - let layoutCallback: ((UIView) -> Void) - - @objc - public required init(frame: CGRect, layoutCallback : @escaping (UIView) -> Void) { - self.layoutCallback = layoutCallback - super.init(frame: frame) - } - - required init?(coder aDecoder: NSCoder) { - self.layoutCallback = { _ in - } - super.init(coder: aDecoder) - } - - override var bounds: CGRect { - didSet { - updateLayer() - } - } - - override var frame: CGRect { - didSet { - updateLayer() - } - } - - override var center: CGPoint { - didSet { - updateLayer() - } - } - - private func updateLayer() { - // Prevent the shape layer from animating changes. - CATransaction.begin() - CATransaction.setDisableActions(true) - - layoutCallback(self) - - CATransaction.commit() - } -} diff --git a/Session/src/ViewControllers/DebugSettingsTableViewController.m b/Session/src/ViewControllers/DebugSettingsTableViewController.m deleted file mode 100644 index 956c02187..000000000 --- a/Session/src/ViewControllers/DebugSettingsTableViewController.m +++ /dev/null @@ -1,75 +0,0 @@ -// -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. -// - -#import "DebugSettingsTableViewController.h" -#import "UIFont+OWS.h" -#import -#import - -@implementation DebugSettingsTableViewController - -- (void)loadView -{ - self.tableViewStyle = UITableViewStylePlain; - [super loadView]; -} - -- (void)viewDidLoad -{ - [super viewDidLoad]; - - [self.navigationController.navigationBar setTranslucent:NO]; - - self.title = @"Debugging"; - - [self updateTableContents]; -} - -- (void)viewWillAppear:(BOOL)animated -{ - [super viewWillAppear:animated]; - - [self updateTableContents]; -} - -- (void)dealloc -{ - [[NSNotificationCenter defaultCenter] removeObserver:self]; -} - -#pragma mark - Table Contents - -- (void)updateTableContents -{ - OWSTableContents *contents = [OWSTableContents new]; - OWSTableSection *section = [OWSTableSection new]; - - __block NSUInteger threadCount; - __block NSUInteger messageCount; - [TSStorageManager.sharedManager.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - threadCount = [[transaction ext:TSThreadDatabaseViewExtensionName] numberOfItemsInAllGroups]; - messageCount = [[transaction ext:TSMessageDatabaseViewExtensionName] numberOfItemsInAllGroups]; - }]; - - [section addItem:[OWSTableItem labelItemWithText:[NSString stringWithFormat:@"Threads: %zd", threadCount]]]; - [section addItem:[OWSTableItem labelItemWithText:[NSString stringWithFormat:@"Messages: %zd", messageCount]]]; - - [contents addSection:section]; - - self.contents = contents; -} - -#pragma mark - Logging - -+ (NSString *)tag -{ - return [NSString stringWithFormat:@"[%@]", self.class]; -} - -- (NSString *)tag -{ - return self.class.tag; -} - -@end diff --git a/Session/src/ViewControllers/DebugUI/DebugContactsUtils.h b/Session/src/ViewControllers/DebugUI/DebugContactsUtils.h deleted file mode 100644 index 41396a687..000000000 --- a/Session/src/ViewControllers/DebugUI/DebugContactsUtils.h +++ /dev/null @@ -1,25 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -NS_ASSUME_NONNULL_BEGIN - -@class CNContact; - -@interface DebugContactsUtils : NSObject - -+ (NSString *)randomPhoneNumber; - -+ (void)createRandomContacts:(NSUInteger)count; - -+ (void)createRandomContacts:(NSUInteger)count - contactHandler: - (nullable void (^)(CNContact *_Nonnull contact, NSUInteger idx, BOOL *_Nonnull stop))contactHandler; - -+ (void)deleteAllContacts; - -+ (void)deleteAllRandomContacts; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/src/ViewControllers/DebugUI/DebugContactsUtils.m b/Session/src/ViewControllers/DebugUI/DebugContactsUtils.m deleted file mode 100644 index 92f792478..000000000 --- a/Session/src/ViewControllers/DebugUI/DebugContactsUtils.m +++ /dev/null @@ -1,1259 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "DebugContactsUtils.h" -#import "Session-Swift.h" -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@implementation DebugContactsUtils - -+ (NSString *)randomFirstName -{ - NSArray *values = @[ - @"Alice", - @"Arthur", - @"Bertha", - @"Bob", - @"Carol", - @"Carole", - @"Carlos", - @"Charlie", - @"Chuck", - @"Craig", - @"Dan", - @"Dave", - @"David", - @"Erin", - @"Eve", - @"Faythe", - @"Frank", - @"Grace", - @"Heidi", - @"Lilia", - @"Mallory", - @"Mallet", - @"Moxie", - @"Oscar", - @"Peggy", - @"Pat", - @"Paul", - @"Riya", - @"Scott", - @"Sybil", - @"Trent", - @"Ted", - @"Trevor", - @"Trudy", - @"Victor", - @"Vanna", - @"Walter", - @"Wendy", - @"Merlin", - ]; - return values[(NSUInteger)arc4random_uniform((uint32_t)values.count)]; -} - -+ (NSString *)randomLastName -{ - NSArray *values = @[ - @"Smith", - @"Johnson", - @"Williams", - @"Jones", - @"Brown", - @"Davis", - @"Miller", - @"Wilson", - @"Moore", - @"Taylor", - @"Anderson", - @"Thomas", - @"Jackson", - @"White", - @"Harris", - @"Martin", - @"Thompson", - @"Garcia", - @"Martinez", - @"Robinson", - @"Clark", - @"Rodriguez", - @"Lewis", - @"Lee", - @"Walker", - @"Hall", - @"Allen", - @"Young", - @"Hernandez", - @"King", - @"Wright", - @"Lopez", - @"Hill", - @"Scott", - @"Green", - @"Adams", - @"Baker", - @"Gonzalez", - @"Nelson", - @"Carter", - @"Mitchell", - @"Perez", - @"Roberts", - @"Turner", - @"Phillips", - @"Campbell", - @"Parker", - @"Evans", - @"Edwards", - @"Collins", - @"Stewart", - @"Sanchez", - @"Morris", - @"Rogers", - @"Reed", - @"Cook", - @"Morgan", - @"Bell", - @"Murphy", - @"Bailey", - @"Rivera", - @"Cooper", - @"Richardson", - @"Cox", - @"Howard", - @"Ward", - @"Torres", - @"Peterson", - @"Gray", - @"Ramirez", - @"James", - @"Watson", - @"Brooks", - @"Kelly", - @"Sanders", - @"Price", - @"Bennett", - @"Wood", - @"Barnes", - @"Ross", - @"Henderson", - @"Coleman", - @"Jenkins", - @"Perry", - @"Powell", - @"Long", - @"Patterson", - @"Hughes", - @"Flores", - @"Washington", - @"Butler", - @"Simmons", - @"Foster", - @"Gonzales", - @"Bryant", - @"Alexander", - @"Russell", - @"Griffin", - @"Diaz", - @"Hayes", - @"Myers", - @"Ford", - @"Hamilton", - @"Graham", - @"Sullivan", - @"Wallace", - @"Woods", - @"Cole", - @"West", - @"Jordan", - @"Owens", - @"Reynolds", - @"Fisher", - @"Ellis", - @"Harrison", - @"Gibson", - @"Mcdonald", - @"Cruz", - @"Marshall", - @"Ortiz", - @"Gomez", - @"Murray", - @"Freeman", - @"Wells", - @"Webb", - @"Simpson", - @"Stevens", - @"Tucker", - @"Porter", - @"Hunter", - @"Hicks", - @"Crawford", - @"Henry", - @"Boyd", - @"Mason", - @"Morales", - @"Kennedy", - @"Warren", - @"Dixon", - @"Ramos", - @"Reyes", - @"Burns", - @"Gordon", - @"Shaw", - @"Holmes", - @"Rice", - @"Robertson", - @"Hunt", - @"Black", - @"Daniels", - @"Palmer", - @"Mills", - @"Nichols", - @"Grant", - @"Knight", - @"Ferguson", - @"Rose", - @"Stone", - @"Hawkins", - @"Dunn", - @"Perkins", - @"Hudson", - @"Spencer", - @"Gardner", - @"Stephens", - @"Payne", - @"Pierce", - @"Berry", - @"Matthews", - @"Arnold", - @"Wagner", - @"Willis", - @"Ray", - @"Watkins", - @"Olson", - @"Carroll", - @"Duncan", - @"Snyder", - @"Hart", - @"Cunningham", - @"Bradley", - @"Lane", - @"Andrews", - @"Ruiz", - @"Harper", - @"Fox", - @"Riley", - @"Armstrong", - @"Carpenter", - @"Weaver", - @"Greene", - @"Lawrence", - @"Elliott", - @"Chavez", - @"Sims", - @"Austin", - @"Peters", - @"Kelley", - @"Franklin", - @"Lawson", - @"Fields", - @"Gutierrez", - @"Ryan", - @"Schmidt", - @"Carr", - @"Vasquez", - @"Castillo", - @"Wheeler", - @"Chapman", - @"Oliver", - @"Montgomery", - @"Richards", - @"Williamson", - @"Johnston", - @"Banks", - @"Meyer", - @"Bishop", - @"Mccoy", - @"Howell", - @"Alvarez", - @"Morrison", - @"Hansen", - @"Fernandez", - @"Garza", - @"Harvey", - @"Little", - @"Burton", - @"Stanley", - @"Nguyen", - @"George", - @"Jacobs", - @"Reid", - @"Kim", - @"Fuller", - @"Lynch", - @"Dean", - @"Gilbert", - @"Garrett", - @"Romero", - @"Welch", - @"Larson", - @"Frazier", - @"Burke", - @"Hanson", - @"Day", - @"Mendoza", - @"Moreno", - @"Bowman", - @"Medina", - @"Fowler", - @"Brewer", - @"Hoffman", - @"Carlson", - @"Silva", - @"Pearson", - @"Holland", - @"Douglas", - @"Fleming", - @"Jensen", - @"Vargas", - @"Byrd", - @"Davidson", - @"Hopkins", - @"May", - @"Terry", - @"Herrera", - @"Wade", - @"Soto", - @"Walters", - @"Curtis", - @"Neal", - @"Caldwell", - @"Lowe", - @"Jennings", - @"Barnett", - @"Graves", - @"Jimenez", - @"Horton", - @"Shelton", - @"Barrett", - @"O'brien", - @"Castro", - @"Sutton", - @"Gregory", - @"Mckinney", - @"Lucas", - @"Miles", - @"Craig", - @"Rodriquez", - @"Chambers", - @"Holt", - @"Lambert", - @"Fletcher", - @"Watts", - @"Bates", - @"Hale", - @"Rhodes", - @"Pena", - @"Beck", - @"Newman", - @"Haynes", - @"Mcdaniel", - @"Mendez", - @"Bush", - @"Vaughn", - @"Parks", - @"Dawson", - @"Santiago", - @"Norris", - @"Hardy", - @"Love", - @"Steele", - @"Curry", - @"Powers", - @"Schultz", - @"Barker", - @"Guzman", - @"Page", - @"Munoz", - @"Ball", - @"Keller", - @"Chandler", - @"Weber", - @"Leonard", - @"Walsh", - @"Lyons", - @"Ramsey", - @"Wolfe", - @"Schneider", - @"Mullins", - @"Benson", - @"Sharp", - @"Bowen", - @"Daniel", - @"Barber", - @"Cummings", - @"Hines", - @"Baldwin", - @"Griffith", - @"Valdez", - @"Hubbard", - @"Salazar", - @"Reeves", - @"Warner", - @"Stevenson", - @"Burgess", - @"Santos", - @"Tate", - @"Cross", - @"Garner", - @"Mann", - @"Mack", - @"Moss", - @"Thornton", - @"Dennis", - @"Mcgee", - @"Farmer", - @"Delgado", - @"Aguilar", - @"Vega", - @"Glover", - @"Manning", - @"Cohen", - @"Harmon", - @"Rodgers", - @"Robbins", - @"Newton", - @"Todd", - @"Blair", - @"Higgins", - @"Ingram", - @"Reese", - @"Cannon", - @"Strickland", - @"Townsend", - @"Potter", - @"Goodwin", - @"Walton", - @"Rowe", - @"Hampton", - @"Ortega", - @"Patton", - @"Swanson", - @"Joseph", - @"Francis", - @"Goodman", - @"Maldonado", - @"Yates", - @"Becker", - @"Erickson", - @"Hodges", - @"Rios", - @"Conner", - @"Adkins", - @"Webster", - @"Norman", - @"Malone", - @"Hammond", - @"Flowers", - @"Cobb", - @"Moody", - @"Quinn", - @"Blake", - @"Maxwell", - @"Pope", - @"Floyd", - @"Osborne", - @"Paul", - @"Mccarthy", - @"Guerrero", - @"Lindsey", - @"Estrada", - @"Sandoval", - @"Gibbs", - @"Tyler", - @"Gross", - @"Fitzgerald", - @"Stokes", - @"Doyle", - @"Sherman", - @"Saunders", - @"Wise", - @"Colon", - @"Gill", - @"Alvarado", - @"Greer", - @"Padilla", - @"Simon", - @"Waters", - @"Nunez", - @"Ballard", - @"Schwartz", - @"Mcbride", - @"Houston", - @"Christensen", - @"Klein", - @"Pratt", - @"Briggs", - @"Parsons", - @"Mclaughlin", - @"Zimmerman", - @"French", - @"Buchanan", - @"Moran", - @"Copeland", - @"Roy", - @"Pittman", - @"Brady", - @"Mccormick", - @"Holloway", - @"Brock", - @"Poole", - @"Frank", - @"Logan", - @"Owen", - @"Bass", - @"Marsh", - @"Drake", - @"Wong", - @"Jefferson", - @"Park", - @"Morton", - @"Abbott", - @"Sparks", - @"Patrick", - @"Norton", - @"Huff", - @"Clayton", - @"Massey", - @"Lloyd", - @"Figueroa", - @"Carson", - @"Bowers", - @"Roberson", - @"Barton", - @"Tran", - @"Lamb", - @"Harrington", - @"Casey", - @"Boone", - @"Cortez", - @"Clarke", - @"Mathis", - @"Singleton", - @"Wilkins", - @"Cain", - @"Bryan", - @"Underwood", - @"Hogan", - @"Mckenzie", - @"Collier", - @"Luna", - @"Phelps", - @"Mcguire", - @"Allison", - @"Bridges", - @"Wilkerson", - @"Nash", - @"Summers", - @"Atkins", - @"Wilcox", - @"Pitts", - @"Conley", - @"Marquez", - @"Burnett", - @"Richard", - @"Cochran", - @"Chase", - @"Davenport", - @"Hood", - @"Gates", - @"Clay", - @"Ayala", - @"Sawyer", - @"Roman", - @"Vazquez", - @"Dickerson", - @"Hodge", - @"Acosta", - @"Flynn", - @"Espinoza", - @"Nicholson", - @"Monroe", - @"Wolf", - @"Morrow", - @"Kirk", - @"Randall", - @"Anthony", - @"Whitaker", - @"O'connor", - @"Skinner", - @"Ware", - @"Molina", - @"Kirby", - @"Huffman", - @"Bradford", - @"Charles", - @"Gilmore", - @"Dominguez", - @"O'neal", - @"Bruce", - @"Lang", - @"Combs", - @"Kramer", - @"Heath", - @"Hancock", - @"Gallagher", - @"Gaines", - @"Shaffer", - @"Short", - @"Wiggins", - @"Mathews", - @"Mcclain", - @"Fischer", - @"Wall", - @"Small", - @"Melton", - @"Hensley", - @"Bond", - @"Dyer", - @"Cameron", - @"Grimes", - @"Contreras", - @"Christian", - @"Wyatt", - @"Baxter", - @"Snow", - @"Mosley", - @"Shepherd", - @"Larsen", - @"Hoover", - @"Beasley", - @"Glenn", - @"Petersen", - @"Whitehead", - @"Meyers", - @"Keith", - @"Garrison", - @"Vincent", - @"Shields", - @"Horn", - @"Savage", - @"Olsen", - @"Schroeder", - @"Hartman", - @"Woodard", - @"Mueller", - @"Kemp", - @"Deleon", - @"Booth", - @"Patel", - @"Calhoun", - @"Wiley", - @"Eaton", - @"Cline", - @"Navarro", - @"Harrell", - @"Lester", - @"Humphrey", - @"Parrish", - @"Duran", - @"Hutchinson", - @"Hess", - @"Dorsey", - @"Bullock", - @"Robles", - @"Beard", - @"Dalton", - @"Avila", - @"Vance", - @"Rich", - @"Blackwell", - @"York", - @"Johns", - @"Blankenship", - @"Trevino", - @"Salinas", - @"Campos", - @"Pruitt", - @"Moses", - @"Callahan", - @"Golden", - @"Montoya", - @"Hardin", - @"Guerra", - @"Mcdowell", - @"Carey", - @"Stafford", - @"Gallegos", - @"Henson", - @"Wilkinson", - @"Booker", - @"Merritt", - @"Miranda", - @"Atkinson", - @"Orr", - @"Decker", - @"Hobbs", - @"Preston", - @"Tanner", - @"Knox", - @"Pacheco", - @"Stephenson", - @"Glass", - @"Rojas", - @"Serrano", - @"Marks", - @"Hickman", - @"English", - @"Sweeney", - @"Strong", - @"Prince", - @"Mcclure", - @"Conway", - @"Walter", - @"Roth", - @"Maynard", - @"Farrell", - @"Lowery", - @"Hurst", - @"Nixon", - @"Weiss", - @"Trujillo", - @"Ellison", - @"Sloan", - @"Juarez", - @"Winters", - @"Mclean", - @"Randolph", - @"Leon", - @"Boyer", - @"Villarreal", - @"Mccall", - @"Gentry", - @"Carrillo", - @"Kent", - @"Ayers", - @"Lara", - @"Shannon", - @"Sexton", - @"Pace", - @"Hull", - @"Leblanc", - @"Browning", - @"Velasquez", - @"Leach", - @"Chang", - @"House", - @"Sellers", - @"Herring", - @"Noble", - @"Foley", - @"Bartlett", - @"Mercado", - @"Landry", - @"Durham", - @"Walls", - @"Barr", - @"Mckee", - @"Bauer", - @"Rivers", - @"Everett", - @"Bradshaw", - @"Pugh", - @"Velez", - @"Rush", - @"Estes", - @"Dodson", - @"Morse", - @"Sheppard", - @"Weeks", - @"Camacho", - @"Bean", - @"Barron", - @"Livingston", - @"Middleton", - @"Spears", - @"Branch", - @"Blevins", - @"Chen", - @"Kerr", - @"Mcconnell", - @"Hatfield", - @"Harding", - @"Ashley", - @"Solis", - @"Herman", - @"Frost", - @"Giles", - @"Blackburn", - @"William", - @"Pennington", - @"Woodward", - @"Finley", - @"Mcintosh", - @"Koch", - @"Best", - @"Solomon", - @"Mccullough", - @"Dudley", - @"Nolan", - @"Blanchard", - @"Rivas", - @"Brennan", - @"Mejia", - @"Kane", - @"Benton", - @"Joyce", - @"Buckley", - @"Haley", - @"Valentine", - @"Maddox", - @"Russo", - @"Mcknight", - @"Buck", - @"Moon", - @"Mcmillan", - @"Crosby", - @"Berg", - @"Dotson", - @"Mays", - @"Roach", - @"Church", - @"Chan", - @"Richmond", - @"Meadows", - @"Faulkner", - @"O'neill", - @"Knapp", - @"Kline", - @"Barry", - @"Ochoa", - @"Jacobson", - @"Gay", - @"Avery", - @"Hendricks", - @"Horne", - @"Shepard", - @"Hebert", - @"Cherry", - @"Cardenas", - @"Mcintyre", - @"Whitney", - @"Waller", - @"Holman", - @"Donaldson", - @"Cantu", - @"Terrell", - @"Morin", - @"Gillespie", - @"Fuentes", - @"Tillman", - @"Sanford", - @"Bentley", - @"Peck", - @"Key", - @"Salas", - @"Rollins", - @"Gamble", - @"Dickson", - @"Battle", - @"Santana", - @"Cabrera", - @"Cervantes", - @"Howe", - @"Hinton", - @"Hurley", - @"Spence", - @"Zamora", - @"Yang", - @"Mcneil", - @"Suarez", - @"Case", - @"Petty", - @"Gould", - @"Mcfarland", - @"Sampson", - @"Carver", - @"Bray", - @"Rosario", - @"Macdonald", - @"Stout", - @"Hester", - @"Melendez", - @"Dillon", - @"Farley", - @"Hopper", - @"Galloway", - @"Potts", - @"Bernard", - @"Joyner", - @"Stein", - @"Aguirre", - @"Osborn", - @"Mercer", - @"Bender", - @"Franco", - @"Rowland", - @"Sykes", - @"Benjamin", - @"Travis", - @"Pickett", - @"Crane", - @"Sears", - @"Mayo", - @"Dunlap", - @"Hayden", - @"Wilder", - @"Mckay", - @"Coffey", - @"Mccarty", - @"Ewing", - @"Cooley", - @"Vaughan", - @"Bonner", - @"Cotton", - @"Holder", - @"Stark", - @"Ferrell", - @"Cantrell", - @"Fulton", - @"Lynn", - @"Lott", - @"Calderon", - @"Rosa", - @"Pollard", - @"Hooper", - @"Burch", - @"Mullen", - @"Fry", - @"Riddle", - @"Levy", - @"David", - @"Duke", - @"O'donnell", - @"Guy", - @"Michael", - @"Britt", - @"Frederick", - @"Daugherty", - @"Berger", - @"Dillard", - @"Alston", - @"Jarvis", - @"Frye", - @"Riggs", - @"Chaney", - @"Odom", - @"Duffy", - @"Fitzpatrick", - @"Valenzuela", - @"Merrill", - @"Mayer", - @"Alford", - @"Mcpherson", - @"Acevedo", - @"Donovan", - @"Barrera", - @"Albert", - @"Cote", - @"Reilly", - @"Compton", - @"Raymond", - @"Mooney", - @"Mcgowan", - @"Craft", - @"Cleveland", - @"Clemons", - @"Wynn", - @"Nielsen", - @"Baird", - @"Stanton", - @"Snider", - @"Rosales", - @"Bright", - @"Witt", - @"Stuart", - @"Hays", - @"Holden", - @"Rutledge", - @"Kinney", - @"Clements", - @"Castaneda", - @"Slater", - @"Hahn", - @"Emerson", - @"Conrad", - @"Burks", - @"Delaney", - @"Pate", - @"Lancaster", - @"Sweet", - @"Justice", - @"Tyson", - @"Sharpe", - @"Whitfield", - @"Talley", - @"Macias", - @"Irwin", - @"Burris", - @"Ratliff", - @"Mccray", - @"Madden", - @"Kaufman", - @"Beach", - @"Goff", - @"Cash", - @"Bolton", - @"Mcfadden", - @"Levine", - @"Good", - @"Byers", - @"Kirkland", - @"Kidd", - @"Workman", - @"Carney", - @"Dale", - @"Mcleod", - @"Holcomb", - @"England", - @"Finch", - @"Head", - @"Burt", - @"Hendrix", - @"Sosa", - @"Haney", - @"Franks", - @"Sargent", - @"Nieves", - @"Downs", - @"Rasmussen", - @"Bird", - @"Hewitt", - @"Lindsay", - @"Le", - @"Foreman", - @"Valencia", - @"O'neil", - @"Delacruz", - @"Vinson", - @"Dejesus", - @"Hyde", - @"Forbes", - @"Gilliam", - @"Guthrie", - @"Wooten", - @"Huber", - @"Barlow", - @"Boyle", - @"Mcmahon", - @"Buckner", - @"Rocha", - @"Puckett", - @"Langley", - @"Knowles", - @"Cooke", - @"Velazquez", - @"Whitley", - @"Noel", - @"Vang", - ]; - - uint32_t index = arc4random_uniform((uint32_t)values.count); - return values[index]; -} - -+ (NSString *)randomPhoneNumber -{ - if (arc4random_uniform(2) == 0) { - // Generate a US phone number. - NSMutableString *result = [@"+1" mutableCopy]; - for (int i = 0; i < 10; i++) { - // Add digits. - [result appendString:[@(arc4random_uniform(10)) description]]; - } - return result; - } else { - // Generate a UK phone number. - NSMutableString *result = [@"+441" mutableCopy]; - for (int i = 0; i < 9; i++) { - // Add digits. - [result appendString:[@(arc4random_uniform(10)) description]]; - } - return result; - } -} - -+ (void)createRandomContacts:(NSUInteger)count -{ - [self createRandomContacts:count contactHandler:nil]; -} - -+ (void)createRandomContacts:(NSUInteger)count - contactHandler: - (nullable void (^)(CNContact *_Nonnull contact, NSUInteger idx, BOOL *_Nonnull stop))contactHandler -{ - OWSAssertDebug(count > 0); - - NSUInteger remainder = count; - const NSUInteger kMaxBatchSize = 20; - NSUInteger batch = MIN(kMaxBatchSize, remainder); - remainder -= batch; - [self createRandomContactsBatch:batch - contactHandler:contactHandler - batchCompletionHandler:^{ - if (remainder > 0) { - dispatch_async(dispatch_get_main_queue(), ^{ - [self createRandomContacts:remainder contactHandler:contactHandler]; - }); - } - }]; -} - -+ (void)createRandomContactsBatch:(NSUInteger)count - contactHandler:(nullable void (^)( - CNContact *_Nonnull contact, NSUInteger idx, BOOL *_Nonnull stop))contactHandler - batchCompletionHandler:(nullable void (^)(void))batchCompletionHandler -{ - OWSAssertDebug(count > 0); - OWSAssertDebug(batchCompletionHandler); - - OWSLogDebug(@"createRandomContactsBatch: %zu", count); - - CNAuthorizationStatus status = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts]; - if (status == CNAuthorizationStatusDenied || status == CNAuthorizationStatusRestricted) { - [OWSAlerts showAlertWithTitle:@"Error" message:@"No contacts access."]; - return; - } - - NSMutableArray *contacts = [NSMutableArray new]; - CNContactStore *store = [[CNContactStore alloc] init]; - [store requestAccessForEntityType:CNEntityTypeContacts - completionHandler:^(BOOL granted, NSError *_Nullable error) { - if (!granted || error) { - dispatch_async(dispatch_get_main_queue(), ^{ - [OWSAlerts showAlertWithTitle:@"Error" message:@"No contacts access."]; - }); - return; - } - - CNSaveRequest *request = [[CNSaveRequest alloc] init]; - for (NSUInteger i = 0; i < count; i++) { - @autoreleasepool { - CNMutableContact *contact = [[CNMutableContact alloc] init]; - contact.familyName = [@"Rando-" stringByAppendingString:[self randomLastName]]; - contact.givenName = [self randomFirstName]; - - NSString *phoneString = [self randomPhoneNumber]; - CNLabeledValue *homePhone = [CNLabeledValue - labeledValueWithLabel:CNLabelHome - value:[CNPhoneNumber phoneNumberWithStringValue:phoneString]]; - contact.phoneNumbers = @[ homePhone ]; - - // 50% chance of fake contact having an avatar - const NSUInteger kPercentWithAvatar = 50; - const NSUInteger kMinimumAvatarDiameter = 200; - const NSUInteger kMaximumAvatarDiameter = 800; - OWSAssertDebug(kMaximumAvatarDiameter >= kMinimumAvatarDiameter); - if (arc4random_uniform(100) < kPercentWithAvatar) { - NSUInteger avatarDiameter - = arc4random_uniform(kMaximumAvatarDiameter - kMinimumAvatarDiameter) - + kMinimumAvatarDiameter; - // Note this doesn't work on iOS9, since iOS9 doesn't generate the - // imageThumbnailData from programmatically assigned imageData. We could make our - // own thumbnail in Contact.m, but it's not worth it for the sake of debug UI. - contact.imageData = UIImageJPEGRepresentation( - [OWSAvatarBuilder buildRandomAvatarWithDiameter:avatarDiameter], (CGFloat)0.9); - OWSLogDebug(@"avatar size: %lu bytes", (unsigned long)contact.imageData.length); - } - - [contacts addObject:contact]; - [request addContact:contact toContainerWithIdentifier:nil]; - } - } - - OWSLogError(@"Saving fake contacts: %zu", contacts.count); - - NSError *saveError = nil; - if (![store executeSaveRequest:request error:&saveError]) { - OWSLogError(@"Error saving fake contacts: %@", saveError); - [OWSAlerts showAlertWithTitle:@"Error" message:saveError.localizedDescription]; - } else { - if (contactHandler) { - [contacts enumerateObjectsUsingBlock:contactHandler]; - } - } - if (batchCompletionHandler) { - batchCompletionHandler(); - } - }]; -} - -+ (void)deleteContactsWithFilter:(BOOL (^_Nonnull)(CNContact *contact))filterBlock -{ - OWSAssertDebug(filterBlock); - - CNAuthorizationStatus status = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts]; - if (status == CNAuthorizationStatusDenied || status == CNAuthorizationStatusRestricted) { - [OWSAlerts showAlertWithTitle:@"Error" message:@"No contacts access."]; - return; - } - - CNContactStore *store = [[CNContactStore alloc] init]; - [store requestAccessForEntityType:CNEntityTypeContacts - completionHandler:^(BOOL granted, NSError *_Nullable error) { - if (!granted || error) { - dispatch_async(dispatch_get_main_queue(), ^{ - [OWSAlerts showAlertWithTitle:@"Error" message:@"No contacts access."]; - }); - return; - } - - CNContactFetchRequest *fetchRequest = [[CNContactFetchRequest alloc] initWithKeysToFetch:@[ - CNContactIdentifierKey, - CNContactGivenNameKey, - CNContactFamilyNameKey, - [CNContactFormatter descriptorForRequiredKeysForStyle:CNContactFormatterStyleFullName], - ]]; - CNSaveRequest *request = [[CNSaveRequest alloc] init]; - NSError *fetchError = nil; - BOOL result = - [store enumerateContactsWithFetchRequest:fetchRequest - error:&fetchError - usingBlock:^(CNContact *contact, BOOL *stop) { - if (filterBlock(contact)) { - [request deleteContact:[contact mutableCopy]]; - } - }]; - - NSError *saveError = nil; - if (!result || fetchError) { - OWSLogError(@"error = %@", fetchError); - [OWSAlerts showAlertWithTitle:@"Error" message:fetchError.localizedDescription]; - } else if (![store executeSaveRequest:request error:&saveError]) { - OWSLogError(@"error = %@", saveError); - [OWSAlerts showAlertWithTitle:@"Error" message:saveError.localizedDescription]; - } - }]; -} - -+ (void)deleteAllContacts -{ - [self deleteContactsWithFilter:^(CNContact *contact) { - return YES; - }]; -} - -+ (void)deleteAllRandomContacts -{ - [self deleteContactsWithFilter:^(CNContact *contact) { - return [contact.familyName hasPrefix:@"Rando-"]; - }]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/src/ViewControllers/DebugUI/DebugUIBackup.h b/Session/src/ViewControllers/DebugUI/DebugUIBackup.h deleted file mode 100644 index 8f437ef41..000000000 --- a/Session/src/ViewControllers/DebugUI/DebugUIBackup.h +++ /dev/null @@ -1,13 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "DebugUIPage.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface DebugUIBackup : DebugUIPage - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/src/ViewControllers/DebugUI/DebugUIBackup.m b/Session/src/ViewControllers/DebugUI/DebugUIBackup.m deleted file mode 100644 index a4c5fd04c..000000000 --- a/Session/src/ViewControllers/DebugUI/DebugUIBackup.m +++ /dev/null @@ -1,258 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "DebugUIBackup.h" -#import "OWSBackup.h" -#import "OWSTableViewController.h" -#import "Session-Swift.h" -#import -#import - -@import CloudKit; - -NS_ASSUME_NONNULL_BEGIN - -@implementation DebugUIBackup - -#pragma mark - Dependencies - -+ (TSAccountManager *)tsAccountManager -{ - OWSAssertDebug(SSKEnvironment.shared.tsAccountManager); - - return SSKEnvironment.shared.tsAccountManager; -} - -+ (OWSBackup *)backup -{ - OWSAssertDebug(AppEnvironment.shared.backup); - - return AppEnvironment.shared.backup; -} - -#pragma mark - Factory Methods - -- (NSString *)name -{ - return @"Backup"; -} - -- (nullable OWSTableSection *)sectionForThread:(nullable TSThread *)thread -{ - NSMutableArray *items = [NSMutableArray new]; - [items addObject:[OWSTableItem itemWithTitle:@"Backup test file to CloudKit" - actionBlock:^{ - [DebugUIBackup backupTestFile]; - }]]; - [items addObject:[OWSTableItem itemWithTitle:@"Check for CloudKit backup" - actionBlock:^{ - [DebugUIBackup checkForBackup]; - }]]; - [items addObject:[OWSTableItem itemWithTitle:@"Log CloudKit backup records" - actionBlock:^{ - [DebugUIBackup logBackupRecords]; - }]]; - [items addObject:[OWSTableItem itemWithTitle:@"Log CloudKit backup manifests" - actionBlock:^{ - [DebugUIBackup logBackupManifests]; - }]]; - [items addObject:[OWSTableItem itemWithTitle:@"Restore CloudKit backup" - actionBlock:^{ - [DebugUIBackup tryToImportBackup]; - }]]; - [items addObject:[OWSTableItem itemWithTitle:@"Log Database Size Stats" - actionBlock:^{ - [DebugUIBackup logDatabaseSizeStats]; - }]]; - [items addObject:[OWSTableItem itemWithTitle:@"Clear All CloudKit Records" - actionBlock:^{ - [DebugUIBackup clearAllCloudKitRecords]; - }]]; - [items addObject:[OWSTableItem itemWithTitle:@"Clear Backup Metadata Cache" - actionBlock:^{ - [DebugUIBackup clearBackupMetadataCache]; - }]]; - [items addObject:[OWSTableItem itemWithTitle:@"Log Backup Metadata Cache" - actionBlock:^{ - [DebugUIBackup logBackupMetadataCache]; - }]]; - [items addObject:[OWSTableItem itemWithTitle:@"Lazy Restore Attachments" - actionBlock:^{ - [AppEnvironment.shared.backupLazyRestore runIfNecessary]; - }]]; - [items addObject:[OWSTableItem itemWithTitle:@"Upload 100 CK records" - actionBlock:^{ - [DebugUIBackup uploadCKBatch:100]; - }]]; - [items addObject:[OWSTableItem itemWithTitle:@"Upload 1,000 CK records" - actionBlock:^{ - [DebugUIBackup uploadCKBatch:1000]; - }]]; - [items addObject:[OWSTableItem itemWithTitle:@"Upload 10,000 CK records" - actionBlock:^{ - [DebugUIBackup uploadCKBatch:10000]; - }]]; - - return [OWSTableSection sectionWithTitle:self.name items:items]; -} - -+ (void)backupTestFile -{ - OWSLogInfo(@"backupTestFile."); - - NSData *_Nullable data = [Randomness generateRandomBytes:32]; - OWSAssertDebug(data); - NSString *filePath = [OWSFileSystem temporaryFilePathWithFileExtension:@"pdf"]; - BOOL success = [data writeToFile:filePath atomically:YES]; - OWSAssertDebug(success); - - NSString *recipientId = self.tsAccountManager.localNumber; - NSString *recordName = [OWSBackupAPI recordNameForTestFileWithRecipientId:recipientId]; - CKRecord *record = [OWSBackupAPI recordForFileUrl:[NSURL fileURLWithPath:filePath] recordName:recordName]; - - [[self.backup ensureCloudKitAccess].thenInBackground(^{ - return [OWSBackupAPI saveRecordsToCloudObjcWithRecords:@[ record ]]; - }) retainUntilComplete]; -} - -+ (void)checkForBackup -{ - OWSLogInfo(@"checkForBackup."); - - [OWSBackup.sharedManager - checkCanImportBackup:^(BOOL value) { - OWSLogInfo(@"has backup available for import? %d", value); - } - failure:^(NSError *error){ - // Do nothing. - }]; -} - -+ (void)logBackupRecords -{ - OWSLogInfo(@"logBackupRecords."); - - [OWSBackup.sharedManager logBackupRecords]; -} - -+ (void)logBackupManifests -{ - OWSLogInfo(@"logBackupManifests."); - - [OWSBackup.sharedManager - allRecipientIdsWithManifestsInCloud:^(NSArray *recipientIds) { - OWSLogInfo(@"recipientIds: %@", recipientIds); - } - failure:^(NSError *error) { - OWSLogError(@"error: %@", error); - }]; -} - -+ (void)tryToImportBackup -{ - OWSLogInfo(@"tryToImportBackup."); - - UIAlertController *alert = - [UIAlertController alertControllerWithTitle:@"Restore CloudKit Backup" - message:@"This will delete all of your database contents." - preferredStyle:UIAlertControllerStyleAlert]; - - [alert addAction:[UIAlertAction actionWithTitle:@"Restore" - style:UIAlertActionStyleDefault - handler:^(UIAlertAction *_Nonnull action) { - [OWSBackup.sharedManager tryToImportBackup]; - }]]; - [alert addAction:[OWSAlerts cancelAction]]; - UIViewController *fromViewController = [[UIApplication sharedApplication] frontmostViewController]; - [fromViewController presentAlert:alert]; -} - -+ (void)logDatabaseSizeStats -{ - OWSLogInfo(@"logDatabaseSizeStats."); - - __block unsigned long long interactionCount = 0; - __block unsigned long long interactionSizeTotal = 0; - __block unsigned long long attachmentCount = 0; - __block unsigned long long attachmentSizeTotal = 0; - [[OWSPrimaryStorage.sharedManager newDatabaseConnection] readWithBlock:^(YapDatabaseReadTransaction *transaction) { - [transaction enumerateKeysAndObjectsInCollection:[TSInteraction collection] - usingBlock:^(NSString *key, id object, BOOL *stop) { - TSInteraction *interaction = object; - interactionCount++; - NSData *_Nullable data = - [NSKeyedArchiver archivedDataWithRootObject:interaction]; - OWSAssertDebug(data); - ows_add_overflow( - interactionSizeTotal, data.length, &interactionSizeTotal); - }]; - [transaction enumerateKeysAndObjectsInCollection:[TSAttachment collection] - usingBlock:^(NSString *key, id object, BOOL *stop) { - TSAttachment *attachment = object; - attachmentCount++; - NSData *_Nullable data = - [NSKeyedArchiver archivedDataWithRootObject:attachment]; - OWSAssertDebug(data); - ows_add_overflow( - attachmentSizeTotal, data.length, &attachmentSizeTotal); - }]; - }]; - - OWSLogInfo(@"interactionCount: %llu", interactionCount); - OWSLogInfo(@"interactionSizeTotal: %llu", interactionSizeTotal); - if (interactionCount > 0) { - OWSLogInfo(@"interaction average size: %f", interactionSizeTotal / (double)interactionCount); - } - OWSLogInfo(@"attachmentCount: %llu", attachmentCount); - OWSLogInfo(@"attachmentSizeTotal: %llu", attachmentSizeTotal); - if (attachmentCount > 0) { - OWSLogInfo(@"attachment average size: %f", attachmentSizeTotal / (double)attachmentCount); - } -} - -+ (void)clearAllCloudKitRecords -{ - OWSLogInfo(@""); - - [OWSBackup.sharedManager clearAllCloudKitRecords]; -} - -+ (void)clearBackupMetadataCache -{ - OWSLogInfo(@""); - - [OWSPrimaryStorage.sharedManager.newDatabaseConnection - readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [transaction removeAllObjectsInCollection:[OWSBackupFragment collection]]; - }]; -} - -+ (void)logBackupMetadataCache -{ - [self.backup logBackupMetadataCache:OWSPrimaryStorage.sharedManager.newDatabaseConnection]; -} - -+ (void)uploadCKBatch:(NSUInteger)count -{ - NSMutableArray *records = [NSMutableArray new]; - for (NSUInteger i = 0; i < count; i++) { - NSData *_Nullable data = [Randomness generateRandomBytes:32]; - OWSAssertDebug(data); - NSString *filePath = [OWSFileSystem temporaryFilePathWithFileExtension:@"pdf"]; - BOOL success = [data writeToFile:filePath atomically:YES]; - OWSAssertDebug(success); - - NSString *recipientId = self.tsAccountManager.localNumber; - NSString *recordName = [OWSBackupAPI recordNameForTestFileWithRecipientId:recipientId]; - CKRecord *record = [OWSBackupAPI recordForFileUrl:[NSURL fileURLWithPath:filePath] recordName:recordName]; - [records addObject:record]; - } - [[OWSBackupAPI saveRecordsToCloudObjcWithRecords:records].thenInBackground(^{ - OWSLogVerbose(@"success."); - }) retainUntilComplete]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/src/ViewControllers/DebugUI/DebugUICalling.swift b/Session/src/ViewControllers/DebugUI/DebugUICalling.swift deleted file mode 100644 index 4ae460b87..000000000 --- a/Session/src/ViewControllers/DebugUI/DebugUICalling.swift +++ /dev/null @@ -1,75 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -import Foundation -import SignalUtilitiesKit -import SignalUtilitiesKit - -class DebugUICalling: DebugUIPage { - - // MARK: Dependencies - - var messageSender: MessageSender { - return SSKEnvironment.shared.messageSender - } - - // MARK: Overrides - - override func name() -> String { - return "Calling" - } - - override func section(thread aThread: TSThread?) -> OWSTableSection? { - guard let thread = aThread as? TSContactThread else { - owsFailDebug("Calling is only valid for contact thread, got thread: \(String(describing: aThread))") - return nil - } - - let sectionItems = [ - OWSTableItem(title: "Send 'hangup' for old call") { [weak self] in - guard let strongSelf = self else { return } - - let kFakeCallId = UInt64(12345) - var hangupMessage: SSKProtoCallMessageHangup - do { - let hangupBuilder = SSKProtoCallMessageHangup.builder(id: kFakeCallId) - hangupMessage = try hangupBuilder.build() - } catch { - owsFailDebug("could not build proto") - return - } - let callMessage = OWSOutgoingCallMessage(thread: thread, hangupMessage: hangupMessage) - - strongSelf.messageSender.sendPromise(message: callMessage).done { - Logger.debug("Successfully sent hangup call message to \(thread.contactIdentifier())") - }.catch { error in - Logger.error("failed to send hangup call message to \(thread.contactIdentifier()) with error: \(error)") - }.retainUntilComplete() - }, - OWSTableItem(title: "Send 'busy' for old call") { [weak self] in - guard let strongSelf = self else { return } - - let kFakeCallId = UInt64(12345) - var busyMessage: SSKProtoCallMessageBusy - do { - let busyBuilder = SSKProtoCallMessageBusy.builder(id: kFakeCallId) - busyMessage = try busyBuilder.build() - } catch { - owsFailDebug("Couldn't build proto") - return - } - - let callMessage = OWSOutgoingCallMessage(thread: thread, busyMessage: busyMessage) - - strongSelf.messageSender.sendPromise(message: callMessage).done { - Logger.debug("Successfully sent busy call message to \(thread.contactIdentifier())") - }.catch { error in - Logger.error("failed to send busy call message to \(thread.contactIdentifier()) with error: \(error)") - }.retainUntilComplete() - } - ] - - return OWSTableSection(title: "Call Debug", items: sectionItems) - } -} diff --git a/Session/src/ViewControllers/DebugUI/DebugUIContacts.h b/Session/src/ViewControllers/DebugUI/DebugUIContacts.h deleted file mode 100644 index 1a2866816..000000000 --- a/Session/src/ViewControllers/DebugUI/DebugUIContacts.h +++ /dev/null @@ -1,16 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "DebugUIPage.h" - -NS_ASSUME_NONNULL_BEGIN - -@class CNContact; -@class OWSTableSection; - -@interface DebugUIContacts : DebugUIPage - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/src/ViewControllers/DebugUI/DebugUIContacts.m b/Session/src/ViewControllers/DebugUI/DebugUIContacts.m deleted file mode 100644 index d4d14044d..000000000 --- a/Session/src/ViewControllers/DebugUI/DebugUIContacts.m +++ /dev/null @@ -1,120 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "DebugUIContacts.h" -#import "DebugContactsUtils.h" -#import "OWSTableViewController.h" -#import "Session-Swift.h" -#import "SignalApp.h" -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@implementation DebugUIContacts - -#pragma mark - Factory Methods - -- (NSString *)name -{ - return @"Contacts"; -} - -- (nullable OWSTableSection *)sectionForThread:(nullable TSThread *)thread -{ - return [OWSTableSection sectionWithTitle:self.name - items:@[ - [OWSTableItem itemWithTitle:@"Create 1 Random Contact" - actionBlock:^{ - [DebugContactsUtils createRandomContacts:1]; - }], - [OWSTableItem itemWithTitle:@"Create 100 Random Contacts" - actionBlock:^{ - [DebugContactsUtils createRandomContacts:100]; - }], - [OWSTableItem itemWithTitle:@"Create 1k Random Contacts" - actionBlock:^{ - [DebugContactsUtils createRandomContacts:1000]; - }], - [OWSTableItem itemWithTitle:@"Create 10k Random Contacts" - actionBlock:^{ - [DebugContactsUtils createRandomContacts:10 * 1000]; - }], - [OWSTableItem itemWithTitle:@"Delete Random Contacts" - actionBlock:^{ - [DebugContactsUtils deleteAllRandomContacts]; - }], - [OWSTableItem itemWithTitle:@"Delete All Contacts" - actionBlock:^{ - [DebugContactsUtils deleteAllContacts]; - }], - [OWSTableItem itemWithTitle:@"Clear SignalAccount Cache" - actionBlock:^{ - [DebugUIContacts clearSignalAccountCache]; - }], - [OWSTableItem itemWithTitle:@"Clear SignalRecipient Cache" - actionBlock:^{ - [DebugUIContacts clearSignalRecipientCache]; - }], - [OWSTableItem itemWithTitle:@"New Unregistered Contact Thread" - actionBlock:^{ - [DebugUIContacts createUnregisteredContactThread]; - }], - [OWSTableItem itemWithTitle:@"New Unregistered Group Thread" - actionBlock:^{ - [DebugUIContacts createUnregisteredGroupThread]; - }], - ]]; -} - -+ (void)clearSignalAccountCache -{ - OWSLogWarn(@"Deleting all signal accounts."); - [SignalAccount removeAllObjectsInCollection]; -} - -+ (void)clearSignalRecipientCache -{ - OWSLogWarn(@"Deleting all signal recipients."); - [SignalRecipient removeAllObjectsInCollection]; -} - -+ (NSString *)unregisteredRecipientId -{ - // We ensure that the phone number is invalid by appending too many digits. - NSMutableString *recipientId = [@"+1" mutableCopy]; - for (int i = 0; i < 11; i++) { - [recipientId appendFormat:@"%d", (int)(arc4random() % 10)]; - } - return [recipientId copy]; -} - -+ (void)createUnregisteredContactThread -{ - NSString *recipientId = [self unregisteredRecipientId]; - TSContactThread *thread = [TSContactThread getOrCreateThreadWithContactId:recipientId]; - [SignalApp.sharedApp presentConversationForThread:thread animated:YES]; -} - -+ (void)createUnregisteredGroupThread -{ - NSString *unregisteredRecipientId = [self unregisteredRecipientId]; - NSString *validRecipientId = @"+19174054216"; - - NSString *groupName = @"Partially invalid group"; - NSMutableArray *recipientIds = [@[ - unregisteredRecipientId, - validRecipientId, - TSAccountManager.localNumber, - ] mutableCopy]; - NSData *groupId = [Randomness generateRandomBytes:16]; - TSGroupModel *model = [[TSGroupModel alloc] initWithTitle:groupName memberIds:recipientIds image:nil groupId:groupId groupType:closedGroup adminIds:@[ TSAccountManager.localNumber ]]; - TSGroupThread *thread = [TSGroupThread getOrCreateThreadWithGroupModel:model]; - - [SignalApp.sharedApp presentConversationForThread:thread animated:YES]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/src/ViewControllers/DebugUI/DebugUIDiskUsage.h b/Session/src/ViewControllers/DebugUI/DebugUIDiskUsage.h deleted file mode 100644 index 5cb1c5ff3..000000000 --- a/Session/src/ViewControllers/DebugUI/DebugUIDiskUsage.h +++ /dev/null @@ -1,13 +0,0 @@ -// -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. -// - -#import "DebugUIPage.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface DebugUIDiskUsage : DebugUIPage - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/src/ViewControllers/DebugUI/DebugUIDiskUsage.m b/Session/src/ViewControllers/DebugUI/DebugUIDiskUsage.m deleted file mode 100644 index a6dd47c8d..000000000 --- a/Session/src/ViewControllers/DebugUI/DebugUIDiskUsage.m +++ /dev/null @@ -1,116 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "DebugUIDiskUsage.h" -#import "OWSOrphanDataCleaner.h" -#import "OWSTableViewController.h" -#import "Session-Swift.h" -#import -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@implementation DebugUIDiskUsage - -#pragma mark - Factory Methods - -- (NSString *)name -{ - return @"Orphans & Disk Usage"; -} - -- (nullable OWSTableSection *)sectionForThread:(nullable TSThread *)thread -{ - return [OWSTableSection sectionWithTitle:self.name - items:@[ - [OWSTableItem itemWithTitle:@"Audit & Log" - actionBlock:^{ - [OWSOrphanDataCleaner auditAndCleanup:NO]; - }], - [OWSTableItem itemWithTitle:@"Audit & Clean Up" - actionBlock:^{ - [OWSOrphanDataCleaner auditAndCleanup:YES]; - }], - [OWSTableItem itemWithTitle:@"Save All Attachments" - actionBlock:^{ - [DebugUIDiskUsage saveAllAttachments]; - }], - [OWSTableItem itemWithTitle:@"Delete Messages older than 3 Months" - actionBlock:^{ - [DebugUIDiskUsage deleteOldMessages_3Months]; - }], - ]]; -} - -+ (void)saveAllAttachments -{ - OWSPrimaryStorage *primaryStorage = [OWSPrimaryStorage sharedManager]; - [primaryStorage.newDatabaseConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { - NSMutableArray *attachmentStreams = [NSMutableArray new]; - [transaction enumerateKeysAndObjectsInCollection:TSAttachmentStream.collection - usingBlock:^(NSString *key, TSAttachment *attachment, BOOL *stop) { - if (![attachment isKindOfClass:[TSAttachmentStream class]]) { - return; - } - TSAttachmentStream *attachmentStream - = (TSAttachmentStream *)attachment; - [attachmentStreams addObject:attachmentStream]; - }]; - - OWSLogInfo(@"Saving %zd attachment streams.", attachmentStreams.count); - - // Persist the new localRelativeFilePath property of TSAttachmentStream. - // For performance, we want to upgrade all existing attachment streams in - // a single transaction. - for (TSAttachmentStream *attachmentStream in attachmentStreams) { - [attachmentStream saveWithTransaction:transaction]; - } - }]; -} - -+ (void)deleteOldMessages_3Months -{ - [self deleteOldMessages:kMonthInterval * 3]; -} - -+ (void)deleteOldMessages:(NSTimeInterval)maxAgeSeconds -{ - OWSPrimaryStorage *primaryStorage = [OWSPrimaryStorage sharedManager]; - [primaryStorage.newDatabaseConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { - NSMutableArray *threadIds = [NSMutableArray new]; - YapDatabaseViewTransaction *interactionsByThread = [transaction ext:TSMessageDatabaseViewExtensionName]; - [interactionsByThread enumerateGroupsUsingBlock:^(NSString *group, BOOL *stop) { - [threadIds addObject:group]; - }]; - NSMutableArray *interactionsToDelete = [NSMutableArray new]; - for (NSString *threadId in threadIds) { - [interactionsByThread enumerateKeysAndObjectsInGroup:threadId - usingBlock:^(NSString *collection, - NSString *key, - TSInteraction *interaction, - NSUInteger index, - BOOL *stop) { - NSTimeInterval ageSeconds - = fabs(interaction.receivedAtDate.timeIntervalSinceNow); - if (ageSeconds < maxAgeSeconds) { - *stop = YES; - return; - } - [interactionsToDelete addObject:interaction]; - }]; - } - - OWSLogInfo(@"Deleting %zd interactions.", interactionsToDelete.count); - - for (TSInteraction *interaction in interactionsToDelete) { - [interaction removeWithTransaction:transaction]; - } - }]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/src/ViewControllers/DebugUI/DebugUIFileBrowser.swift b/Session/src/ViewControllers/DebugUI/DebugUIFileBrowser.swift deleted file mode 100644 index 7a20e1065..000000000 --- a/Session/src/ViewControllers/DebugUI/DebugUIFileBrowser.swift +++ /dev/null @@ -1,378 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -@objc class DebugUIFileBrowser: OWSTableViewController { - - // MARK: Dependencies - var fileManager: FileManager { - return FileManager.default - } - - // MARK: Overrides - let fileURL: URL - - @objc init(fileURL: URL) { - self.fileURL = fileURL - - super.init() - - self.contents = buildContents() - } - - required init?(coder aDecoder: NSCoder) { - notImplemented() - } - - override func viewDidLoad() { - super.viewDidLoad() - let titleLabel = UILabel() - titleLabel.text = "\(fileURL)" - titleLabel.sizeToFit() - titleLabel.textColor = Theme.primaryColor - titleLabel.lineBreakMode = .byTruncatingHead - self.navigationItem.titleView = titleLabel - } - - fileprivate func updateContents() { - self.contents = buildContents() - self.tableView.reloadData() - } - - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - // In case files were added / removed in child view controller - updateContents() - } - - func buildContents() -> OWSTableContents { - let contents = OWSTableContents() - - let isDirectoryPtr: UnsafeMutablePointer = UnsafeMutablePointer.allocate(capacity: 1) - guard fileManager.fileExists(atPath: fileURL.path, isDirectory: isDirectoryPtr) else { - contents.title = "File not found: \(fileURL)" - return contents - } - - let isDirectory: Bool = isDirectoryPtr.pointee.boolValue - - if isDirectory { - var fileItems: [OWSTableItem] = [] - let resourceKeys: [URLResourceKey] = [.isDirectoryKey] - - let directoryContents: [URL] = { - do { - return try fileManager.contentsOfDirectory(at: fileURL, - includingPropertiesForKeys: resourceKeys) - } catch { - owsFailDebug("contentsOfDirectory(\(fileURL) failed with error: \(error)") - return [] - } - }() - - fileItems = directoryContents.map { fileInDirectory in - let fileIcon: String = { - do { - guard let isDirectory = try fileInDirectory.resourceValues(forKeys: Set(resourceKeys)).isDirectory else { - owsFailDebug("unable to check isDirectory for file: \(fileInDirectory)") - return "" - } - - return isDirectory ? "📁 " : "" - } catch { - owsFailDebug("failed to check isDirectory for file: \(fileInDirectory) with error: \(error)") - return "" - } - }() - - let labelText = "\(fileIcon)\(fileInDirectory.lastPathComponent)" - - return OWSTableItem.disclosureItem(withText: labelText) { [weak self] in - let subBrowser = DebugUIFileBrowser(fileURL: fileInDirectory) - self?.navigationController?.pushViewController(subBrowser, animated: true) - } - } - - let filesSection = OWSTableSection(title: "Dir with \(fileItems.count) files", items: fileItems) - contents.addSection(filesSection) - } // end `if isDirectory` - - let attributeItems: [OWSTableItem] = { - do { - let attributes: [FileAttributeKey: Any] = try fileManager.attributesOfItem(atPath: fileURL.path) - return attributes.map { (fileAttribute: FileAttributeKey, value: Any) in - let title = fileAttribute.rawValue.replacingOccurrences(of: "NSFile", with: "") - return OWSTableItem(title: "\(title): \(value)") { - OWSAlerts.showAlert(title: title, message: "\(value)") - } - } - } catch { - owsFailDebug("failed getting attributes for file at path: \(fileURL)") - return [] - } - }() - let attributesSection = OWSTableSection(title: "Attributes", items: attributeItems) - contents.addSection(attributesSection) - - var managementItems = [ - OWSTableItem.disclosureItem(withText: "✎ Rename") { [weak self] in - guard let strongSelf = self else { - return - } - - let alert = UIAlertController(title: "Rename File", - message: "Will be created in \(strongSelf.fileURL.lastPathComponent)", - preferredStyle: .alert) - - alert.addAction(OWSAlerts.cancelAction) - alert.addAction(UIAlertAction(title: "Rename \(strongSelf.fileURL.lastPathComponent)", style: .default) { _ in - guard let textField = alert.textFields?.first else { - owsFailDebug("missing text field") - return - } - - guard let inputString = textField.text, inputString.count >= 4 else { - OWSAlerts.showAlert(title: "new file name missing or less than 4 chars") - return - } - - let newURL = strongSelf.fileURL.deletingLastPathComponent().appendingPathComponent(inputString) - - do { - try strongSelf.fileManager.moveItem(at: strongSelf.fileURL, to: newURL) - - Logger.debug("\(strongSelf) moved \(strongSelf.fileURL) -> \(newURL)") - strongSelf.navigationController?.popViewController(animated: true) - } catch { - owsFailDebug("\(strongSelf) failed to move \(strongSelf.fileURL) -> \(newURL) with error: \(error)") - } - }) - - alert.addTextField { textField in - textField.placeholder = "New Name" - textField.text = strongSelf.fileURL.lastPathComponent - } - - strongSelf.presentAlert(alert) - }, - - OWSTableItem.disclosureItem(withText: "➡ Move") { [weak self] in - guard let strongSelf = self else { - return - } - - let fileURL: URL = strongSelf.fileURL - let filename: String = fileURL.lastPathComponent - let oldDirectory: URL = fileURL.deletingLastPathComponent() - - let alert = UIAlertController(title: "Moving File: \(filename)", - message: "Currently in: \(oldDirectory)", - preferredStyle: .alert) - - alert.addAction(OWSAlerts.cancelAction) - alert.addAction(UIAlertAction(title: "Moving \(filename)", style: .default) { _ in - guard let textField = alert.textFields?.first else { - owsFailDebug("missing text field") - return - } - - guard let inputString = textField.text, inputString.count >= 4 else { - OWSAlerts.showAlert(title: "new file dir missing or less than 4 chars") - return - } - - let newURL = URL(fileURLWithPath: inputString).appendingPathComponent(filename) - - do { - try strongSelf.fileManager.moveItem(at: fileURL, to: newURL) - - Logger.debug("\(strongSelf) moved \(fileURL) -> \(newURL)") - strongSelf.navigationController?.popViewController(animated: true) - } catch { - owsFailDebug("\(strongSelf) failed to move \(fileURL) -> \(newURL) with error: \(error)") - } - }) - - alert.addTextField { textField in - textField.placeholder = "New Directory" - textField.text = oldDirectory.path - } - - strongSelf.presentAlert(alert) - }, - - OWSTableItem.disclosureItem(withText: "❌ Delete") { [weak self] in - guard let strongSelf = self else { - return - } - - OWSAlerts.showConfirmationAlert(title: "Delete \(strongSelf.fileURL.path)?") { _ in - Logger.debug("deleting file at \(strongSelf.fileURL.path)") - do { - try strongSelf.fileManager.removeItem(atPath: strongSelf.fileURL.path) - strongSelf.navigationController?.popViewController(animated: true) - } catch { - owsFailDebug("failed to remove item: \(strongSelf.fileURL) with error: \(error)") - } - } - }, - - OWSTableItem.disclosureItem(withText: "📋 Copy Path to Clipboard") { [weak self] in - guard let strongSelf = self else { - return - } - - UIPasteboard.general.string = strongSelf.fileURL.path - - let alert = UIAlertController(title: "Path Copied to Clipboard!", - message: "\(strongSelf.fileURL.path)", - preferredStyle: .alert) - alert.addAction(UIAlertAction(title: "Copy Filename Instead", style: .default) { _ in - UIPasteboard.general.string = strongSelf.fileURL.lastPathComponent - }) - - alert.addAction(UIAlertAction(title: "Dismiss", style: .default)) - - strongSelf.presentAlert(alert) - }, - - OWSTableItem.disclosureItem(withText: "🔒 Set File Protection") { [weak self] in - guard let strongSelf = self else { - return - } - - let fileURL = strongSelf.fileURL - - let currentFileProtection: FileProtectionType? = { - do { - let attributes = try strongSelf.fileManager.attributesOfItem(atPath: fileURL.path) - return attributes[FileAttributeKey.protectionKey] as? FileProtectionType - } catch { - owsFailDebug("failed to get current file protection for file: \(fileURL)") - return nil - } - }() - - let actionSheet = UIAlertController(title: "Set file protection level", - message: "Currently: \(currentFileProtection?.rawValue ?? "Unknown")", - preferredStyle: .actionSheet) - - let protections: [FileProtectionType] = [.none, .complete, .completeUnlessOpen, .completeUntilFirstUserAuthentication] - protections.forEach { (protection: FileProtectionType) in - actionSheet.addAction(UIAlertAction(title: "\(protection.rawValue.replacingOccurrences(of: "NSFile", with: ""))", style: .default) { (_: UIAlertAction) in - Logger.debug("chose protection: \(protection) for file: \(fileURL)") - let fileAttributes: [FileAttributeKey: Any] = [.protectionKey: protection] - do { - try strongSelf.fileManager.setAttributes(fileAttributes, ofItemAtPath: strongSelf.fileURL.path) - Logger.debug("updated file protection at path:\(fileURL.path) to: \(protection.rawValue)") - strongSelf.updateContents() - } catch { - owsFailDebug("failed to update file protection at path:\(fileURL.path) with error: \(error)") - } - }) - } - actionSheet.addAction(OWSAlerts.cancelAction) - - strongSelf.presentAlert(actionSheet) - } - ] - - if isDirectory { - let createFileItem = OWSTableItem.disclosureItem(withText: "📝 Create File in this Dir") { [weak self] in - guard let strongSelf = self else { - return - } - - let alert = UIAlertController(title: "Name of file", - message: "Will be created in \(strongSelf.fileURL.lastPathComponent)", - preferredStyle: .alert) - - alert.addAction(OWSAlerts.cancelAction) - alert.addAction(UIAlertAction(title: "Create", style: .default) { _ in - guard let textField = alert.textFields?.first else { - owsFailDebug("missing text field") - return - } - - guard let inputString = textField.text, inputString.count >= 4 else { - OWSAlerts.showAlert(title: "file name missing or less than 4 chars") - return - } - - let newPath = strongSelf.fileURL.appendingPathComponent(inputString).path - - Logger.debug("creating file at \(newPath)") - strongSelf.fileManager.createFile(atPath: newPath, contents: nil) - - strongSelf.updateContents() - }) - - alert.addTextField { textField in - textField.placeholder = "File Name" - } - - strongSelf.presentAlert(alert) - } - - managementItems.append(createFileItem) - - let createDirItem = OWSTableItem.disclosureItem(withText: "📁 Create Dir in this Dir") { [weak self] in - guard let strongSelf = self else { - return - } - - let alert = UIAlertController(title: "Name of Dir", - message: "Will be created in \(strongSelf.fileURL.lastPathComponent)", - preferredStyle: .alert) - - alert.addAction(OWSAlerts.cancelAction) - alert.addAction(UIAlertAction(title: "Create", style: .default) { _ in - guard let textField = alert.textFields?.first else { - owsFailDebug("missing text field") - return - } - - guard let inputString = textField.text, inputString.count >= 4 else { - OWSAlerts.showAlert(title: "dir name missing or less than 4 chars") - return - } - - let newPath = strongSelf.fileURL.appendingPathComponent(inputString).path - - Logger.debug("creating dir at \(newPath)") - do { - try strongSelf.fileManager.createDirectory(atPath: newPath, withIntermediateDirectories: false) - strongSelf.updateContents() - } catch { - owsFailDebug("Failed to create dir: \(newPath) with error: \(error)") - } - }) - - alert.addTextField { textField in - textField.placeholder = "Dir Name" - } - - strongSelf.presentAlert(alert) - } - managementItems.append(createDirItem) - - } else { // if not directory - - let shareItem = OWSTableItem.disclosureItem(withText: "📩 Share") { [weak self] in - guard let strongSelf = self else { - return - } - - AttachmentSharing.showShareUI(for: strongSelf.fileURL) - } - managementItems.append(shareItem) - } - - let fileType = isDirectory ? "Dir" : "File" - let filesSection = OWSTableSection(title: "\(fileType): \(fileURL.lastPathComponent)", items: managementItems) - contents.addSection(filesSection) - - contents.title = "\(fileType): \(fileURL)" - return contents - } -} diff --git a/Session/src/ViewControllers/DebugUI/DebugUIMessages.h b/Session/src/ViewControllers/DebugUI/DebugUIMessages.h deleted file mode 100644 index 4ff187f13..000000000 --- a/Session/src/ViewControllers/DebugUI/DebugUIMessages.h +++ /dev/null @@ -1,13 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "DebugUIPage.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface DebugUIMessages : DebugUIPage - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/src/ViewControllers/DebugUI/DebugUIMessages.m b/Session/src/ViewControllers/DebugUI/DebugUIMessages.m deleted file mode 100644 index aec519062..000000000 --- a/Session/src/ViewControllers/DebugUI/DebugUIMessages.m +++ /dev/null @@ -1,4863 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "DebugUIMessages.h" -#import "DebugContactsUtils.h" -#import "DebugUIContacts.h" -#import "DebugUIMessagesAction.h" -#import "DebugUIMessagesAssetLoader.h" -#import "OWSTableViewController.h" -#import "Session-Swift.h" -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface TSIncomingMessage (DebugUI) - -@property (nonatomic, getter=wasRead) BOOL read; - -@end - -#pragma mark - - -@interface TSOutgoingMessage (PostDatingDebug) - -- (void)setReceivedAtTimestamp:(uint64_t)value; - -@end - -#pragma mark - - -@implementation DebugUIMessages - -#pragma mark - Factory Methods - -- (NSString *)name -{ - return @"Messages"; -} - -#ifdef DEBUG - -- (NSArray *)itemsForActions:(NSArray *)actions -{ - NSMutableArray *items = [NSMutableArray new]; - - for (DebugUIMessagesAction *action in actions) { - [items addObject:[OWSTableItem itemWithTitle:action.label - actionBlock:^{ - // For "all in group" actions, do each subaction in the group - // exactly once, in a predictable order. - if ([action isKindOfClass:[DebugUIMessagesGroupAction class]]) { - DebugUIMessagesGroupAction *groupAction - = (DebugUIMessagesGroupAction *)action; - if (groupAction.subactionMode == SubactionMode_Ordered) { - [action prepareAndPerformNTimes:groupAction.subactions.count]; - return; - } - } - [DebugUIMessages performActionNTimes:action]; - }]]; - } - - return items; -} - -#endif - -- (nullable OWSTableSection *)sectionForThread:(nullable TSThread *)thread -{ - OWSAssertDebug(thread); - - NSMutableArray *items = [NSMutableArray new]; - -#ifdef DEBUG - - [items addObject:[OWSTableItem itemWithTitle:@"Delete all messages in thread" - actionBlock:^{ - [DebugUIMessages deleteAllMessagesInThread:thread]; - }]]; - [items addObject:[OWSTableItem itemWithTitle:@"👷 Thrash insert/deletes" - actionBlock:^{ - [DebugUIMessages thrashInsertAndDeleteForThread:(TSThread *)thread - counter:300]; - }]]; - - [items addObjectsFromArray:[self itemsForActions:@[ - [DebugUIMessages fakeAllContactShareAction:thread], - [DebugUIMessages sendMessageVariationsAction:thread], - // Send Media - [DebugUIMessages sendAllMediaAction:thread], - [DebugUIMessages sendRandomMediaAction:thread], - // Fake Media - [DebugUIMessages fakeAllMediaAction:thread], - [DebugUIMessages fakeRandomMediaAction:thread], - // Fake Text - [DebugUIMessages fakeAllTextAction:thread], - [DebugUIMessages fakeRandomTextAction:thread], - // Sequences - [DebugUIMessages allFakeSequencesAction:thread], - // Quoted Replies - [DebugUIMessages allQuotedReplyAction:thread], - // Exemplary - [DebugUIMessages allFakeAction:thread], - [DebugUIMessages allFakeBackDatedAction:thread], - ]]]; - - [items addObjectsFromArray:@[ - -#pragma mark - Actions - - [OWSTableItem itemWithTitle:@"Send N text messages (1/sec.)" - actionBlock:^{ - [DebugUIMessages sendNTextMessagesInThread:thread]; - }], - [OWSTableItem itemWithTitle:@"Send Media Gallery" - actionBlock:^{ - [DebugUIMessages sendMediaAlbumInThread:thread]; - }], - [OWSTableItem itemWithTitle:@"Send Exemplary Media Galleries" - actionBlock:^{ - [DebugUIMessages sendExemplaryMediaGalleriesInThread:thread]; - }], - [OWSTableItem itemWithTitle:@"Select Fake" - actionBlock:^{ - [DebugUIMessages selectFakeAction:thread]; - }], - [OWSTableItem itemWithTitle:@"Select Send Media" - actionBlock:^{ - [DebugUIMessages selectSendMediaAction:thread]; - }], - [OWSTableItem itemWithTitle:@"Send All Contact Shares" - actionBlock:^{ - [DebugUIMessages sendAllContacts:thread]; - }], - [OWSTableItem itemWithTitle:@"Select Quoted Reply" - actionBlock:^{ - [DebugUIMessages selectQuotedReplyAction:thread]; - }], - [OWSTableItem itemWithTitle:@"Select Back-Dated" - actionBlock:^{ - [DebugUIMessages selectBackDatedAction:thread]; - }], - - -#pragma mark - Misc. - - [OWSTableItem itemWithTitle:@"Perform 100 random actions" - actionBlock:^{ - [DebugUIMessages performRandomActions:100 thread:thread]; - }], - [OWSTableItem itemWithTitle:@"Perform 1,000 random actions" - actionBlock:^{ - [DebugUIMessages performRandomActions:1000 thread:thread]; - }], - [OWSTableItem itemWithTitle:@"Create 10 fake messages" - actionBlock:^{ - [DebugUIMessages sendFakeMessages:10 thread:thread]; - }], - [OWSTableItem itemWithTitle:@"Create 1 fake thread with 1 message" - actionBlock:^{ - [DebugUIMessages createFakeThreads:1 withFakeMessages:1]; - }], - [OWSTableItem itemWithTitle:@"Create 100 fake threads with 10 messages" - actionBlock:^{ - [DebugUIMessages createFakeThreads:100 withFakeMessages:10]; - }], - [OWSTableItem itemWithTitle:@"Create 10 fake threads with 100 messages" - actionBlock:^{ - [DebugUIMessages createFakeThreads:10 withFakeMessages:100]; - }], - [OWSTableItem itemWithTitle:@"Create 10 fake threads with 10 messages" - actionBlock:^{ - [DebugUIMessages createFakeThreads:10 withFakeMessages:10]; - }], - [OWSTableItem itemWithTitle:@"Create 100 fake threads with 100 messages" - actionBlock:^{ - [DebugUIMessages createFakeThreads:100 withFakeMessages:100]; - }], - [OWSTableItem itemWithTitle:@"Create 1k fake threads with 1 message" - actionBlock:^{ - [DebugUIMessages createFakeThreads:1000 withFakeMessages:1]; - }], - [OWSTableItem itemWithTitle:@"Create 1k fake messages" - actionBlock:^{ - [DebugUIMessages sendFakeMessages:1000 thread:thread]; - }], - [OWSTableItem itemWithTitle:@"Create 10k fake messages" - actionBlock:^{ - [DebugUIMessages sendFakeMessages:10 * 1000 thread:thread]; - }], - [OWSTableItem itemWithTitle:@"Create 10k fake text messages" - actionBlock:^{ - [DebugUIMessages sendFakeMessages:10 * 1000 thread:thread isTextOnly:YES]; - }], - [OWSTableItem itemWithTitle:@"Create 100k fake messages" - actionBlock:^{ - [DebugUIMessages sendFakeMessages:100 * 1000 thread:thread]; - }], - [OWSTableItem itemWithTitle:@"Create 100k fake text messages" - actionBlock:^{ - [DebugUIMessages sendFakeMessages:100 * 1000 thread:thread isTextOnly:YES]; - }], - [OWSTableItem itemWithTitle:@"Send text/x-signal-plain" - actionBlock:^{ - [DebugUIMessages sendOversizeTextMessage:thread]; - }], - [OWSTableItem itemWithTitle:@"Send unknown mimetype" - actionBlock:^{ - [DebugUIMessages sendRandomAttachment:thread uti:kUnknownTestAttachmentUTI]; - }], - [OWSTableItem itemWithTitle:@"Send pdf" - actionBlock:^{ - [DebugUIMessages sendRandomAttachment:thread uti:(NSString *)kUTTypePDF]; - }], - [OWSTableItem itemWithTitle:@"Create all system messages" - actionBlock:^{ - [DebugUIMessages createSystemMessagesInThread:thread]; - }], - [OWSTableItem itemWithTitle:@"Create messages with variety of timestamps" - actionBlock:^{ - [DebugUIMessages createTimestampMessagesInThread:thread]; - }], - - [OWSTableItem itemWithTitle:@"Send 10 text and system messages" - actionBlock:^{ - [DebugUIMessages sendTextAndSystemMessages:10 thread:thread]; - }], - [OWSTableItem itemWithTitle:@"Send 100 text and system messages" - actionBlock:^{ - [DebugUIMessages sendTextAndSystemMessages:100 thread:thread]; - }], - [OWSTableItem itemWithTitle:@"Send 1,000 text and system messages" - actionBlock:^{ - [DebugUIMessages sendTextAndSystemMessages:1000 thread:thread]; - }], - [OWSTableItem - itemWithTitle:@"Request Bogus group info" - actionBlock:^{ - OWSLogInfo(@"Requesting bogus group info for thread: %@", thread); - OWSSyncGroupsRequestMessage *syncGroupsRequestMessage = [[OWSSyncGroupsRequestMessage alloc] - initWithThread:thread - groupId:[Randomness generateRandomBytes:kGroupIdLength]]; - [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { - [self.messageSenderJobQueue addMessage:syncGroupsRequestMessage transaction:transaction]; - }]; - }], - [OWSTableItem itemWithTitle:@"Message with stalled timer" - actionBlock:^{ - [DebugUIMessages createDisappearingMessagesWhichFailedToStartInThread:thread]; - }], - [OWSTableItem itemWithTitle:@"Inject 10 fake incoming messages" - actionBlock:^{ - [DebugUIMessages injectFakeIncomingMessages:10 thread:thread]; - }], - [OWSTableItem itemWithTitle:@"Inject 100 fake incoming messages" - actionBlock:^{ - [DebugUIMessages injectFakeIncomingMessages:100 thread:thread]; - }], - [OWSTableItem itemWithTitle:@"Inject 1,000 fake incoming messages" - actionBlock:^{ - [DebugUIMessages injectFakeIncomingMessages:1000 thread:thread]; - }], - [OWSTableItem itemWithTitle:@"Test Indic Scripts" - actionBlock:^{ - [DebugUIMessages testIndicScriptsInThread:thread]; - }], - [OWSTableItem itemWithTitle:@"Test Zalgo" - actionBlock:^{ - [DebugUIMessages testZalgoTextInThread:thread]; - }], - [OWSTableItem itemWithTitle:@"Test Directional Filenames" - actionBlock:^{ - [DebugUIMessages testDirectionalFilenamesInThread:thread]; - }], - [OWSTableItem itemWithTitle:@"Test Linkification" - actionBlock:^{ - [DebugUIMessages testLinkificationInThread:thread]; - }], - - ]]; - - if ([thread isKindOfClass:[TSContactThread class]]) { - TSContactThread *contactThread = (TSContactThread *)thread; - NSString *recipientId = contactThread.contactIdentifier; - [items addObject:[OWSTableItem itemWithTitle:@"Create 10 new groups" - actionBlock:^{ - [DebugUIMessages createNewGroups:10 recipientId:recipientId]; - }]]; - [items addObject:[OWSTableItem itemWithTitle:@"Create 100 new groups" - actionBlock:^{ - [DebugUIMessages createNewGroups:100 recipientId:recipientId]; - }]]; - [items addObject:[OWSTableItem itemWithTitle:@"Create 1,000 new groups" - actionBlock:^{ - [DebugUIMessages createNewGroups:1000 recipientId:recipientId]; - }]]; - } - if ([thread isKindOfClass:[TSGroupThread class]]) { - TSGroupThread *groupThread = (TSGroupThread *)thread; - [items addObject:[OWSTableItem itemWithTitle:@"Send message to all members" - actionBlock:^{ - [DebugUIMessages sendMessages:1 toAllMembersOfGroup:groupThread]; - }]]; - } - -#endif - - return [OWSTableSection sectionWithTitle:self.name items:items]; -} - -#ifdef DEBUG - -#pragma mark - Dependencies - -- (YapDatabaseConnection *)dbConnection -{ - return self.class.dbConnection; -} - -+ (YapDatabaseConnection *)dbConnection -{ - return SSKEnvironment.shared.primaryStorage.dbReadWriteConnection; -} - -+ (SSKMessageSenderJobQueue *)messageSenderJobQueue -{ - return SSKEnvironment.shared.messageSenderJobQueue; -} - -- (SSKMessageSenderJobQueue *)messageSenderJobQueue -{ - return self.class.messageSenderJobQueue; -} - -+ (void)sendMessages:(NSUInteger)count toAllMembersOfGroup:(TSGroupThread *)groupThread -{ - for (NSString *recipientId in groupThread.groupModel.groupMemberIds) { - TSContactThread *contactThread = [TSContactThread getOrCreateThreadWithContactId:recipientId]; - [[self sendTextMessagesActionInThread:contactThread] prepareAndPerformNTimes:count]; - } -} - -+ (void)sendTextMessageInThread:(TSThread *)thread counter:(NSUInteger)counter -{ - OWSLogInfo(@"sendTextMessageInThread: %zd", counter); - [DDLog flushLog]; - - NSString *randomText = [self randomText]; - NSString *text = [[[@(counter) description] stringByAppendingString:@" "] stringByAppendingString:randomText]; - __block TSOutgoingMessage *message; - [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - message = [ThreadUtil enqueueMessageWithText:text - inThread:thread - quotedReplyModel:nil - linkPreviewDraft:nil - transaction:transaction]; - }]; - OWSLogError(@"sendTextMessageInThread timestamp: %llu.", message.timestamp); -} - -+ (void)sendNTextMessagesInThread:(TSThread *)thread -{ - [self performActionNTimes:[self sendTextMessagesActionInThread:thread]]; -} - -+ (DebugUIMessagesAction *)sendTextMessagesActionInThread:(TSThread *)thread -{ - OWSAssertDebug(thread); - - return [DebugUIMessagesSingleAction actionWithLabel:@"Send Text Message" - staggeredActionBlock:^(NSUInteger index, - YapDatabaseReadWriteTransaction *transaction, - ActionSuccessBlock success, - ActionFailureBlock failure) { - dispatch_async(dispatch_get_main_queue(), ^{ - [self sendTextMessageInThread:thread counter:index]; - // TODO: - success(); - }); - }]; -} - -+ (void)sendAttachmentWithFilePath:(NSString *)filePath - thread:(TSThread *)thread - label:(NSString *)label - hasCaption:(BOOL)hasCaption - success:(nullable void (^)(void))success - failure:(nullable void (^)(void))failure -{ - OWSAssertDebug(filePath); - OWSAssertDebug(thread); - - NSString *filename = [filePath lastPathComponent]; - NSString *utiType = [MIMETypeUtil utiTypeForFileExtension:filename.pathExtension]; - DataSource *_Nullable dataSource = [DataSourcePath dataSourceWithFilePath:filePath shouldDeleteOnDeallocation:NO]; - [dataSource setSourceFilename:filename]; - SignalAttachment *attachment = - [SignalAttachment attachmentWithDataSource:dataSource dataUTI:utiType imageQuality:TSImageQualityOriginal]; - - NSString *messageBody = nil; - if (hasCaption) { - // We want a message body that is "more than one line on all devices, - // using all dynamic type sizes." - NSString *sampleText = @"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, " - @"consectetur adipiscing elit."; - messageBody = [[label stringByAppendingString:@" "] stringByAppendingString:sampleText]; - - messageBody = [messageBody stringByAppendingString:@" 🔤"]; - } - attachment.captionText = messageBody; - - OWSAssertDebug(attachment); - if ([attachment hasError]) { - OWSLogError(@"attachment[%@]: %@", [attachment sourceFilename], [attachment errorName]); - [DDLog flushLog]; - } - OWSAssertDebug(![attachment hasError]); - - [self sendAttachment:attachment thread:thread messageBody:messageBody]; - - success(); -} - -#pragma mark - Infrastructure - -+ (void)performActionNTimes:(DebugUIMessagesAction *)action -{ - OWSAssertIsOnMainThread(); - OWSAssertDebug(action); - - UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"How many?" - message:nil - preferredStyle:UIAlertControllerStyleActionSheet]; - for (NSNumber *countValue in @[ - @(1), - @(10), - @(100), - @(1 * 1000), - @(10 * 1000), - ]) { - [alert addAction:[UIAlertAction actionWithTitle:countValue.stringValue - style:UIAlertActionStyleDefault - handler:^(UIAlertAction *ignore) { - [action prepareAndPerformNTimes:countValue.unsignedIntegerValue]; - }]]; - } - - [alert addAction:[OWSAlerts cancelAction]]; - UIViewController *fromViewController = [[UIApplication sharedApplication] frontmostViewController]; - [fromViewController presentAlert:alert]; -} - -#pragma mark - Send Media - -+ (NSArray *)allSendMediaActions:(TSThread *)thread -{ - OWSAssertDebug(thread); - - NSArray *actions = @[ - [self sendJpegAction:thread hasCaption:NO], - [self sendJpegAction:thread hasCaption:YES], - [self sendGifAction:thread hasCaption:NO], - [self sendGifAction:thread hasCaption:YES], - [self sendLargeGifAction:thread hasCaption:NO], - [self sendLargeGifAction:thread hasCaption:YES], - [self sendMp3Action:thread hasCaption:NO], - [self sendMp3Action:thread hasCaption:YES], - [self sendMp4Action:thread hasCaption:NO], - [self sendMp4Action:thread hasCaption:YES], - ]; - return actions; -} - -+ (DebugUIMessagesAction *)sendJpegAction:(TSThread *)thread hasCaption:(BOOL)hasCaption -{ - OWSAssertDebug(thread); - - return [self sendMediaAction:@"Send Jpeg" - hasCaption:hasCaption - fakeAssetLoader:[DebugUIMessagesAssetLoader jpegInstance] - thread:thread]; -} - -+ (DebugUIMessagesAction *)sendGifAction:(TSThread *)thread hasCaption:(BOOL)hasCaption -{ - OWSAssertDebug(thread); - - return [self sendMediaAction:@"Send Gif" - hasCaption:hasCaption - fakeAssetLoader:[DebugUIMessagesAssetLoader gifInstance] - thread:thread]; -} - -+ (DebugUIMessagesAction *)sendLargeGifAction:(TSThread *)thread hasCaption:(BOOL)hasCaption -{ - OWSAssertDebug(thread); - - return [self sendMediaAction:@"Send Large Gif" - hasCaption:hasCaption - fakeAssetLoader:[DebugUIMessagesAssetLoader largeGifInstance] - thread:thread]; -} - -+ (DebugUIMessagesAction *)sendMp3Action:(TSThread *)thread hasCaption:(BOOL)hasCaption -{ - OWSAssertDebug(thread); - - return [self sendMediaAction:@"Send Mp3" - hasCaption:hasCaption - fakeAssetLoader:[DebugUIMessagesAssetLoader mp3Instance] - thread:thread]; -} - -+ (DebugUIMessagesAction *)sendMp4Action:(TSThread *)thread hasCaption:(BOOL)hasCaption -{ - OWSAssertDebug(thread); - - return [self sendMediaAction:@"Send Mp4" - hasCaption:hasCaption - fakeAssetLoader:[DebugUIMessagesAssetLoader mp4Instance] - thread:thread]; -} - -+ (DebugUIMessagesAction *)sendMediaAction:(NSString *)labelParam - hasCaption:(BOOL)hasCaption - fakeAssetLoader:(DebugUIMessagesAssetLoader *)fakeAssetLoader - thread:(TSThread *)thread -{ - OWSAssertDebug(labelParam.length > 0); - OWSAssertDebug(fakeAssetLoader); - OWSAssertDebug(thread); - - NSString *label = labelParam; - if (hasCaption) { - label = [label stringByAppendingString:@" 🔤"]; - } - - return [DebugUIMessagesSingleAction - actionWithLabel:label - staggeredActionBlock:^(NSUInteger index, - YapDatabaseReadWriteTransaction *transaction, - ActionSuccessBlock success, - ActionFailureBlock failure) { - dispatch_async(dispatch_get_main_queue(), ^{ - OWSAssertDebug(fakeAssetLoader.filePath.length > 0); - [self sendAttachmentWithFilePath:fakeAssetLoader.filePath - thread:thread - label:label - hasCaption:hasCaption - success:success - failure:failure]; - }); - } - prepareBlock:fakeAssetLoader.prepareBlock]; -} - -+ (DebugUIMessagesAction *)sendAllMediaAction:(TSThread *)thread -{ - OWSAssertDebug(thread); - - return [DebugUIMessagesGroupAction allGroupActionWithLabel:@"All Send Media" - subactions:[self allSendMediaActions:thread]]; -} - -+ (DebugUIMessagesAction *)sendRandomMediaAction:(TSThread *)thread -{ - OWSAssertDebug(thread); - - return [DebugUIMessagesGroupAction randomGroupActionWithLabel:@"Random Send Media" - subactions:[self allSendMediaActions:thread]]; -} - -+ (void)selectSendMediaAction:(TSThread *)thread -{ - OWSAssertDebug(thread); - - [self selectActionUI:[self allSendMediaActions:thread] label:@"Select Send Media"]; -} - -#pragma mark - Fake Outgoing Media - -+ (DebugUIMessagesAction *)fakeOutgoingJpegAction:(TSThread *)thread - messageState:(TSOutgoingMessageState)messageState - hasCaption:(BOOL)hasCaption -{ - OWSAssertDebug(thread); - - return [self fakeOutgoingMediaAction:@"Fake Outgoing Jpeg" - messageState:messageState - hasCaption:hasCaption - fakeAssetLoader:[DebugUIMessagesAssetLoader jpegInstance] - thread:thread]; -} - -+ (DebugUIMessagesAction *)fakeOutgoingGifAction:(TSThread *)thread - messageState:(TSOutgoingMessageState)messageState - hasCaption:(BOOL)hasCaption -{ - OWSAssertDebug(thread); - - return [self fakeOutgoingMediaAction:@"Fake Outgoing Gif" - messageState:messageState - hasCaption:hasCaption - fakeAssetLoader:[DebugUIMessagesAssetLoader gifInstance] - thread:thread]; -} - -+ (DebugUIMessagesAction *)fakeOutgoingLargeGifAction:(TSThread *)thread - messageState:(TSOutgoingMessageState)messageState - hasCaption:(BOOL)hasCaption -{ - OWSAssertDebug(thread); - - return [self fakeOutgoingMediaAction:@"Fake Outgoing Large Gif" - messageState:messageState - hasCaption:hasCaption - fakeAssetLoader:[DebugUIMessagesAssetLoader largeGifInstance] - thread:thread]; -} - -+ (DebugUIMessagesAction *)fakeOutgoingMp3Action:(TSThread *)thread - messageState:(TSOutgoingMessageState)messageState - hasCaption:(BOOL)hasCaption -{ - OWSAssertDebug(thread); - - return [self fakeOutgoingMediaAction:@"Fake Outgoing Mp3" - messageState:messageState - hasCaption:hasCaption - fakeAssetLoader:[DebugUIMessagesAssetLoader mp3Instance] - thread:thread]; -} - -+ (DebugUIMessagesAction *)fakeOutgoingMp4Action:(TSThread *)thread - messageState:(TSOutgoingMessageState)messageState - hasCaption:(BOOL)hasCaption -{ - OWSAssertDebug(thread); - - return [self fakeOutgoingMediaAction:@"Fake Outgoing Mp4" - messageState:messageState - hasCaption:hasCaption - fakeAssetLoader:[DebugUIMessagesAssetLoader mp4Instance] - thread:thread]; -} - -+ (DebugUIMessagesAction *)fakeOutgoingCompactPortraitPngAction:(TSThread *)thread - messageState:(TSOutgoingMessageState)messageState - hasCaption:(BOOL)hasCaption -{ - OWSAssertDebug(thread); - - return [self fakeOutgoingMediaAction:@"Fake Outgoing Portrait Png" - messageState:messageState - hasCaption:hasCaption - fakeAssetLoader:[DebugUIMessagesAssetLoader compactLandscapePngInstance] - thread:thread]; -} - -+ (DebugUIMessagesAction *)fakeOutgoingCompactLandscapePngAction:(TSThread *)thread - messageState:(TSOutgoingMessageState)messageState - hasCaption:(BOOL)hasCaption -{ - OWSAssertDebug(thread); - - return [self fakeOutgoingMediaAction:@"Fake Outgoing Landscape Png" - messageState:messageState - hasCaption:hasCaption - fakeAssetLoader:[DebugUIMessagesAssetLoader compactPortraitPngInstance] - thread:thread]; -} - -+ (DebugUIMessagesAction *)fakeOutgoingTallPortraitPngAction:(TSThread *)thread - messageState:(TSOutgoingMessageState)messageState - hasCaption:(BOOL)hasCaption -{ - OWSAssertDebug(thread); - - return [self fakeOutgoingMediaAction:@"Fake Outgoing Tall Portrait Png" - messageState:messageState - hasCaption:hasCaption - fakeAssetLoader:[DebugUIMessagesAssetLoader tallPortraitPngInstance] - thread:thread]; -} - -+ (DebugUIMessagesAction *)fakeOutgoingWideLandscapePngAction:(TSThread *)thread - messageState:(TSOutgoingMessageState)messageState - hasCaption:(BOOL)hasCaption -{ - OWSAssertDebug(thread); - - return [self fakeOutgoingMediaAction:@"Fake Outgoing Wide Landscape Png" - messageState:messageState - hasCaption:hasCaption - fakeAssetLoader:[DebugUIMessagesAssetLoader wideLandscapePngInstance] - thread:thread]; -} - -+ (DebugUIMessagesAction *)fakeOutgoingLargePngAction:(TSThread *)thread - messageState:(TSOutgoingMessageState)messageState - hasCaption:(BOOL)hasCaption -{ - OWSAssertDebug(thread); - - return [self fakeOutgoingMediaAction:@"Fake Outgoing Large Png" - messageState:messageState - hasCaption:hasCaption - fakeAssetLoader:[DebugUIMessagesAssetLoader largePngInstance] - thread:thread]; -} - -+ (DebugUIMessagesAction *)fakeOutgoingTinyPngAction:(TSThread *)thread - messageState:(TSOutgoingMessageState)messageState - hasCaption:(BOOL)hasCaption -{ - OWSAssertDebug(thread); - - return [self fakeOutgoingMediaAction:@"Fake Outgoing Tiny Png" - messageState:messageState - hasCaption:hasCaption - fakeAssetLoader:[DebugUIMessagesAssetLoader tinyPngInstance] - thread:thread]; -} - -+ (DebugUIMessagesAction *)fakeOutgoingPngAction:(TSThread *)thread - actionLabel:(NSString *)actionLabel - imageSize:(CGSize)imageSize - backgroundColor:(UIColor *)backgroundColor - textColor:(UIColor *)textColor - imageLabel:(NSString *)imageLabel - messageState:(TSOutgoingMessageState)messageState - hasCaption:(BOOL)hasCaption -{ - OWSAssertDebug(thread); - - return [self fakeOutgoingMediaAction:actionLabel - messageState:messageState - hasCaption:hasCaption - fakeAssetLoader:[DebugUIMessagesAssetLoader pngInstanceWithSize:imageSize - backgroundColor:backgroundColor - textColor:textColor - label:imageLabel] - thread:thread]; -} - -+ (DebugUIMessagesAction *)fakeOutgoingTinyPdfAction:(TSThread *)thread - messageState:(TSOutgoingMessageState)messageState - hasCaption:(BOOL)hasCaption -{ - OWSAssertDebug(thread); - - return [self fakeOutgoingMediaAction:@"Fake Outgoing Tiny Pdf" - messageState:messageState - hasCaption:hasCaption - fakeAssetLoader:[DebugUIMessagesAssetLoader tinyPdfInstance] - thread:thread]; -} - -+ (DebugUIMessagesAction *)fakeOutgoingLargePdfAction:(TSThread *)thread - messageState:(TSOutgoingMessageState)messageState - hasCaption:(BOOL)hasCaption -{ - OWSAssertDebug(thread); - - return [self fakeOutgoingMediaAction:@"Fake Outgoing Large Pdf" - messageState:messageState - hasCaption:hasCaption - fakeAssetLoader:[DebugUIMessagesAssetLoader largePdfInstance] - thread:thread]; -} - -+ (DebugUIMessagesAction *)fakeOutgoingMissingPngAction:(TSThread *)thread - messageState:(TSOutgoingMessageState)messageState - hasCaption:(BOOL)hasCaption -{ - OWSAssertDebug(thread); - - return [self fakeOutgoingMediaAction:@"Fake Outgoing Missing Png" - messageState:messageState - hasCaption:hasCaption - fakeAssetLoader:[DebugUIMessagesAssetLoader missingPngInstance] - thread:thread]; -} - -+ (DebugUIMessagesAction *)fakeOutgoingMissingPdfAction:(TSThread *)thread - messageState:(TSOutgoingMessageState)messageState - hasCaption:(BOOL)hasCaption -{ - OWSAssertDebug(thread); - - return [self fakeOutgoingMediaAction:@"Fake Outgoing Missing Pdf" - messageState:messageState - hasCaption:hasCaption - fakeAssetLoader:[DebugUIMessagesAssetLoader missingPdfInstance] - thread:thread]; -} - -+ (DebugUIMessagesAction *)fakeOutgoingOversizeTextAction:(TSThread *)thread - messageState:(TSOutgoingMessageState)messageState - hasCaption:(BOOL)hasCaption -{ - OWSAssertDebug(thread); - - return [self fakeOutgoingMediaAction:@"Fake Outgoing Oversize Text" - messageState:messageState - hasCaption:hasCaption - fakeAssetLoader:[DebugUIMessagesAssetLoader oversizeTextInstance] - thread:thread]; -} - -+ (DebugUIMessagesAction *)fakeOutgoingMediaAction:(NSString *)labelParam - messageState:(TSOutgoingMessageState)messageState - hasCaption:(BOOL)hasCaption - fakeAssetLoader:(DebugUIMessagesAssetLoader *)fakeAssetLoader - thread:(TSThread *)thread -{ - OWSAssertDebug(labelParam.length > 0); - OWSAssertDebug(fakeAssetLoader); - OWSAssertDebug(thread); - - NSString *label = [labelParam stringByAppendingString:[self actionLabelForHasCaption:hasCaption - outgoingMessageState:messageState - isDelivered:NO - isRead:NO]]; - - return - [DebugUIMessagesSingleAction actionWithLabel:label - unstaggeredActionBlock:^(NSUInteger index, YapDatabaseReadWriteTransaction *transaction) { - OWSAssertDebug(fakeAssetLoader.filePath.length > 0); - [self createFakeOutgoingMedia:index - messageState:messageState - hasCaption:hasCaption - fakeAssetLoader:fakeAssetLoader - thread:thread - transaction:transaction]; - } - prepareBlock:fakeAssetLoader.prepareBlock]; -} - -+ (void)createFakeOutgoingMedia:(NSUInteger)index - messageState:(TSOutgoingMessageState)messageState - hasCaption:(BOOL)hasCaption - fakeAssetLoader:(DebugUIMessagesAssetLoader *)fakeAssetLoader - thread:(TSThread *)thread - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSAssertDebug(thread); - OWSAssertDebug(fakeAssetLoader.filePath); - OWSAssertDebug(transaction); - - // Random time within last n years. Helpful for filling out a media gallery over time. - // double yearsMillis = 4.0 * kYearsInMs; - // uint64_t millisAgo = (uint64_t)(((double)arc4random() / ((double)0xffffffff)) * yearsMillis); - // uint64_t timestamp = [NSDate ows_millisecondTimeStamp] - millisAgo; - uint64_t timestamp = [NSDate ows_millisecondTimeStamp]; - - NSString *messageBody = nil; - if (hasCaption) { - // We want a message body that is "more than one line on all devices, - // using all dynamic type sizes." - NSString *sampleText = @"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, " - @"consectetur adipiscing elit."; - messageBody = [[@(index).stringValue stringByAppendingString:@" "] stringByAppendingString:sampleText]; - messageBody = [messageBody stringByAppendingString:[self actionLabelForHasCaption:hasCaption - outgoingMessageState:messageState - isDelivered:NO - isRead:NO]]; - } - - TSOutgoingMessage *message = [self createFakeOutgoingMessage:thread - messageBody:messageBody - fakeAssetLoader:fakeAssetLoader - messageState:messageState - isDelivered:YES - isRead:NO - quotedMessage:nil - contactShare:nil - linkPreview:nil - transaction:transaction]; - - // This is a hack to "back-date" the message. - [message setReceivedAtTimestamp:timestamp]; - - [message saveWithTransaction:transaction]; -} - -#pragma mark - Fake Incoming Media - -+ (DebugUIMessagesAction *)fakeIncomingJpegAction:(TSThread *)thread - isAttachmentDownloaded:(BOOL)isAttachmentDownloaded - hasCaption:(BOOL)hasCaption -{ - OWSAssertDebug(thread); - - return [self fakeIncomingMediaAction:@"Fake Incoming Jpeg" - isAttachmentDownloaded:isAttachmentDownloaded - hasCaption:hasCaption - fakeAssetLoader:[DebugUIMessagesAssetLoader jpegInstance] - thread:thread]; -} - -+ (DebugUIMessagesAction *)fakeIncomingGifAction:(TSThread *)thread - isAttachmentDownloaded:(BOOL)isAttachmentDownloaded - hasCaption:(BOOL)hasCaption -{ - OWSAssertDebug(thread); - - return [self fakeIncomingMediaAction:@"Fake Incoming Gif" - isAttachmentDownloaded:isAttachmentDownloaded - hasCaption:hasCaption - fakeAssetLoader:[DebugUIMessagesAssetLoader gifInstance] - thread:thread]; -} - -+ (DebugUIMessagesAction *)fakeIncomingLargeGifAction:(TSThread *)thread - isAttachmentDownloaded:(BOOL)isAttachmentDownloaded - hasCaption:(BOOL)hasCaption -{ - OWSAssertDebug(thread); - - return [self fakeIncomingMediaAction:@"Fake Incoming Large Gif" - isAttachmentDownloaded:isAttachmentDownloaded - hasCaption:hasCaption - fakeAssetLoader:[DebugUIMessagesAssetLoader largeGifInstance] - thread:thread]; -} - -+ (DebugUIMessagesAction *)fakeIncomingMp3Action:(TSThread *)thread - isAttachmentDownloaded:(BOOL)isAttachmentDownloaded - hasCaption:(BOOL)hasCaption -{ - OWSAssertDebug(thread); - - return [self fakeIncomingMediaAction:@"Fake Incoming Mp3" - isAttachmentDownloaded:isAttachmentDownloaded - hasCaption:hasCaption - fakeAssetLoader:[DebugUIMessagesAssetLoader mp3Instance] - thread:thread]; -} - -+ (DebugUIMessagesAction *)fakeIncomingMp4Action:(TSThread *)thread - isAttachmentDownloaded:(BOOL)isAttachmentDownloaded - hasCaption:(BOOL)hasCaption -{ - OWSAssertDebug(thread); - - return [self fakeIncomingMediaAction:@"Fake Incoming Mp4" - isAttachmentDownloaded:isAttachmentDownloaded - hasCaption:hasCaption - fakeAssetLoader:[DebugUIMessagesAssetLoader mp4Instance] - thread:thread]; -} - -+ (DebugUIMessagesAction *)fakeIncomingCompactPortraitPngAction:(TSThread *)thread - isAttachmentDownloaded:(BOOL)isAttachmentDownloaded - hasCaption:(BOOL)hasCaption -{ - OWSAssertDebug(thread); - - return [self fakeIncomingMediaAction:@"Fake Incoming Portrait Png" - isAttachmentDownloaded:isAttachmentDownloaded - hasCaption:hasCaption - fakeAssetLoader:[DebugUIMessagesAssetLoader compactPortraitPngInstance] - thread:thread]; -} - -+ (DebugUIMessagesAction *)fakeIncomingCompactLandscapePngAction:(TSThread *)thread - isAttachmentDownloaded:(BOOL)isAttachmentDownloaded - hasCaption:(BOOL)hasCaption -{ - OWSAssertDebug(thread); - - return [self fakeIncomingMediaAction:@"Fake Incoming Landscape Png" - isAttachmentDownloaded:isAttachmentDownloaded - hasCaption:hasCaption - fakeAssetLoader:[DebugUIMessagesAssetLoader compactLandscapePngInstance] - thread:thread]; -} - -+ (DebugUIMessagesAction *)fakeIncomingTallPortraitPngAction:(TSThread *)thread - isAttachmentDownloaded:(BOOL)isAttachmentDownloaded - hasCaption:(BOOL)hasCaption -{ - OWSAssertDebug(thread); - - return [self fakeIncomingMediaAction:@"Fake Incoming Tall Portrait Png" - isAttachmentDownloaded:isAttachmentDownloaded - hasCaption:hasCaption - fakeAssetLoader:[DebugUIMessagesAssetLoader tallPortraitPngInstance] - thread:thread]; -} - -+ (DebugUIMessagesAction *)fakeIncomingWideLandscapePngAction:(TSThread *)thread - isAttachmentDownloaded:(BOOL)isAttachmentDownloaded - hasCaption:(BOOL)hasCaption -{ - OWSAssertDebug(thread); - - return [self fakeIncomingMediaAction:@"Fake Incoming Wide Landscape Png" - isAttachmentDownloaded:isAttachmentDownloaded - hasCaption:hasCaption - fakeAssetLoader:[DebugUIMessagesAssetLoader wideLandscapePngInstance] - thread:thread]; -} - -+ (DebugUIMessagesAction *)fakeIncomingLargePngAction:(TSThread *)thread - isAttachmentDownloaded:(BOOL)isAttachmentDownloaded - hasCaption:(BOOL)hasCaption -{ - OWSAssertDebug(thread); - - return [self fakeIncomingMediaAction:@"Fake Incoming Large Png" - isAttachmentDownloaded:isAttachmentDownloaded - hasCaption:hasCaption - fakeAssetLoader:[DebugUIMessagesAssetLoader largePngInstance] - thread:thread]; -} - -+ (DebugUIMessagesAction *)fakeIncomingTinyPngAction:(TSThread *)thread - isAttachmentDownloaded:(BOOL)isAttachmentDownloaded - hasCaption:(BOOL)hasCaption -{ - OWSAssertDebug(thread); - - return [self fakeIncomingMediaAction:@"Tiny Incoming Large Png" - isAttachmentDownloaded:isAttachmentDownloaded - hasCaption:hasCaption - fakeAssetLoader:[DebugUIMessagesAssetLoader tinyPngInstance] - thread:thread]; -} - -+ (DebugUIMessagesAction *)fakeIncomingPngAction:(TSThread *)thread - actionLabel:(NSString *)actionLabel - imageSize:(CGSize)imageSize - backgroundColor:(UIColor *)backgroundColor - textColor:(UIColor *)textColor - imageLabel:(NSString *)imageLabel - isAttachmentDownloaded:(BOOL)isAttachmentDownloaded - hasCaption:(BOOL)hasCaption -{ - OWSAssertDebug(thread); - - return [self fakeIncomingMediaAction:actionLabel - isAttachmentDownloaded:isAttachmentDownloaded - hasCaption:hasCaption - fakeAssetLoader:[DebugUIMessagesAssetLoader pngInstanceWithSize:imageSize - backgroundColor:backgroundColor - textColor:textColor - label:imageLabel] - thread:thread]; -} - -+ (DebugUIMessagesAction *)fakeIncomingTinyPdfAction:(TSThread *)thread - isAttachmentDownloaded:(BOOL)isAttachmentDownloaded - hasCaption:(BOOL)hasCaption -{ - OWSAssertDebug(thread); - - return [self fakeIncomingMediaAction:@"Fake Incoming Tiny Pdf" - isAttachmentDownloaded:isAttachmentDownloaded - hasCaption:hasCaption - fakeAssetLoader:[DebugUIMessagesAssetLoader tinyPdfInstance] - thread:thread]; -} - -+ (DebugUIMessagesAction *)fakeIncomingLargePdfAction:(TSThread *)thread - isAttachmentDownloaded:(BOOL)isAttachmentDownloaded - hasCaption:(BOOL)hasCaption -{ - OWSAssertDebug(thread); - - return [self fakeIncomingMediaAction:@"Fake Incoming Large Pdf" - isAttachmentDownloaded:isAttachmentDownloaded - hasCaption:hasCaption - fakeAssetLoader:[DebugUIMessagesAssetLoader largePdfInstance] - thread:thread]; -} - -+ (DebugUIMessagesAction *)fakeIncomingMissingPngAction:(TSThread *)thread - isAttachmentDownloaded:(BOOL)isAttachmentDownloaded - hasCaption:(BOOL)hasCaption -{ - OWSAssertDebug(thread); - - return [self fakeIncomingMediaAction:@"Fake Incoming Missing Png" - isAttachmentDownloaded:isAttachmentDownloaded - hasCaption:hasCaption - fakeAssetLoader:[DebugUIMessagesAssetLoader missingPngInstance] - thread:thread]; -} - -+ (DebugUIMessagesAction *)fakeIncomingMissingPdfAction:(TSThread *)thread - isAttachmentDownloaded:(BOOL)isAttachmentDownloaded - hasCaption:(BOOL)hasCaption -{ - OWSAssertDebug(thread); - - return [self fakeIncomingMediaAction:@"Fake Incoming Missing Pdf" - isAttachmentDownloaded:isAttachmentDownloaded - hasCaption:hasCaption - fakeAssetLoader:[DebugUIMessagesAssetLoader missingPdfInstance] - thread:thread]; -} - -+ (DebugUIMessagesAction *)fakeIncomingOversizeTextAction:(TSThread *)thread - isAttachmentDownloaded:(BOOL)isAttachmentDownloaded - hasCaption:(BOOL)hasCaption -{ - OWSAssertDebug(thread); - - return [self fakeIncomingMediaAction:@"Fake Incoming Oversize Text" - isAttachmentDownloaded:isAttachmentDownloaded - hasCaption:hasCaption - fakeAssetLoader:[DebugUIMessagesAssetLoader oversizeTextInstance] - thread:thread]; -} - -+ (DebugUIMessagesAction *)fakeIncomingMediaAction:(NSString *)labelParam - isAttachmentDownloaded:(BOOL)isAttachmentDownloaded - hasCaption:(BOOL)hasCaption - fakeAssetLoader:(DebugUIMessagesAssetLoader *)fakeAssetLoader - thread:(TSThread *)thread -{ - OWSAssertDebug(labelParam.length > 0); - OWSAssertDebug(fakeAssetLoader); - OWSAssertDebug(thread); - - NSString *label = labelParam; - if (hasCaption) { - label = [label stringByAppendingString:@" 🔤"]; - } - - if (isAttachmentDownloaded) { - label = [label stringByAppendingString:@" 👍"]; - } - - return - [DebugUIMessagesSingleAction actionWithLabel:label - unstaggeredActionBlock:^(NSUInteger index, YapDatabaseReadWriteTransaction *transaction) { - OWSAssertDebug(fakeAssetLoader.filePath.length > 0); - [self createFakeIncomingMedia:index - isAttachmentDownloaded:isAttachmentDownloaded - hasCaption:hasCaption - fakeAssetLoader:fakeAssetLoader - thread:thread - transaction:transaction]; - } - prepareBlock:fakeAssetLoader.prepareBlock]; -} - -+ (TSIncomingMessage *)createFakeIncomingMedia:(NSUInteger)index - isAttachmentDownloaded:(BOOL)isAttachmentDownloaded - hasCaption:(BOOL)hasCaption - fakeAssetLoader:(DebugUIMessagesAssetLoader *)fakeAssetLoader - thread:(TSThread *)thread - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - NSString *_Nullable caption = nil; - if (hasCaption) { - // We want a message body that is "more than one line on all devices, - // using all dynamic type sizes." - caption = @"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, " - @"consectetur adipiscing elit."; - } - return [self createFakeIncomingMedia:index - isAttachmentDownloaded:isAttachmentDownloaded - caption:caption - fakeAssetLoader:fakeAssetLoader - thread:thread - transaction:transaction]; -} - -+ (TSIncomingMessage *)createFakeIncomingMedia:(NSUInteger)index - isAttachmentDownloaded:(BOOL)isAttachmentDownloaded - caption:(nullable NSString *)caption - fakeAssetLoader:(DebugUIMessagesAssetLoader *)fakeAssetLoader - thread:(TSThread *)thread - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSAssertDebug(thread); - OWSAssertDebug(fakeAssetLoader.filePath); - OWSAssertDebug(transaction); - - // // Random time within last n years. Helpful for filling out a media gallery over time. - // double yearsMillis = 4.0 * kYearsInMs; - // uint64_t millisAgo = (uint64_t)(((double)arc4random() / ((double)0xffffffff)) * yearsMillis); - // uint64_t timestamp = [NSDate ows_millisecondTimeStamp] - millisAgo; - - NSString *messageBody = nil; - if (caption) { - messageBody = [[@(index).stringValue stringByAppendingString:@" "] stringByAppendingString:caption]; - - messageBody = [messageBody stringByAppendingString:@" 🔤"]; - - if (isAttachmentDownloaded) { - messageBody = [messageBody stringByAppendingString:@" 👍"]; - } - } - - return [self createFakeIncomingMessage:thread - messageBody:messageBody - fakeAssetLoader:fakeAssetLoader - isAttachmentDownloaded:isAttachmentDownloaded - quotedMessage:nil - transaction:transaction]; -} - -#pragma mark - Fake Media - -+ (NSArray *)allFakeMediaActions:(TSThread *)thread includeLabels:(BOOL)includeLabels -{ - OWSAssertDebug(thread); - - NSMutableArray *actions = [NSMutableArray new]; - - if (includeLabels) { - [actions addObject:[self fakeOutgoingTextMessageAction:thread - messageState:TSOutgoingMessageStateSent - text:@"⚠️ Outgoing Jpeg ⚠️"]]; - } - [actions addObjectsFromArray:@[ - [self fakeOutgoingJpegAction:thread messageState:TSOutgoingMessageStateFailed hasCaption:NO], - [self fakeOutgoingJpegAction:thread messageState:TSOutgoingMessageStateFailed hasCaption:YES], - [self fakeOutgoingJpegAction:thread messageState:TSOutgoingMessageStateSending hasCaption:NO], - [self fakeOutgoingJpegAction:thread messageState:TSOutgoingMessageStateSending hasCaption:YES], - [self fakeOutgoingJpegAction:thread messageState:TSOutgoingMessageStateSent hasCaption:NO], - [self fakeOutgoingJpegAction:thread messageState:TSOutgoingMessageStateSent hasCaption:YES], - ]]; - if (includeLabels) { - [actions addObject:[self fakeOutgoingTextMessageAction:thread - messageState:TSOutgoingMessageStateSent - text:@"⚠️ Outgoing Gif ⚠️"]]; - } - [actions addObjectsFromArray:@[ - // Don't bother with multiple GIF states. - [self fakeOutgoingGifAction:thread messageState:TSOutgoingMessageStateSent hasCaption:NO], - [self fakeOutgoingLargeGifAction:thread messageState:TSOutgoingMessageStateSent hasCaption:NO], - ]]; - if (includeLabels) { - [actions addObject:[self fakeOutgoingTextMessageAction:thread - messageState:TSOutgoingMessageStateSent - text:@"⚠️ Outgoing Mp3 ⚠️"]]; - } - [actions addObjectsFromArray:@[ - [self fakeOutgoingMp3Action:thread messageState:TSOutgoingMessageStateSending hasCaption:YES], - [self fakeOutgoingMp3Action:thread messageState:TSOutgoingMessageStateSending hasCaption:NO], - [self fakeOutgoingMp3Action:thread messageState:TSOutgoingMessageStateFailed hasCaption:NO], - [self fakeOutgoingMp3Action:thread messageState:TSOutgoingMessageStateFailed hasCaption:YES], - [self fakeOutgoingMp3Action:thread messageState:TSOutgoingMessageStateSent hasCaption:NO], - [self fakeOutgoingMp3Action:thread messageState:TSOutgoingMessageStateSent hasCaption:YES], - ]]; - if (includeLabels) { - [actions addObject:[self fakeOutgoingTextMessageAction:thread - messageState:TSOutgoingMessageStateSent - text:@"⚠️ Outgoing Mp4 ⚠️"]]; - } - [actions addObjectsFromArray:@[ - [self fakeOutgoingMp4Action:thread messageState:TSOutgoingMessageStateSending hasCaption:NO], - [self fakeOutgoingMp4Action:thread messageState:TSOutgoingMessageStateSending hasCaption:YES], - [self fakeOutgoingMp4Action:thread messageState:TSOutgoingMessageStateFailed hasCaption:NO], - [self fakeOutgoingMp4Action:thread messageState:TSOutgoingMessageStateFailed hasCaption:YES], - [self fakeOutgoingMp4Action:thread messageState:TSOutgoingMessageStateSent hasCaption:NO], - [self fakeOutgoingMp4Action:thread messageState:TSOutgoingMessageStateSent hasCaption:YES], - ]]; - if (includeLabels) { - [actions addObject:[self fakeOutgoingTextMessageAction:thread - messageState:TSOutgoingMessageStateSent - text:@"⚠️ Outgoing Compact Landscape Png ⚠️"]]; - } - [actions addObjectsFromArray:@[ - [self fakeOutgoingCompactLandscapePngAction:thread messageState:TSOutgoingMessageStateSending hasCaption:NO], - [self fakeOutgoingCompactLandscapePngAction:thread messageState:TSOutgoingMessageStateSending hasCaption:YES], - [self fakeOutgoingCompactLandscapePngAction:thread messageState:TSOutgoingMessageStateFailed hasCaption:NO], - [self fakeOutgoingCompactLandscapePngAction:thread messageState:TSOutgoingMessageStateFailed hasCaption:YES], - [self fakeOutgoingCompactLandscapePngAction:thread messageState:TSOutgoingMessageStateSent hasCaption:NO], - [self fakeOutgoingCompactLandscapePngAction:thread messageState:TSOutgoingMessageStateSent hasCaption:YES], - ]]; - if (includeLabels) { - [actions addObject:[self fakeOutgoingTextMessageAction:thread - messageState:TSOutgoingMessageStateSent - text:@"⚠️ Outgoing Compact Portrait Png ⚠️"]]; - } - [actions addObjectsFromArray:@[ - [self fakeOutgoingCompactPortraitPngAction:thread messageState:TSOutgoingMessageStateSending hasCaption:NO], - [self fakeOutgoingCompactPortraitPngAction:thread messageState:TSOutgoingMessageStateSending hasCaption:YES], - [self fakeOutgoingCompactPortraitPngAction:thread messageState:TSOutgoingMessageStateFailed hasCaption:NO], - [self fakeOutgoingCompactPortraitPngAction:thread messageState:TSOutgoingMessageStateFailed hasCaption:YES], - [self fakeOutgoingCompactPortraitPngAction:thread messageState:TSOutgoingMessageStateSent hasCaption:NO], - [self fakeOutgoingCompactPortraitPngAction:thread messageState:TSOutgoingMessageStateSent hasCaption:YES], - ]]; - if (includeLabels) { - [actions addObject:[self fakeOutgoingTextMessageAction:thread - messageState:TSOutgoingMessageStateSent - text:@"⚠️ Outgoing Wide Landscape Png ⚠️"]]; - } - [actions addObjectsFromArray:@[ - [self fakeOutgoingWideLandscapePngAction:thread messageState:TSOutgoingMessageStateSending hasCaption:NO], - [self fakeOutgoingWideLandscapePngAction:thread messageState:TSOutgoingMessageStateSending hasCaption:YES], - [self fakeOutgoingWideLandscapePngAction:thread messageState:TSOutgoingMessageStateFailed hasCaption:NO], - [self fakeOutgoingWideLandscapePngAction:thread messageState:TSOutgoingMessageStateFailed hasCaption:YES], - [self fakeOutgoingWideLandscapePngAction:thread messageState:TSOutgoingMessageStateSent hasCaption:NO], - [self fakeOutgoingWideLandscapePngAction:thread messageState:TSOutgoingMessageStateSent hasCaption:YES], - ]]; - if (includeLabels) { - [actions addObject:[self fakeOutgoingTextMessageAction:thread - messageState:TSOutgoingMessageStateSent - text:@"⚠️ Outgoing Tall Portrait Png ⚠️"]]; - } - [actions addObjectsFromArray:@[ - [self fakeOutgoingTallPortraitPngAction:thread messageState:TSOutgoingMessageStateSending hasCaption:NO], - [self fakeOutgoingTallPortraitPngAction:thread messageState:TSOutgoingMessageStateSending hasCaption:YES], - [self fakeOutgoingTallPortraitPngAction:thread messageState:TSOutgoingMessageStateFailed hasCaption:NO], - [self fakeOutgoingTallPortraitPngAction:thread messageState:TSOutgoingMessageStateFailed hasCaption:YES], - [self fakeOutgoingTallPortraitPngAction:thread messageState:TSOutgoingMessageStateSent hasCaption:NO], - [self fakeOutgoingTallPortraitPngAction:thread messageState:TSOutgoingMessageStateSent hasCaption:YES], - ]]; - if (includeLabels) { - [actions addObject:[self fakeOutgoingTextMessageAction:thread - messageState:TSOutgoingMessageStateSent - text:@"⚠️ Outgoing Large Png ⚠️"]]; - } - [actions addObjectsFromArray:@[ - [self fakeOutgoingLargePngAction:thread messageState:TSOutgoingMessageStateSent hasCaption:NO], - [self fakeOutgoingLargePngAction:thread messageState:TSOutgoingMessageStateSent hasCaption:YES], - ]]; - if (includeLabels) { - [actions addObject:[self fakeOutgoingTextMessageAction:thread - messageState:TSOutgoingMessageStateSent - text:@"⚠️ Outgoing Tiny Png ⚠️"]]; - } - [actions addObjectsFromArray:@[ - [self fakeOutgoingTinyPngAction:thread messageState:TSOutgoingMessageStateSent hasCaption:NO], - [self fakeOutgoingTinyPngAction:thread messageState:TSOutgoingMessageStateSent hasCaption:YES], - ]]; - if (includeLabels) { - [actions addObject:[self fakeOutgoingTextMessageAction:thread - messageState:TSOutgoingMessageStateSent - text:@"⚠️ Outgoing Reserved Color Png ⚠️"]]; - } - - ConversationStyle *conversationStyle = [[ConversationStyle alloc] initWithThread:thread]; - [actions addObjectsFromArray:@[ - [self fakeOutgoingPngAction:thread - actionLabel:@"Fake Outgoing White Png" - imageSize:CGSizeMake(200.f, 200.f) - backgroundColor:[UIColor whiteColor] - textColor:[UIColor ows_signalBrandBlueColor] - imageLabel:@"W" - messageState:TSOutgoingMessageStateFailed - hasCaption:YES], - [self fakeOutgoingPngAction:thread - actionLabel:@"Fake Outgoing White Png" - imageSize:CGSizeMake(200.f, 200.f) - backgroundColor:[UIColor whiteColor] - textColor:[UIColor ows_signalBrandBlueColor] - imageLabel:@"W" - messageState:TSOutgoingMessageStateSending - hasCaption:YES], - [self fakeOutgoingPngAction:thread - actionLabel:@"Fake Outgoing White Png" - imageSize:CGSizeMake(200.f, 200.f) - backgroundColor:[UIColor whiteColor] - textColor:[UIColor ows_signalBrandBlueColor] - imageLabel:@"W" - messageState:TSOutgoingMessageStateSent - hasCaption:YES], - - [self fakeOutgoingPngAction:thread - actionLabel:@"Fake Outgoing 'Outgoing' Png" - imageSize:CGSizeMake(200.f, 200.f) - backgroundColor:[conversationStyle bubbleColorWithIsIncoming:NO] - textColor:[UIColor whiteColor] - imageLabel:@"W" - messageState:TSOutgoingMessageStateFailed - hasCaption:YES], - [self fakeOutgoingPngAction:thread - actionLabel:@"Fake Outgoing 'Outgoing' Png" - imageSize:CGSizeMake(200.f, 200.f) - backgroundColor:[conversationStyle bubbleColorWithIsIncoming:NO] - textColor:[UIColor whiteColor] - imageLabel:@"W" - messageState:TSOutgoingMessageStateSending - hasCaption:YES], - [self fakeOutgoingPngAction:thread - actionLabel:@"Fake Outgoing 'Outgoing' Png" - imageSize:CGSizeMake(200.f, 200.f) - backgroundColor:[conversationStyle bubbleColorWithIsIncoming:NO] - textColor:[UIColor whiteColor] - imageLabel:@"W" - messageState:TSOutgoingMessageStateSent - hasCaption:YES], - ]]; - if (includeLabels) { - [actions addObject:[self fakeOutgoingTextMessageAction:thread - messageState:TSOutgoingMessageStateSent - text:@"⚠️ Outgoing Tiny Pdf ⚠️"]]; - } - [actions addObjectsFromArray:@[ - [self fakeOutgoingTinyPdfAction:thread messageState:TSOutgoingMessageStateSending hasCaption:NO], - [self fakeOutgoingTinyPdfAction:thread messageState:TSOutgoingMessageStateSending hasCaption:YES], - [self fakeOutgoingTinyPdfAction:thread messageState:TSOutgoingMessageStateFailed hasCaption:NO], - [self fakeOutgoingTinyPdfAction:thread messageState:TSOutgoingMessageStateFailed hasCaption:YES], - [self fakeOutgoingTinyPdfAction:thread messageState:TSOutgoingMessageStateSent hasCaption:NO], - [self fakeOutgoingTinyPdfAction:thread messageState:TSOutgoingMessageStateSent hasCaption:YES], - ]]; - if (includeLabels) { - [actions addObject:[self fakeOutgoingTextMessageAction:thread - messageState:TSOutgoingMessageStateSent - text:@"⚠️ Outgoing Large Pdf ⚠️"]]; - } - [actions addObjectsFromArray:@[ - [self fakeOutgoingLargePdfAction:thread messageState:TSOutgoingMessageStateFailed hasCaption:NO], - ]]; - if (includeLabels) { - [actions addObject:[self fakeOutgoingTextMessageAction:thread - messageState:TSOutgoingMessageStateSent - text:@"⚠️ Outgoing Missing Png ⚠️"]]; - } - [actions addObjectsFromArray:@[ - [self fakeOutgoingMissingPngAction:thread messageState:TSOutgoingMessageStateFailed hasCaption:NO], - ]]; - if (includeLabels) { - [actions addObject:[self fakeOutgoingTextMessageAction:thread - messageState:TSOutgoingMessageStateSent - text:@"⚠️ Outgoing Large Pdf ⚠️"]]; - } - [actions addObjectsFromArray:@[ - [self fakeOutgoingMissingPdfAction:thread messageState:TSOutgoingMessageStateFailed hasCaption:NO], - ]]; - if (includeLabels) { - [actions addObject:[self fakeOutgoingTextMessageAction:thread - messageState:TSOutgoingMessageStateSent - text:@"⚠️ Outgoing Oversize Text ⚠️"]]; - } - [actions addObjectsFromArray:@[ - [self fakeOutgoingOversizeTextAction:thread messageState:TSOutgoingMessageStateFailed hasCaption:NO], - [self fakeOutgoingOversizeTextAction:thread messageState:TSOutgoingMessageStateSending hasCaption:NO], - [self fakeOutgoingOversizeTextAction:thread messageState:TSOutgoingMessageStateSent hasCaption:NO], - ]]; - - // Incoming - - if (includeLabels) { - [actions addObject:[self fakeIncomingTextMessageAction:thread text:@"⚠️ Incoming Jpg ⚠️"]]; - } - [actions addObjectsFromArray:@[ - [self fakeIncomingJpegAction:thread isAttachmentDownloaded:NO hasCaption:NO], - [self fakeIncomingJpegAction:thread isAttachmentDownloaded:YES hasCaption:NO], - [self fakeIncomingJpegAction:thread isAttachmentDownloaded:NO hasCaption:YES], - [self fakeIncomingJpegAction:thread isAttachmentDownloaded:YES hasCaption:YES], - ]]; - if (includeLabels) { - [actions addObject:[self fakeIncomingTextMessageAction:thread text:@"⚠️ Incoming Gif ⚠️"]]; - } - [actions addObjectsFromArray:@[ - [self fakeIncomingGifAction:thread isAttachmentDownloaded:YES hasCaption:NO], - [self fakeIncomingLargeGifAction:thread isAttachmentDownloaded:YES hasCaption:NO], - ]]; - if (includeLabels) { - [actions addObject:[self fakeIncomingTextMessageAction:thread text:@"⚠️ Incoming Mp3 ⚠️"]]; - } - [actions addObjectsFromArray:@[ - [self fakeIncomingMp3Action:thread isAttachmentDownloaded:NO hasCaption:NO], - [self fakeIncomingMp3Action:thread isAttachmentDownloaded:YES hasCaption:NO], - [self fakeIncomingMp3Action:thread isAttachmentDownloaded:NO hasCaption:YES], - [self fakeIncomingMp3Action:thread isAttachmentDownloaded:YES hasCaption:YES], - ]]; - if (includeLabels) { - [actions addObject:[self fakeIncomingTextMessageAction:thread text:@"⚠️ Incoming Mp4 ⚠️"]]; - } - [actions addObjectsFromArray:@[ - [self fakeIncomingMp4Action:thread isAttachmentDownloaded:NO hasCaption:NO], - [self fakeIncomingMp4Action:thread isAttachmentDownloaded:YES hasCaption:NO], - [self fakeIncomingMp4Action:thread isAttachmentDownloaded:NO hasCaption:YES], - [self fakeIncomingMp4Action:thread isAttachmentDownloaded:YES hasCaption:YES], - ]]; - if (includeLabels) { - [actions - addObject:[self fakeIncomingTextMessageAction:thread text:@"⚠️ Incoming Compact Landscape Png ⚠️"]]; - } - [actions addObjectsFromArray:@[ - [self fakeIncomingCompactLandscapePngAction:thread isAttachmentDownloaded:NO hasCaption:NO], - [self fakeIncomingCompactLandscapePngAction:thread isAttachmentDownloaded:YES hasCaption:NO], - [self fakeIncomingCompactLandscapePngAction:thread isAttachmentDownloaded:NO hasCaption:YES], - [self fakeIncomingCompactLandscapePngAction:thread isAttachmentDownloaded:YES hasCaption:YES], - ]]; - if (includeLabels) { - [actions - addObject:[self fakeIncomingTextMessageAction:thread text:@"⚠️ Incoming Compact Portrait Png ⚠️"]]; - } - [actions addObjectsFromArray:@[ - [self fakeIncomingCompactPortraitPngAction:thread isAttachmentDownloaded:NO hasCaption:NO], - [self fakeIncomingCompactPortraitPngAction:thread isAttachmentDownloaded:YES hasCaption:NO], - [self fakeIncomingCompactPortraitPngAction:thread isAttachmentDownloaded:NO hasCaption:YES], - [self fakeIncomingCompactPortraitPngAction:thread isAttachmentDownloaded:YES hasCaption:YES], - ]]; - if (includeLabels) { - [actions - addObject:[self fakeIncomingTextMessageAction:thread text:@"⚠️ Incoming Wide Landscape Png ⚠️"]]; - } - [actions addObjectsFromArray:@[ - [self fakeIncomingWideLandscapePngAction:thread isAttachmentDownloaded:NO hasCaption:NO], - [self fakeIncomingWideLandscapePngAction:thread isAttachmentDownloaded:YES hasCaption:NO], - [self fakeIncomingWideLandscapePngAction:thread isAttachmentDownloaded:NO hasCaption:YES], - [self fakeIncomingWideLandscapePngAction:thread isAttachmentDownloaded:YES hasCaption:YES], - ]]; - if (includeLabels) { - [actions - addObject:[self fakeIncomingTextMessageAction:thread text:@"⚠️ Incoming Tall Portrait Png ⚠️"]]; - } - [actions addObjectsFromArray:@[ - [self fakeIncomingTallPortraitPngAction:thread isAttachmentDownloaded:NO hasCaption:NO], - [self fakeIncomingTallPortraitPngAction:thread isAttachmentDownloaded:YES hasCaption:NO], - [self fakeIncomingTallPortraitPngAction:thread isAttachmentDownloaded:NO hasCaption:YES], - [self fakeIncomingTallPortraitPngAction:thread isAttachmentDownloaded:YES hasCaption:YES], - ]]; - if (includeLabels) { - [actions addObject:[self fakeIncomingTextMessageAction:thread text:@"⚠️ Incoming Large Png ⚠️"]]; - } - [actions addObjectsFromArray:@[ - [self fakeIncomingLargePngAction:thread isAttachmentDownloaded:YES hasCaption:NO], - [self fakeIncomingLargePngAction:thread isAttachmentDownloaded:YES hasCaption:YES], - ]]; - if (includeLabels) { - [actions addObject:[self fakeIncomingTextMessageAction:thread text:@"⚠️ Incoming Tiny Png ⚠️"]]; - } - [actions addObjectsFromArray:@[ - [self fakeIncomingTinyPngAction:thread isAttachmentDownloaded:YES hasCaption:NO], - [self fakeIncomingTinyPngAction:thread isAttachmentDownloaded:YES hasCaption:YES], - ]]; - if (includeLabels) { - [actions - addObject:[self fakeIncomingTextMessageAction:thread text:@"⚠️ Incoming Reserved Color Png ⚠️"]]; - } - [actions addObjectsFromArray:@[ - [self fakeIncomingPngAction:thread - actionLabel:@"Fake Incoming White Png" - imageSize:CGSizeMake(200.f, 200.f) - backgroundColor:[UIColor whiteColor] - textColor:[UIColor ows_signalBrandBlueColor] - imageLabel:@"W" - isAttachmentDownloaded:YES - hasCaption:YES], - [self fakeIncomingPngAction:thread - actionLabel:@"Fake Incoming White Png" - imageSize:CGSizeMake(200.f, 200.f) - backgroundColor:[UIColor whiteColor] - textColor:[UIColor ows_signalBrandBlueColor] - imageLabel:@"W" - isAttachmentDownloaded:NO - hasCaption:YES], - [self fakeIncomingPngAction:thread - actionLabel:@"Fake Incoming 'Incoming' Png" - imageSize:CGSizeMake(200.f, 200.f) - backgroundColor:[conversationStyle conversationColor].primaryColor - textColor:[UIColor whiteColor] - imageLabel:@"W" - isAttachmentDownloaded:YES - hasCaption:YES], - [self fakeIncomingPngAction:thread - actionLabel:@"Fake Incoming 'Incoming' Png" - imageSize:CGSizeMake(200.f, 200.f) - backgroundColor:[conversationStyle conversationColor].shadeColor - textColor:[UIColor whiteColor] - imageLabel:@"W" - isAttachmentDownloaded:YES - hasCaption:YES], - [self fakeIncomingPngAction:thread - actionLabel:@"Fake Incoming 'Incoming' Png" - imageSize:CGSizeMake(200.f, 200.f) - backgroundColor:[conversationStyle conversationColor].primaryColor - textColor:[UIColor whiteColor] - imageLabel:@"W" - isAttachmentDownloaded:NO - hasCaption:YES], - [self fakeIncomingPngAction:thread - actionLabel:@"Fake Incoming 'Incoming' Png" - imageSize:CGSizeMake(200.f, 200.f) - backgroundColor:[conversationStyle conversationColor].shadeColor - textColor:[UIColor whiteColor] - imageLabel:@"W" - isAttachmentDownloaded:NO - hasCaption:YES], - ]]; - if (includeLabels) { - [actions addObject:[self fakeIncomingTextMessageAction:thread text:@"⚠️ Incoming Tiny Pdf ⚠️"]]; - } - [actions addObjectsFromArray:@[ - [self fakeIncomingTinyPdfAction:thread isAttachmentDownloaded:NO hasCaption:NO], - [self fakeIncomingTinyPdfAction:thread isAttachmentDownloaded:YES hasCaption:NO], - [self fakeIncomingTinyPdfAction:thread isAttachmentDownloaded:NO hasCaption:YES], - [self fakeIncomingTinyPdfAction:thread isAttachmentDownloaded:YES hasCaption:YES], - ]]; - if (includeLabels) { - [actions addObject:[self fakeIncomingTextMessageAction:thread text:@"⚠️ Incoming Large Pdf ⚠️"]]; - } - [actions addObjectsFromArray:@[ - [self fakeIncomingLargePdfAction:thread isAttachmentDownloaded:YES hasCaption:NO], - ]]; - if (includeLabels) { - [actions addObject:[self fakeIncomingTextMessageAction:thread text:@"⚠️ Incoming Missing Png ⚠️"]]; - } - [actions addObjectsFromArray:@[ - [self fakeIncomingMissingPngAction:thread isAttachmentDownloaded:YES hasCaption:NO], - [self fakeIncomingMissingPngAction:thread isAttachmentDownloaded:YES hasCaption:YES], - ]]; - if (includeLabels) { - [actions addObject:[self fakeIncomingTextMessageAction:thread text:@"⚠️ Incoming Missing Pdf ⚠️"]]; - } - [actions addObjectsFromArray:@[ - [self fakeIncomingMissingPdfAction:thread isAttachmentDownloaded:YES hasCaption:NO], - [self fakeIncomingMissingPdfAction:thread isAttachmentDownloaded:YES hasCaption:YES], - ]]; - if (includeLabels) { - [actions addObject:[self fakeIncomingTextMessageAction:thread text:@"⚠️ Incoming Oversize Text ⚠️"]]; - } - [actions addObjectsFromArray:@[ - [self fakeIncomingOversizeTextAction:thread isAttachmentDownloaded:NO hasCaption:NO], - [self fakeIncomingOversizeTextAction:thread isAttachmentDownloaded:YES hasCaption:NO], - ]]; - return actions; -} - -+ (DebugUIMessagesAction *)fakeAllMediaAction:(TSThread *)thread -{ - OWSAssertDebug(thread); - - return [DebugUIMessagesGroupAction allGroupActionWithLabel:@"All Fake Media" - subactions:[self allFakeMediaActions:thread includeLabels:YES]]; -} - -+ (DebugUIMessagesAction *)fakeRandomMediaAction:(TSThread *)thread -{ - OWSAssertDebug(thread); - - return [DebugUIMessagesGroupAction randomGroupActionWithLabel:@"Random Fake Media" - subactions:[self allFakeMediaActions:thread includeLabels:NO]]; -} - -#pragma mark - Send Text Messages - -+ (DebugUIMessagesAction *)sendShortTextMessageAction:(TSThread *)thread -{ - OWSAssertDebug(thread); - - return [DebugUIMessagesSingleAction actionWithLabel:@"Send Short Text Message" - staggeredActionBlock:^(NSUInteger index, - YapDatabaseReadWriteTransaction *transaction, - ActionSuccessBlock success, - ActionFailureBlock failure) { - dispatch_async(dispatch_get_main_queue(), ^{ - [self sendTextMessageInThread:thread counter:index]; - }); - }]; -} - -+ (DebugUIMessagesAction *)sendOversizeTextMessageAction:(TSThread *)thread -{ - OWSAssertDebug(thread); - - return [DebugUIMessagesSingleAction actionWithLabel:@"Send Oversize Text Message" - staggeredActionBlock:^(NSUInteger index, - YapDatabaseReadWriteTransaction *transaction, - ActionSuccessBlock success, - ActionFailureBlock failure) { - dispatch_async(dispatch_get_main_queue(), ^{ - [self sendOversizeTextMessage:thread]; - }); - }]; -} - -+ (DebugUIMessagesAction *)sendMessageVariationsAction:(TSThread *)thread -{ - OWSAssertDebug(thread); - - NSArray *actions = @[ - [self sendShortTextMessageAction:thread], - [self sendOversizeTextMessageAction:thread], - ]; - - return [DebugUIMessagesGroupAction allGroupActionWithLabel:@"Send Conversation Cell Variations" subactions:actions]; -} - -#pragma mark - Fake Text Messages - -+ (DebugUIMessagesAction *)fakeShortIncomingTextMessageAction:(TSThread *)thread -{ - OWSAssertDebug(thread); - - return [DebugUIMessagesSingleAction - actionWithLabel:@"Fake Short Incoming Text Message" - unstaggeredActionBlock:^(NSUInteger index, YapDatabaseReadWriteTransaction *transaction) { - NSString *messageBody = - [[@(index).stringValue stringByAppendingString:@" "] stringByAppendingString:[self randomText]]; - [self createFakeIncomingMessage:thread - messageBody:messageBody - fakeAssetLoader:nil - isAttachmentDownloaded:NO - quotedMessage:nil - transaction:transaction]; - }]; -} - -+ (SignalAttachment *)signalAttachmentForFilePath:(NSString *)filePath -{ - OWSAssertDebug(filePath); - - NSString *filename = [filePath lastPathComponent]; - NSString *utiType = [MIMETypeUtil utiTypeForFileExtension:filename.pathExtension]; - DataSource *_Nullable dataSource = [DataSourcePath dataSourceWithFilePath:filePath shouldDeleteOnDeallocation:NO]; - [dataSource setSourceFilename:filename]; - SignalAttachment *attachment = - [SignalAttachment attachmentWithDataSource:dataSource dataUTI:utiType imageQuality:TSImageQualityOriginal]; - if (arc4random_uniform(100) > 50) { - attachment.captionText = [self randomCaptionText]; - } - - OWSAssertDebug(attachment); - if ([attachment hasError]) { - OWSLogError(@"attachment[%@]: %@", [attachment sourceFilename], [attachment errorName]); - [DDLog flushLog]; - } - OWSAssertDebug(![attachment hasError]); - return attachment; -} - -+ (void)sendAttachment:(nullable SignalAttachment *)attachment - thread:(TSThread *)thread - messageBody:(nullable NSString *)messageBody -{ - [self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) { - NSArray *attachments = @[]; - if (attachment != nil) { - attachments = @[ attachment ]; - } - [ThreadUtil enqueueMessageWithText:messageBody - mediaAttachments:attachments - inThread:thread - quotedReplyModel:nil - linkPreviewDraft:nil - transaction:transaction]; - }]; -} - - -+ (DebugUIMessagesAction *)fakeIncomingTextMessageAction:(TSThread *)thread text:(NSString *)text -{ - OWSAssertDebug(thread); - - return [DebugUIMessagesSingleAction - actionWithLabel:[NSString stringWithFormat:@"Fake Incoming Text Message (%@)", text] - unstaggeredActionBlock:^(NSUInteger index, YapDatabaseReadWriteTransaction *transaction) { - NSString *messageBody = [[@(index).stringValue stringByAppendingString:@" "] stringByAppendingString:text]; - [self createFakeIncomingMessage:thread - messageBody:messageBody - fakeAssetLoader:nil - isAttachmentDownloaded:NO - quotedMessage:nil - transaction:transaction]; - }]; -} - -+ (DebugUIMessagesAction *)fakeOutgoingTextMessageAction:(TSThread *)thread - messageState:(TSOutgoingMessageState)messageState - text:(NSString *)text -{ - OWSAssertDebug(thread); - - return [DebugUIMessagesSingleAction - actionWithLabel:[NSString stringWithFormat:@"Fake Incoming Text Message (%@)", text] - unstaggeredActionBlock:^(NSUInteger index, YapDatabaseReadWriteTransaction *transaction) { - NSString *messageBody = [[@(index).stringValue stringByAppendingString:@" "] stringByAppendingString:text]; - [self createFakeOutgoingMessage:thread - messageBody:messageBody - fakeAssetLoader:nil - messageState:messageState - isDelivered:NO - isRead:NO - quotedMessage:nil - contactShare:nil - linkPreview:nil - transaction:transaction]; - }]; -} - -+ (DebugUIMessagesAction *)fakeShortOutgoingTextMessageAction:(TSThread *)thread - messageState:(TSOutgoingMessageState)messageState -{ - return [self fakeShortOutgoingTextMessageAction:thread messageState:messageState isDelivered:NO isRead:NO]; -} - -+ (DebugUIMessagesAction *)fakeShortOutgoingTextMessageAction:(TSThread *)thread - messageState:(TSOutgoingMessageState)messageState - isDelivered:(BOOL)isDelivered - isRead:(BOOL)isRead -{ - return [self fakeShortOutgoingTextMessageAction:(TSThread *)thread - text:[self randomText] - messageState:messageState - isDelivered:isDelivered - isRead:isRead]; -} - -+ (DebugUIMessagesAction *)fakeShortOutgoingTextMessageAction:(TSThread *)thread - text:(NSString *)text - messageState:(TSOutgoingMessageState)messageState - isDelivered:(BOOL)isDelivered - isRead:(BOOL)isRead -{ - OWSAssertDebug(thread); - - NSString *label = @"Fake Short Incoming Text Message"; - label = [label stringByAppendingString:[self actionLabelForHasCaption:YES - outgoingMessageState:messageState - isDelivered:isDelivered - isRead:isRead]]; - - return [DebugUIMessagesSingleAction - actionWithLabel:label - unstaggeredActionBlock:^(NSUInteger index, YapDatabaseReadWriteTransaction *transaction) { - NSString *messageBody = [[@(index).stringValue stringByAppendingString:@" "] stringByAppendingString:text]; - [self createFakeOutgoingMessage:thread - messageBody:messageBody - fakeAssetLoader:nil - messageState:messageState - isDelivered:isDelivered - isRead:isRead - quotedMessage:nil - contactShare:nil - linkPreview:nil - transaction:transaction]; - }]; -} - -+ (NSArray *)allFakeTextActions:(TSThread *)thread includeLabels:(BOOL)includeLabels -{ - OWSAssertDebug(thread); - - NSArray *messageBodies = @[ - @"Hi", - @"1️⃣", - @"1️⃣2️⃣", - @"1️⃣2️⃣3️⃣", - @"落", - @"﷽", - ]; - - NSMutableArray *actions = [NSMutableArray new]; - - if (includeLabels) { - [actions addObject:[self fakeIncomingTextMessageAction:thread text:@"⚠️ Incoming Message Bodies ⚠️"]]; - } - [actions addObject:[self fakeShortIncomingTextMessageAction:thread]]; - for (NSString *messageBody in messageBodies) { - [actions addObject:[self fakeIncomingTextMessageAction:thread text:messageBody]]; - } - - if (includeLabels) { - [actions addObject:[self fakeOutgoingTextMessageAction:thread - messageState:TSOutgoingMessageStateSent - text:@"⚠️ Outgoing Statuses ⚠️"]]; - } - [actions addObjectsFromArray:@[ - [self fakeShortOutgoingTextMessageAction:thread messageState:TSOutgoingMessageStateFailed], - [self fakeShortOutgoingTextMessageAction:thread messageState:TSOutgoingMessageStateSending], - [self fakeShortOutgoingTextMessageAction:thread messageState:TSOutgoingMessageStateSent], - [self fakeShortOutgoingTextMessageAction:thread - messageState:TSOutgoingMessageStateSent - isDelivered:YES - isRead:NO], - [self fakeShortOutgoingTextMessageAction:thread - messageState:TSOutgoingMessageStateSent - isDelivered:YES - isRead:YES], - ]]; - - if (includeLabels) { - [actions addObject:[self fakeOutgoingTextMessageAction:thread - messageState:TSOutgoingMessageStateSent - text:@"⚠️ Outgoing Message Bodies ⚠️"]]; - } - for (NSString *messageBody in messageBodies) { - [actions addObject:[self fakeOutgoingTextMessageAction:thread - messageState:TSOutgoingMessageStateSent - text:messageBody]]; - } - return actions; -} - -+ (DebugUIMessagesAction *)fakeAllTextAction:(TSThread *)thread -{ - OWSAssertDebug(thread); - - return [DebugUIMessagesGroupAction allGroupActionWithLabel:@"All Fake Text" - subactions:[self allFakeTextActions:thread includeLabels:YES]]; -} - -+ (DebugUIMessagesAction *)fakeRandomTextAction:(TSThread *)thread -{ - OWSAssertDebug(thread); - - return [DebugUIMessagesGroupAction randomGroupActionWithLabel:@"Random Fake Text" - subactions:[self allFakeTextActions:thread includeLabels:NO]]; -} - -#pragma mark - Fake Quoted Replies - -+ (DebugUIMessagesAction *) - fakeQuotedReplyAction:(TSThread *)thread - quotedMessageLabel:(NSString *)quotedMessageLabel - isQuotedMessageIncoming:(BOOL)isQuotedMessageIncoming - // Optional. At least one of quotedMessageBody and quotedMessageAssetLoader should be non-nil. - quotedMessageBody:(nullable NSString *)quotedMessageBody - // Optional. At least one of quotedMessageBody and quotedMessageAssetLoader should be non-nil. - quotedMessageAssetLoader:(nullable DebugUIMessagesAssetLoader *)quotedMessageAssetLoader - replyLabel:(NSString *)replyLabel - isReplyIncoming:(BOOL)isReplyIncoming - replyMessageBody:(nullable NSString *)replyMessageBody - replyAssetLoader:(nullable DebugUIMessagesAssetLoader *)replyAssetLoader - // Only applies if !isReplyIncoming. - replyMessageState:(TSOutgoingMessageState)replyMessageState -{ - OWSAssertDebug(thread); - - // Used fixed values for properties that shouldn't matter much. - BOOL quotedMessageIsDelivered = NO; - BOOL quotedMessageIsRead = NO; - TSOutgoingMessageState quotedMessageMessageState = TSOutgoingMessageStateSent; - BOOL replyIsDelivered = NO; - BOOL replyIsRead = NO; - - // Seamlessly convert oversize text messages to oversize text attachments. - if ([quotedMessageBody lengthOfBytesUsingEncoding:NSUTF8StringEncoding] >= kOversizeTextMessageSizeThreshold) { - OWSAssertDebug(!quotedMessageAssetLoader); - quotedMessageAssetLoader = [DebugUIMessagesAssetLoader oversizeTextInstanceWithText:quotedMessageBody]; - quotedMessageBody = nil; - } - if (replyMessageBody && - [replyMessageBody lengthOfBytesUsingEncoding:NSUTF8StringEncoding] >= kOversizeTextMessageSizeThreshold) { - OWSAssertDebug(!replyAssetLoader); - replyAssetLoader = [DebugUIMessagesAssetLoader oversizeTextInstanceWithText:replyMessageBody]; - replyMessageBody = nil; - } - - NSMutableString *label = [NSMutableString new]; - [label appendString:@"Quoted Reply ("]; - [label appendString:replyLabel]; - if (isReplyIncoming) { - } else { - [label appendString:[self actionLabelForHasCaption:NO - outgoingMessageState:replyMessageState - isDelivered:replyIsDelivered - isRead:replyIsRead]]; - } - [label appendString:@") to ("]; - [label appendString:quotedMessageLabel]; - if (quotedMessageAssetLoader) { - [label appendFormat:@" %@", quotedMessageAssetLoader.labelEmoji]; - } - if (isQuotedMessageIncoming) { - } else { - [label appendString:[self actionLabelForHasCaption:quotedMessageBody.length > 0 - outgoingMessageState:quotedMessageMessageState - isDelivered:quotedMessageIsDelivered - isRead:quotedMessageIsRead]]; - } - [label appendString:@")"]; - - NSMutableArray *prepareBlocks = [NSMutableArray new]; - if (quotedMessageAssetLoader.prepareBlock) { - [prepareBlocks addObject:quotedMessageAssetLoader.prepareBlock]; - } - if (replyAssetLoader.prepareBlock) { - [prepareBlocks addObject:replyAssetLoader.prepareBlock]; - } - - // We don't need to configure ConversationStyle's view width in this case. - ConversationStyle *conversationStyle = [[ConversationStyle alloc] initWithThread:thread]; - - return [DebugUIMessagesSingleAction - actionWithLabel:label - unstaggeredActionBlock:^(NSUInteger index, YapDatabaseReadWriteTransaction *transaction) { - NSString *_Nullable quotedMessageBodyWIndex - = (quotedMessageBody ? [NSString stringWithFormat:@"%zd %@", index, quotedMessageBody] : nil); - TSQuotedMessage *_Nullable quotedMessage = nil; - if (isQuotedMessageIncoming) { - TSIncomingMessage *_Nullable messageToQuote = nil; - messageToQuote = [self createFakeIncomingMessage:thread - messageBody:quotedMessageBodyWIndex - fakeAssetLoader:quotedMessageAssetLoader - isAttachmentDownloaded:YES - quotedMessage:nil - transaction:transaction]; - OWSAssertDebug(messageToQuote); - OWSLogVerbose(@"%@", label); - [DDLog flushLog]; - id viewItem = - [[ConversationInteractionViewItem alloc] initWithInteraction:messageToQuote - isGroupThread:thread.isGroupThread - isRSSFeed:NO - transaction:transaction - conversationStyle:conversationStyle]; - quotedMessage = [ - [OWSQuotedReplyModel quotedReplyForSendingWithConversationViewItem:viewItem threadId:viewItem.interaction.uniqueThreadId transaction:transaction] - buildQuotedMessageForSending]; - } else { - TSOutgoingMessage *_Nullable messageToQuote = [self createFakeOutgoingMessage:thread - messageBody:quotedMessageBodyWIndex - fakeAssetLoader:quotedMessageAssetLoader - messageState:quotedMessageMessageState - isDelivered:quotedMessageIsDelivered - isRead:quotedMessageIsRead - quotedMessage:nil - contactShare:nil - linkPreview:nil - transaction:transaction]; - OWSAssertDebug(messageToQuote); - - id viewItem = - [[ConversationInteractionViewItem alloc] initWithInteraction:messageToQuote - isGroupThread:thread.isGroupThread - isRSSFeed:NO - transaction:transaction - conversationStyle:conversationStyle]; - quotedMessage = [[OWSQuotedReplyModel quotedReplyForSendingWithConversationViewItem:viewItem threadId:viewItem.interaction.uniqueThreadId transaction:transaction] - buildQuotedMessageForSending]; - } - OWSAssertDebug(quotedMessage); - - NSString *_Nullable replyMessageBodyWIndex - = (replyMessageBody ? [NSString stringWithFormat:@"%zd %@", index, replyMessageBody] : nil); - if (isReplyIncoming) { - [self createFakeIncomingMessage:thread - messageBody:replyMessageBodyWIndex - fakeAssetLoader:replyAssetLoader - isAttachmentDownloaded:NO - quotedMessage:quotedMessage - transaction:transaction]; - } else { - [self createFakeOutgoingMessage:thread - messageBody:replyMessageBodyWIndex - fakeAssetLoader:replyAssetLoader - messageState:replyMessageState - isDelivered:replyIsDelivered - isRead:replyIsRead - quotedMessage:quotedMessage - contactShare:nil - linkPreview:nil - transaction:transaction]; - } - } - prepareBlock:[self groupPrepareBlockWithPrepareBlocks:prepareBlocks]]; -} - -// Recursively perform a group of "prepare blocks" in sequence, aborting -// if any fail. -+ (ActionPrepareBlock)groupPrepareBlockWithPrepareBlocks:(NSArray *)prepareBlocks -{ - return ^(ActionSuccessBlock success, ActionFailureBlock failure) { - [self groupPrepareBlockStepWithPrepareBlocks:[prepareBlocks mutableCopy] success:success failure:failure]; - }; -} - -+ (void)groupPrepareBlockStepWithPrepareBlocks:(NSMutableArray *)prepareBlocks - success:(ActionSuccessBlock)success - failure:(ActionFailureBlock)failure -{ - if (prepareBlocks.count < 1) { - success(); - return; - } - ActionPrepareBlock nextPrepareBlock = [prepareBlocks lastObject]; - [prepareBlocks removeLastObject]; - - nextPrepareBlock( - ^{ - [self groupPrepareBlockStepWithPrepareBlocks:prepareBlocks success:success failure:failure]; - }, - failure); -} - -+ (NSArray *)allFakeQuotedReplyActions:(TSThread *)thread includeLabels:(BOOL)includeLabels -{ - OWSAssertDebug(thread); - - NSString *shortText = @"Lorem ipsum"; - NSString *mediumText = @"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, " - @"consectetur adipiscing elit."; - NSString *longText = [self randomOversizeText]; - - NSMutableArray *actions = [NSMutableArray new]; - - if (includeLabels) { - [actions addObject:[self fakeIncomingTextMessageAction:thread - text:@"⚠️ Quoted Replies (Message Lengths) ⚠️"]]; - } - [actions addObjectsFromArray:@[ - [self fakeQuotedReplyAction:thread - quotedMessageLabel:@"Short Text" - isQuotedMessageIncoming:NO - quotedMessageBody:shortText - quotedMessageAssetLoader:nil - replyLabel:@"Short Text" - isReplyIncoming:NO - replyMessageBody:shortText - replyAssetLoader:nil - replyMessageState:TSOutgoingMessageStateSent], - - [self fakeQuotedReplyAction:thread - quotedMessageLabel:@"Short Text" - isQuotedMessageIncoming:NO - quotedMessageBody:shortText - quotedMessageAssetLoader:nil - replyLabel:@"Medium Text" - isReplyIncoming:NO - replyMessageBody:mediumText - replyAssetLoader:nil - replyMessageState:TSOutgoingMessageStateSent], - - [self fakeQuotedReplyAction:thread - quotedMessageLabel:@"Medium Text" - isQuotedMessageIncoming:NO - quotedMessageBody:mediumText - quotedMessageAssetLoader:nil - replyLabel:@"Short Text" - isReplyIncoming:NO - replyMessageBody:shortText - replyAssetLoader:nil - replyMessageState:TSOutgoingMessageStateSent], - - [self fakeQuotedReplyAction:thread - quotedMessageLabel:@"Medium Text" - isQuotedMessageIncoming:NO - quotedMessageBody:mediumText - quotedMessageAssetLoader:nil - replyLabel:@"Medium Text" - isReplyIncoming:NO - replyMessageBody:mediumText - replyAssetLoader:nil - replyMessageState:TSOutgoingMessageStateSent], - - [self fakeQuotedReplyAction:thread - quotedMessageLabel:@"Long Text" - isQuotedMessageIncoming:NO - quotedMessageBody:longText - quotedMessageAssetLoader:nil - replyLabel:@"Long Text" - isReplyIncoming:NO - replyMessageBody:longText - replyAssetLoader:nil - replyMessageState:TSOutgoingMessageStateSent], - ]]; - - if (includeLabels) { - [actions addObject:[self fakeIncomingTextMessageAction:thread - text:@"⚠️ Quoted Replies (Attachment Types) ⚠️"]]; - } - [actions addObjectsFromArray:@[ - [self fakeQuotedReplyAction:thread - quotedMessageLabel:@"Jpg" - isQuotedMessageIncoming:NO - quotedMessageBody:nil - quotedMessageAssetLoader:[DebugUIMessagesAssetLoader jpegInstance] - replyLabel:@"Short Text" - isReplyIncoming:NO - replyMessageBody:shortText - replyAssetLoader:nil - replyMessageState:TSOutgoingMessageStateSent], - - [self fakeQuotedReplyAction:thread - quotedMessageLabel:@"Jpg" - isQuotedMessageIncoming:NO - quotedMessageBody:shortText - quotedMessageAssetLoader:[DebugUIMessagesAssetLoader jpegInstance] - replyLabel:@"Short Text" - isReplyIncoming:NO - replyMessageBody:shortText - replyAssetLoader:nil - replyMessageState:TSOutgoingMessageStateSent], - - [self fakeQuotedReplyAction:thread - quotedMessageLabel:@"Mp3" - isQuotedMessageIncoming:NO - quotedMessageBody:nil - quotedMessageAssetLoader:[DebugUIMessagesAssetLoader mp3Instance] - replyLabel:@"Short Text" - isReplyIncoming:NO - replyMessageBody:shortText - replyAssetLoader:nil - replyMessageState:TSOutgoingMessageStateSent], - - [self fakeQuotedReplyAction:thread - quotedMessageLabel:@"Mp3" - isQuotedMessageIncoming:NO - quotedMessageBody:shortText - quotedMessageAssetLoader:[DebugUIMessagesAssetLoader mp3Instance] - replyLabel:@"Short Text" - isReplyIncoming:NO - replyMessageBody:shortText - replyAssetLoader:nil - replyMessageState:TSOutgoingMessageStateSent], - - [self fakeQuotedReplyAction:thread - quotedMessageLabel:@"Mp4" - isQuotedMessageIncoming:NO - quotedMessageBody:nil - quotedMessageAssetLoader:[DebugUIMessagesAssetLoader mp4Instance] - replyLabel:@"Short Text" - isReplyIncoming:NO - replyMessageBody:shortText - replyAssetLoader:nil - replyMessageState:TSOutgoingMessageStateSent], - - [self fakeQuotedReplyAction:thread - quotedMessageLabel:@"Mp4" - isQuotedMessageIncoming:NO - quotedMessageBody:shortText - quotedMessageAssetLoader:[DebugUIMessagesAssetLoader mp4Instance] - replyLabel:@"Short Text" - isReplyIncoming:NO - replyMessageBody:shortText - replyAssetLoader:nil - replyMessageState:TSOutgoingMessageStateSent], - - [self fakeQuotedReplyAction:thread - quotedMessageLabel:@"Gif" - isQuotedMessageIncoming:NO - quotedMessageBody:nil - quotedMessageAssetLoader:[DebugUIMessagesAssetLoader gifInstance] - replyLabel:@"Short Text" - isReplyIncoming:NO - replyMessageBody:shortText - replyAssetLoader:nil - replyMessageState:TSOutgoingMessageStateSent], - - [self fakeQuotedReplyAction:thread - quotedMessageLabel:@"Gif" - isQuotedMessageIncoming:NO - quotedMessageBody:shortText - quotedMessageAssetLoader:[DebugUIMessagesAssetLoader gifInstance] - replyLabel:@"Short Text" - isReplyIncoming:NO - replyMessageBody:shortText - replyAssetLoader:nil - replyMessageState:TSOutgoingMessageStateSent], - - [self fakeQuotedReplyAction:thread - quotedMessageLabel:@"Pdf" - isQuotedMessageIncoming:YES - quotedMessageBody:nil - quotedMessageAssetLoader:[DebugUIMessagesAssetLoader tinyPdfInstance] - replyLabel:@"Short Text" - isReplyIncoming:NO - replyMessageBody:shortText - replyAssetLoader:nil - replyMessageState:TSOutgoingMessageStateSent], - - [self fakeQuotedReplyAction:thread - quotedMessageLabel:@"Missing Pdf" - isQuotedMessageIncoming:YES - quotedMessageBody:nil - quotedMessageAssetLoader:[DebugUIMessagesAssetLoader missingPdfInstance] - replyLabel:@"Short Text" - isReplyIncoming:NO - replyMessageBody:shortText - replyAssetLoader:nil - replyMessageState:TSOutgoingMessageStateSent], - - [self fakeQuotedReplyAction:thread - quotedMessageLabel:@"Tiny Png" - isQuotedMessageIncoming:YES - quotedMessageBody:nil - quotedMessageAssetLoader:[DebugUIMessagesAssetLoader tinyPngInstance] - replyLabel:@"Short Text" - isReplyIncoming:NO - replyMessageBody:shortText - replyAssetLoader:nil - replyMessageState:TSOutgoingMessageStateSent], - - [self fakeQuotedReplyAction:thread - quotedMessageLabel:@"Missing Png" - isQuotedMessageIncoming:YES - quotedMessageBody:nil - quotedMessageAssetLoader:[DebugUIMessagesAssetLoader missingPngInstance] - replyLabel:@"Short Text" - isReplyIncoming:NO - replyMessageBody:shortText - replyAssetLoader:nil - replyMessageState:TSOutgoingMessageStateSent], - ]]; - - if (includeLabels) { - [actions addObject:[self fakeIncomingTextMessageAction:thread - text:@"⚠️ Quoted Replies (Attachment Layout) ⚠️"]]; - } - [actions addObjectsFromArray:@[ - [self fakeQuotedReplyAction:thread - quotedMessageLabel:@"Tall Portrait Png" - isQuotedMessageIncoming:NO - quotedMessageBody:nil - quotedMessageAssetLoader:[DebugUIMessagesAssetLoader tallPortraitPngInstance] - replyLabel:@"Short Text" - isReplyIncoming:NO - replyMessageBody:shortText - replyAssetLoader:nil - replyMessageState:TSOutgoingMessageStateSent], - - [self fakeQuotedReplyAction:thread - quotedMessageLabel:@"Tall Portrait Png" - isQuotedMessageIncoming:NO - quotedMessageBody:nil - quotedMessageAssetLoader:[DebugUIMessagesAssetLoader tallPortraitPngInstance] - replyLabel:@"Medium Text" - isReplyIncoming:NO - replyMessageBody:mediumText - replyAssetLoader:nil - replyMessageState:TSOutgoingMessageStateSent], - - [self fakeQuotedReplyAction:thread - quotedMessageLabel:@"Tall Portrait Png" - isQuotedMessageIncoming:NO - quotedMessageBody:shortText - quotedMessageAssetLoader:[DebugUIMessagesAssetLoader tallPortraitPngInstance] - replyLabel:@"Short Text" - isReplyIncoming:NO - replyMessageBody:shortText - replyAssetLoader:nil - replyMessageState:TSOutgoingMessageStateSent], - - [self fakeQuotedReplyAction:thread - quotedMessageLabel:@"Wide Landscape Png" - isQuotedMessageIncoming:NO - quotedMessageBody:nil - quotedMessageAssetLoader:[DebugUIMessagesAssetLoader wideLandscapePngInstance] - replyLabel:@"Short Text" - isReplyIncoming:NO - replyMessageBody:shortText - replyAssetLoader:nil - replyMessageState:TSOutgoingMessageStateSent], - - [self fakeQuotedReplyAction:thread - quotedMessageLabel:@"Wide Landscape Png" - isQuotedMessageIncoming:NO - quotedMessageBody:nil - quotedMessageAssetLoader:[DebugUIMessagesAssetLoader wideLandscapePngInstance] - replyLabel:@"Medium Text" - isReplyIncoming:NO - replyMessageBody:mediumText - replyAssetLoader:nil - replyMessageState:TSOutgoingMessageStateSent], - - [self fakeQuotedReplyAction:thread - quotedMessageLabel:@"Wide Landscape Png" - isQuotedMessageIncoming:NO - quotedMessageBody:shortText - quotedMessageAssetLoader:[DebugUIMessagesAssetLoader wideLandscapePngInstance] - replyLabel:@"Medium Text" - isReplyIncoming:NO - replyMessageBody:mediumText - replyAssetLoader:nil - replyMessageState:TSOutgoingMessageStateSent], - - [self fakeQuotedReplyAction:thread - quotedMessageLabel:@"Tiny Png" - isQuotedMessageIncoming:YES - quotedMessageBody:nil - quotedMessageAssetLoader:[DebugUIMessagesAssetLoader tinyPngInstance] - replyLabel:@"Short Text" - isReplyIncoming:NO - replyMessageBody:shortText - replyAssetLoader:nil - replyMessageState:TSOutgoingMessageStateSent], - - [self fakeQuotedReplyAction:thread - quotedMessageLabel:@"Tiny Png" - isQuotedMessageIncoming:YES - quotedMessageBody:nil - quotedMessageAssetLoader:[DebugUIMessagesAssetLoader tinyPngInstance] - replyLabel:@"Medium Text" - isReplyIncoming:NO - replyMessageBody:mediumText - replyAssetLoader:nil - replyMessageState:TSOutgoingMessageStateSent], - ]]; - - void (^directionActions)(BOOL, BOOL) = ^(BOOL isQuotedMessageIncoming, BOOL isReplyIncoming) { - [actions addObjectsFromArray:@[ - [self fakeQuotedReplyAction:thread - quotedMessageLabel:@"Short Text" - isQuotedMessageIncoming:isQuotedMessageIncoming - quotedMessageBody:shortText - quotedMessageAssetLoader:nil - replyLabel:@"Short Text" - isReplyIncoming:isReplyIncoming - replyMessageBody:shortText - replyAssetLoader:nil - replyMessageState:TSOutgoingMessageStateSent], - ]]; - }; - - if (includeLabels) { - [actions addObject:[self fakeIncomingTextMessageAction:thread - text:@"⚠️ Quoted Replies (Incoming v. Outgoing) ⚠️"]]; - } - directionActions(NO, NO); - directionActions(YES, NO); - directionActions(NO, YES); - directionActions(YES, YES); - - if (includeLabels) { - [actions addObject:[self fakeIncomingTextMessageAction:thread - text:@"⚠️ Quoted Replies (Message States) ⚠️"]]; - } - [actions addObjectsFromArray:@[ - [self fakeQuotedReplyAction:thread - quotedMessageLabel:@"Jpg" - isQuotedMessageIncoming:YES - quotedMessageBody:nil - quotedMessageAssetLoader:[DebugUIMessagesAssetLoader jpegInstance] - replyLabel:@"Short Text" - isReplyIncoming:NO - replyMessageBody:shortText - replyAssetLoader:nil - replyMessageState:TSOutgoingMessageStateSent], - - [self fakeQuotedReplyAction:thread - quotedMessageLabel:@"Mp3" - isQuotedMessageIncoming:YES - quotedMessageBody:nil - quotedMessageAssetLoader:[DebugUIMessagesAssetLoader mp3Instance] - replyLabel:@"Short Text" - isReplyIncoming:NO - replyMessageBody:shortText - replyAssetLoader:nil - replyMessageState:TSOutgoingMessageStateSent], - - [self fakeQuotedReplyAction:thread - quotedMessageLabel:@"Mp4" - isQuotedMessageIncoming:YES - quotedMessageBody:nil - quotedMessageAssetLoader:[DebugUIMessagesAssetLoader mp4Instance] - replyLabel:@"Short Text" - isReplyIncoming:NO - replyMessageBody:shortText - replyAssetLoader:nil - replyMessageState:TSOutgoingMessageStateSent], - - [self fakeQuotedReplyAction:thread - quotedMessageLabel:@"Gif" - isQuotedMessageIncoming:YES - quotedMessageBody:nil - quotedMessageAssetLoader:[DebugUIMessagesAssetLoader gifInstance] - replyLabel:@"Short Text" - isReplyIncoming:NO - replyMessageBody:shortText - replyAssetLoader:nil - replyMessageState:TSOutgoingMessageStateSent], - - [self fakeQuotedReplyAction:thread - quotedMessageLabel:@"Pdf" - isQuotedMessageIncoming:YES - quotedMessageBody:nil - quotedMessageAssetLoader:[DebugUIMessagesAssetLoader tinyPdfInstance] - replyLabel:@"Short Text" - isReplyIncoming:NO - replyMessageBody:shortText - replyAssetLoader:nil - replyMessageState:TSOutgoingMessageStateSent], - - [self fakeQuotedReplyAction:thread - quotedMessageLabel:@"Missing Pdf" - isQuotedMessageIncoming:YES - quotedMessageBody:nil - quotedMessageAssetLoader:[DebugUIMessagesAssetLoader missingPdfInstance] - replyLabel:@"Short Text" - isReplyIncoming:NO - replyMessageBody:shortText - replyAssetLoader:nil - replyMessageState:TSOutgoingMessageStateSent], - - [self fakeQuotedReplyAction:thread - quotedMessageLabel:@"Tiny Png" - isQuotedMessageIncoming:YES - quotedMessageBody:nil - quotedMessageAssetLoader:[DebugUIMessagesAssetLoader tinyPngInstance] - replyLabel:@"Short Text" - isReplyIncoming:NO - replyMessageBody:shortText - replyAssetLoader:nil - replyMessageState:TSOutgoingMessageStateSent], - - [self fakeQuotedReplyAction:thread - quotedMessageLabel:@"Missing Png" - isQuotedMessageIncoming:YES - quotedMessageBody:nil - quotedMessageAssetLoader:[DebugUIMessagesAssetLoader missingPngInstance] - replyLabel:@"Short Text" - isReplyIncoming:NO - replyMessageBody:shortText - replyAssetLoader:nil - replyMessageState:TSOutgoingMessageStateSent], - - [self fakeQuotedReplyAction:thread - quotedMessageLabel:@"Short Text" - isQuotedMessageIncoming:NO - quotedMessageBody:shortText - quotedMessageAssetLoader:nil - replyLabel:@"Short Text" - isReplyIncoming:NO - replyMessageBody:shortText - replyAssetLoader:nil - replyMessageState:TSOutgoingMessageStateSending], - - [self fakeQuotedReplyAction:thread - quotedMessageLabel:@"Short Text" - isQuotedMessageIncoming:NO - quotedMessageBody:shortText - quotedMessageAssetLoader:nil - replyLabel:@"Short Text" - isReplyIncoming:NO - replyMessageBody:shortText - replyAssetLoader:nil - replyMessageState:TSOutgoingMessageStateSent], - - [self fakeQuotedReplyAction:thread - quotedMessageLabel:@"Short Text" - isQuotedMessageIncoming:NO - quotedMessageBody:shortText - quotedMessageAssetLoader:nil - replyLabel:@"Short Text" - isReplyIncoming:NO - replyMessageBody:shortText - replyAssetLoader:nil - replyMessageState:TSOutgoingMessageStateFailed], - ]]; - - - if (includeLabels) { - [actions addObject:[self fakeIncomingTextMessageAction:thread - text:@"⚠️ Quoted Replies (Reply W. Attachment) ⚠️"]]; - } - [actions addObjectsFromArray:@[ - // Png + Text -> Png + Text - [self fakeQuotedReplyAction:thread - quotedMessageLabel:@"Tall Portrait Png" - isQuotedMessageIncoming:NO - quotedMessageBody:shortText - quotedMessageAssetLoader:[DebugUIMessagesAssetLoader tallPortraitPngInstance] - replyLabel:@"Tall Portrait Png" - isReplyIncoming:NO - replyMessageBody:shortText - replyAssetLoader:[DebugUIMessagesAssetLoader tallPortraitPngInstance] - replyMessageState:TSOutgoingMessageStateSent], - - // Text -> Png + Text - [self fakeQuotedReplyAction:thread - quotedMessageLabel:@"Short Text" - isQuotedMessageIncoming:NO - quotedMessageBody:shortText - quotedMessageAssetLoader:nil - replyLabel:@"Tall Portrait Png" - isReplyIncoming:NO - replyMessageBody:shortText - replyAssetLoader:nil - replyMessageState:TSOutgoingMessageStateSent], - - // Text -> Png - [self fakeQuotedReplyAction:thread - quotedMessageLabel:@"Short Text" - isQuotedMessageIncoming:NO - quotedMessageBody:shortText - quotedMessageAssetLoader:nil - replyLabel:@"Tall Portrait Png" - isReplyIncoming:NO - replyMessageBody:nil - replyAssetLoader:[DebugUIMessagesAssetLoader tallPortraitPngInstance] - replyMessageState:TSOutgoingMessageStateSent], - - // Png -> Png + Text - [self fakeQuotedReplyAction:thread - quotedMessageLabel:@"Short Text" - isQuotedMessageIncoming:NO - quotedMessageBody:shortText - quotedMessageAssetLoader:nil - replyLabel:@"Tall Portrait Png" - isReplyIncoming:NO - replyMessageBody:shortText - replyAssetLoader:[DebugUIMessagesAssetLoader tallPortraitPngInstance] - replyMessageState:TSOutgoingMessageStateSent], - - // Png -> Portrait Png + Text - [self fakeQuotedReplyAction:thread - quotedMessageLabel:@"Short Text" - isQuotedMessageIncoming:NO - quotedMessageBody:shortText - quotedMessageAssetLoader:nil - replyLabel:@"Tall Portrait Png" - isReplyIncoming:NO - replyMessageBody:shortText - replyAssetLoader:[DebugUIMessagesAssetLoader tallPortraitPngInstance] - replyMessageState:TSOutgoingMessageStateSent], - - // Png -> Landscape Png + Text - [self fakeQuotedReplyAction:thread - quotedMessageLabel:@"Short Text" - isQuotedMessageIncoming:NO - quotedMessageBody:shortText - quotedMessageAssetLoader:nil - replyLabel:@"Wide Landscape Png" - isReplyIncoming:NO - replyMessageBody:shortText - replyAssetLoader:[DebugUIMessagesAssetLoader wideLandscapePngInstance] - replyMessageState:TSOutgoingMessageStateSent], - - - // Png -> Landscape Png + Text - [self fakeQuotedReplyAction:thread - quotedMessageLabel:@"Short Text" - isQuotedMessageIncoming:NO - quotedMessageBody:shortText - quotedMessageAssetLoader:nil - replyLabel:@"Wide Landscape Png + Short Text" - isReplyIncoming:NO - replyMessageBody:shortText - replyAssetLoader:[DebugUIMessagesAssetLoader wideLandscapePngInstance] - replyMessageState:TSOutgoingMessageStateSent], - - // Png -> Landscape Png + Text - [self fakeQuotedReplyAction:thread - quotedMessageLabel:@"Short Text" - isQuotedMessageIncoming:NO - quotedMessageBody:shortText - quotedMessageAssetLoader:nil - replyLabel:@"Wide Landscape Png + Short Text" - isReplyIncoming:NO - replyMessageBody:shortText - replyAssetLoader:[DebugUIMessagesAssetLoader wideLandscapePngInstance] - replyMessageState:TSOutgoingMessageStateSent], - - // Png -> Landscape Png + Text - [self fakeQuotedReplyAction:thread - quotedMessageLabel:@"Short Text" - isQuotedMessageIncoming:NO - quotedMessageBody:shortText - quotedMessageAssetLoader:nil - replyLabel:@"Wide Landscape Png + Medium Text" - isReplyIncoming:NO - replyMessageBody:mediumText - replyAssetLoader:[DebugUIMessagesAssetLoader wideLandscapePngInstance] - replyMessageState:TSOutgoingMessageStateSent], - - // Png -> Landscape Png + Text - [self fakeQuotedReplyAction:thread - quotedMessageLabel:@"Short Text" - isQuotedMessageIncoming:NO - quotedMessageBody:shortText - quotedMessageAssetLoader:nil - replyLabel:@"Wide Landscape Png + Medium Text" - isReplyIncoming:NO - replyMessageBody:mediumText - replyAssetLoader:[DebugUIMessagesAssetLoader wideLandscapePngInstance] - replyMessageState:TSOutgoingMessageStateSent], - ]]; - - return actions; -} - -+ (DebugUIMessagesAction *)allQuotedReplyAction:(TSThread *)thread -{ - OWSAssertDebug(thread); - - return - [DebugUIMessagesGroupAction allGroupActionWithLabel:@"All Quoted Reply" - subactions:[self allFakeQuotedReplyActions:thread includeLabels:YES]]; -} - -+ (void)selectQuotedReplyAction:(TSThread *)thread -{ - OWSAssertIsOnMainThread(); - OWSAssertDebug(thread); - - [self selectActionUI:[self allFakeQuotedReplyActions:thread includeLabels:NO] label:@"Select QuotedReply"]; -} - -+ (DebugUIMessagesAction *)randomQuotedReplyAction:(TSThread *)thread -{ - OWSAssertDebug(thread); - - return [DebugUIMessagesGroupAction - randomGroupActionWithLabel:@"Random Quoted Reply" - subactions:[self allFakeQuotedReplyActions:thread includeLabels:NO]]; -} - -#pragma mark - Exemplary - -+ (NSArray *)allFakeActions:(TSThread *)thread includeLabels:(BOOL)includeLabels -{ - OWSAssertDebug(thread); - - NSMutableArray *actions = [NSMutableArray new]; - [actions addObjectsFromArray:[self allFakeMediaActions:thread includeLabels:includeLabels]]; - [actions addObjectsFromArray:[self allFakeTextActions:thread includeLabels:includeLabels]]; - [actions addObjectsFromArray:[self allFakeSequenceActions:thread includeLabels:includeLabels]]; - [actions addObjectsFromArray:[self allFakeQuotedReplyActions:thread includeLabels:includeLabels]]; - [actions addObjectsFromArray:[self allFakeBackDatedActions:thread includeLabels:includeLabels]]; - [actions addObjectsFromArray:[self allFakeContactShareActions:thread includeLabels:includeLabels]]; - return actions; -} - -+ (DebugUIMessagesAction *)allFakeAction:(TSThread *)thread -{ - OWSAssertDebug(thread); - - return [DebugUIMessagesGroupAction allGroupActionWithLabel:@"All Fake" - subactions:[self allFakeActions:thread includeLabels:YES]]; -} - -+ (void)selectFakeAction:(TSThread *)thread -{ - OWSAssertIsOnMainThread(); - OWSAssertDebug(thread); - - [self selectActionUI:[self allFakeActions:thread includeLabels:NO] label:@"Select Fake"]; -} - -+ (void)selectActionUI:(NSArray *)actions label:(NSString *)label -{ - OWSAssertIsOnMainThread(); - UIAlertController *alert = - [UIAlertController alertControllerWithTitle:label message:nil preferredStyle:UIAlertControllerStyleActionSheet]; - for (DebugUIMessagesAction *action in actions) { - [alert addAction:[UIAlertAction actionWithTitle:action.label - style:UIAlertActionStyleDefault - handler:^(UIAlertAction *ignore) { - [self performActionNTimes:action]; - }]]; - } - - [alert addAction:[OWSAlerts cancelAction]]; - - UIViewController *fromViewController = [[UIApplication sharedApplication] frontmostViewController]; - [fromViewController presentAlert:alert]; -} - -#pragma mark - Sequences - -+ (NSArray *)allFakeSequenceActions:(TSThread *)thread includeLabels:(BOOL)includeLabels -{ - OWSAssertDebug(thread); - - NSMutableArray *actions = [NSMutableArray new]; - - if (includeLabels) { - [actions addObject:[self fakeOutgoingTextMessageAction:thread - messageState:TSOutgoingMessageStateSent - text:@"⚠️ Short Message Sequences ⚠️"]]; - } - - [actions addObject:[self fakeIncomingTextMessageAction:thread text:@"Incoming"]]; - [actions - addObject:[self fakeOutgoingTextMessageAction:thread messageState:TSOutgoingMessageStateSent text:@"Outgoing"]]; - [actions addObject:[self fakeIncomingTextMessageAction:thread text:@"Incoming 1"]]; - [actions addObject:[self fakeIncomingTextMessageAction:thread text:@"Incoming 2"]]; - [actions addObject:[self fakeIncomingTextMessageAction:thread text:@"Incoming 3"]]; - [actions addObject:[self fakeOutgoingTextMessageAction:thread - messageState:TSOutgoingMessageStateFailed - text:@"Outgoing Unsent 1"]]; - [actions addObject:[self fakeOutgoingTextMessageAction:thread - messageState:TSOutgoingMessageStateFailed - text:@"Outgoing Unsent 2"]]; - [actions addObject:[self fakeOutgoingTextMessageAction:thread - messageState:TSOutgoingMessageStateSending - text:@"Outgoing Sending 1"]]; - [actions addObject:[self fakeOutgoingTextMessageAction:thread - messageState:TSOutgoingMessageStateSending - text:@"Outgoing Sending 2"]]; - [actions addObject:[self fakeOutgoingTextMessageAction:thread - messageState:TSOutgoingMessageStateSent - text:@"Outgoing Sent 1"]]; - [actions addObject:[self fakeOutgoingTextMessageAction:thread - messageState:TSOutgoingMessageStateSent - text:@"Outgoing Sent 2"]]; - [actions addObject:[self fakeShortOutgoingTextMessageAction:thread - text:@"Outgoing Delivered 1" - messageState:TSOutgoingMessageStateSent - isDelivered:YES - isRead:NO]]; - [actions addObject:[self fakeShortOutgoingTextMessageAction:thread - text:@"Outgoing Delivered 2" - messageState:TSOutgoingMessageStateSent - isDelivered:YES - isRead:NO]]; - [actions addObject:[self fakeShortOutgoingTextMessageAction:thread - text:@"Outgoing Read 1" - messageState:TSOutgoingMessageStateSent - isDelivered:YES - isRead:YES]]; - [actions addObject:[self fakeShortOutgoingTextMessageAction:thread - text:@"Outgoing Read 2" - messageState:TSOutgoingMessageStateSent - isDelivered:YES - isRead:YES]]; - [actions addObject:[self fakeIncomingTextMessageAction:thread text:@"Incoming"]]; - - if (includeLabels) { - [actions addObject:[self fakeOutgoingTextMessageAction:thread - messageState:TSOutgoingMessageStateSent - text:@"⚠️ Long Message Sequences ⚠️"]]; - } - - NSString *longText = @"\nLorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse rutrum, nulla " - @"vitae pretium hendrerit, tellus turpis pharetra libero..."; - - [actions addObject:[self fakeIncomingTextMessageAction:thread text:[@"Incoming" stringByAppendingString:longText]]]; - [actions addObject:[self fakeOutgoingTextMessageAction:thread - messageState:TSOutgoingMessageStateSent - text:[@"Outgoing" stringByAppendingString:longText]]]; - [actions - addObject:[self fakeIncomingTextMessageAction:thread text:[@"Incoming 1" stringByAppendingString:longText]]]; - [actions - addObject:[self fakeIncomingTextMessageAction:thread text:[@"Incoming 2" stringByAppendingString:longText]]]; - [actions - addObject:[self fakeIncomingTextMessageAction:thread text:[@"Incoming 3" stringByAppendingString:longText]]]; - [actions addObject:[self fakeOutgoingTextMessageAction:thread - messageState:TSOutgoingMessageStateFailed - text:[@"Outgoing Unsent 1" stringByAppendingString:longText]]]; - [actions addObject:[self fakeOutgoingTextMessageAction:thread - messageState:TSOutgoingMessageStateFailed - text:[@"Outgoing Unsent 2" stringByAppendingString:longText]]]; - [actions addObject:[self fakeOutgoingTextMessageAction:thread - messageState:TSOutgoingMessageStateSending - text:[@"Outgoing Sending 1" stringByAppendingString:longText]]]; - [actions addObject:[self fakeOutgoingTextMessageAction:thread - messageState:TSOutgoingMessageStateSending - text:[@"Outgoing Sending 2" stringByAppendingString:longText]]]; - [actions addObject:[self fakeOutgoingTextMessageAction:thread - messageState:TSOutgoingMessageStateSent - text:[@"Outgoing Sent 1" stringByAppendingString:longText]]]; - [actions addObject:[self fakeOutgoingTextMessageAction:thread - messageState:TSOutgoingMessageStateSent - text:[@"Outgoing Sent 2" stringByAppendingString:longText]]]; - [actions - addObject:[self fakeShortOutgoingTextMessageAction:thread - text:[@"Outgoing Delivered 1" stringByAppendingString:longText] - messageState:TSOutgoingMessageStateSent - isDelivered:YES - isRead:NO]]; - [actions - addObject:[self fakeShortOutgoingTextMessageAction:thread - text:[@"Outgoing Delivered 2" stringByAppendingString:longText] - messageState:TSOutgoingMessageStateSent - isDelivered:YES - isRead:NO]]; - [actions addObject:[self fakeShortOutgoingTextMessageAction:thread - text:[@"Outgoing Read 1" stringByAppendingString:longText] - messageState:TSOutgoingMessageStateSent - isDelivered:YES - isRead:YES]]; - [actions addObject:[self fakeShortOutgoingTextMessageAction:thread - text:[@"Outgoing Read 2" stringByAppendingString:longText] - messageState:TSOutgoingMessageStateSent - isDelivered:YES - isRead:YES]]; - [actions addObject:[self fakeIncomingTextMessageAction:thread text:[@"Incoming" stringByAppendingString:longText]]]; - - return actions; -} - -+ (DebugUIMessagesAction *)allFakeSequencesAction:(TSThread *)thread -{ - OWSAssertDebug(thread); - - return [DebugUIMessagesGroupAction allGroupActionWithLabel:@"All Fake Sequences" - subactions:[self allFakeSequenceActions:thread includeLabels:YES]]; -} - -#pragma mark - Back-dated - -+ (DebugUIMessagesAction *)fakeBackDatedMessageAction:(TSThread *)thread - label:(NSString *)label - dateOffset:(int64_t)dateOffset -{ - OWSAssertDebug(thread); - - return [DebugUIMessagesSingleAction - actionWithLabel:[NSString stringWithFormat:@"Fake Back-Date Message (%@)", label] - unstaggeredActionBlock:^(NSUInteger index, YapDatabaseReadWriteTransaction *transaction) { - NSString *messageBody = - [[@(index).stringValue stringByAppendingString:@" "] stringByAppendingString:self.randomText]; - TSOutgoingMessage *message = [self createFakeOutgoingMessage:thread - messageBody:messageBody - fakeAssetLoader:nil - messageState:TSOutgoingMessageStateSent - isDelivered:NO - isRead:NO - quotedMessage:nil - contactShare:nil - linkPreview:nil - transaction:transaction]; - [message setReceivedAtTimestamp:(uint64_t)((int64_t)[NSDate ows_millisecondTimeStamp] + dateOffset)]; - [message saveWithTransaction:transaction]; - }]; -} - -+ (NSArray *)allFakeBackDatedActions:(TSThread *)thread includeLabels:(BOOL)includeLabels -{ - OWSAssertDebug(thread); - - NSMutableArray *actions = [NSMutableArray new]; - - if (includeLabels) { - [actions addObject:[self fakeOutgoingTextMessageAction:thread - messageState:TSOutgoingMessageStateSent - text:@"⚠️ Back-Dated ⚠️"]]; - } - - [actions - addObject:[self fakeBackDatedMessageAction:thread label:@"One Minute Ago" dateOffset:-(int64_t)kMinuteInMs]]; - [actions addObject:[self fakeBackDatedMessageAction:thread label:@"One Hour Ago" dateOffset:-(int64_t)kHourInMs]]; - [actions addObject:[self fakeBackDatedMessageAction:thread label:@"One Day Ago" dateOffset:-(int64_t)kDayInMs]]; - [actions - addObject:[self fakeBackDatedMessageAction:thread label:@"Two Days Ago" dateOffset:-(int64_t)kDayInMs * 2]]; - [actions - addObject:[self fakeBackDatedMessageAction:thread label:@"Ten Days Ago" dateOffset:-(int64_t)kDayInMs * 10]]; - [actions - addObject:[self fakeBackDatedMessageAction:thread label:@"400 Days Ago" dateOffset:-(int64_t)kDayInMs * 400]]; - - return actions; -} - -+ (DebugUIMessagesAction *)allFakeBackDatedAction:(TSThread *)thread -{ - OWSAssertDebug(thread); - - return [DebugUIMessagesGroupAction allGroupActionWithLabel:@"All Fake Back-Dated" - subactions:[self allFakeBackDatedActions:thread includeLabels:YES]]; -} - -+ (void)selectBackDatedAction:(TSThread *)thread -{ - OWSAssertIsOnMainThread(); - OWSAssertDebug(thread); - - [self selectActionUI:[self allFakeBackDatedActions:thread includeLabels:NO] label:@"Select Back-Dated"]; -} - -#pragma mark - Contact Shares - -typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transaction); - -+ (DebugUIMessagesAction *)fakeContactShareMessageAction:(TSThread *)thread - label:(NSString *)label - contactBlock:(OWSContactBlock)contactBlock -{ - OWSAssertDebug(thread); - - return [DebugUIMessagesSingleAction - actionWithLabel:[NSString stringWithFormat:@"Fake Contact Share (%@)", label] - unstaggeredActionBlock:^(NSUInteger index, YapDatabaseReadWriteTransaction *transaction) { - OWSContact *contact = contactBlock(transaction); - TSOutgoingMessage *message = [self createFakeOutgoingMessage:thread - messageBody:nil - fakeAssetLoader:nil - messageState:TSOutgoingMessageStateSent - isDelivered:NO - isRead:NO - quotedMessage:nil - contactShare:contact - linkPreview:nil - transaction:transaction]; - [message saveWithTransaction:transaction]; - }]; -} - -+ (NSArray *)allFakeContactShareActions:(TSThread *)thread includeLabels:(BOOL)includeLabels -{ - OWSAssertDebug(thread); - - NSMutableArray *actions = [NSMutableArray new]; - - if (includeLabels) { - [actions addObject:[self fakeOutgoingTextMessageAction:thread - messageState:TSOutgoingMessageStateSent - text:@"⚠️ Share Contact ⚠️"]]; - } - - [actions addObject:[self fakeContactShareMessageAction:thread - label:@"Name & Number" - contactBlock:^(YapDatabaseReadWriteTransaction *transaction) { - OWSContact *contact = [OWSContact new]; - OWSContactName *name = [OWSContactName new]; - contact.name = name; - name.givenName = @"Alice"; - OWSContactPhoneNumber *phoneNumber = [OWSContactPhoneNumber new]; - phoneNumber.phoneType = OWSContactPhoneType_Home; - phoneNumber.phoneNumber = @"+13213214321"; - contact.phoneNumbers = @[ - phoneNumber, - ]; - return contact; - }]]; - [actions addObject:[self fakeContactShareMessageAction:thread - label:@"Name & Email" - contactBlock:^(YapDatabaseReadWriteTransaction *transaction) { - OWSContact *contact = [OWSContact new]; - OWSContactName *name = [OWSContactName new]; - contact.name = name; - name.givenName = @"Bob"; - OWSContactEmail *email = [OWSContactEmail new]; - email.emailType = OWSContactEmailType_Home; - email.email = @"a@b.com"; - contact.emails = @[ - email, - ]; - return contact; - }]]; - [actions addObject:[self fakeContactShareMessageAction:thread - label:@"Complicated" - contactBlock:^(YapDatabaseReadWriteTransaction *transaction) { - OWSContact *contact = [OWSContact new]; - OWSContactName *name = [OWSContactName new]; - contact.name = name; - name.givenName = @"Alice"; - name.familyName = @"Carol"; - name.middleName = @"Bob"; - name.namePrefix = @"Ms."; - name.nameSuffix = @"Esq."; - name.organizationName = @"Falafel Hut"; - - OWSContactPhoneNumber *phoneNumber1 = [OWSContactPhoneNumber new]; - phoneNumber1.phoneType = OWSContactPhoneType_Home; - phoneNumber1.phoneNumber = @"+13213215555"; - OWSContactPhoneNumber *phoneNumber2 = [OWSContactPhoneNumber new]; - phoneNumber2.phoneType = OWSContactPhoneType_Custom; - phoneNumber2.label = @"Carphone"; - phoneNumber2.phoneNumber = @"+13332226666"; - contact.phoneNumbers = @[ - phoneNumber1, - phoneNumber2, - ]; - - NSMutableArray *emails = [NSMutableArray new]; - for (NSUInteger i = 0; i < 16; i++) { - OWSContactEmail *email = [OWSContactEmail new]; - email.emailType = OWSContactEmailType_Home; - email.email = [NSString stringWithFormat:@"a%zd@b.com", i]; - [emails addObject:email]; - } - contact.emails = emails; - - OWSContactAddress *address1 = [OWSContactAddress new]; - address1.addressType = OWSContactAddressType_Home; - address1.street = @"123 home st."; - address1.neighborhood = @"round the bend."; - address1.city = @"homeville"; - address1.region = @"HO"; - address1.postcode = @"12345"; - address1.country = @"USA"; - OWSContactAddress *address2 = [OWSContactAddress new]; - address2.addressType = OWSContactAddressType_Custom; - address2.label = @"Otra casa"; - address2.pobox = @"caja 123"; - address2.street = @"123 casa calle"; - address2.city = @"barrio norte"; - address2.region = @"AB"; - address2.postcode = @"53421"; - address2.country = @"MX"; - contact.addresses = @[ - address1, - address2, - ]; - - UIImage *avatarImage = - [OWSAvatarBuilder buildRandomAvatarWithDiameter:200]; - [contact saveAvatarImage:avatarImage transaction:transaction]; - - return contact; - }]]; - [actions addObject:[self fakeContactShareMessageAction:thread - label:@"Long values" - contactBlock:^(YapDatabaseReadWriteTransaction *transaction) { - OWSContact *contact = [OWSContact new]; - OWSContactName *name = [OWSContactName new]; - contact.name = name; - name.givenName = @"Bobasdjasdlkjasldkjas"; - name.familyName = @"Bobasdjasdlkjasldkjas"; - OWSContactEmail *email = [OWSContactEmail new]; - email.emailType = OWSContactEmailType_Mobile; - email.email = @"asdlakjsaldkjasldkjasdlkjasdlkjasdlkajsa@b.com"; - contact.emails = @[ - email, - ]; - return contact; - }]]; - [actions addObject:[self fakeContactShareMessageAction:thread - label:@"System Contact w/o Signal" - contactBlock:^(YapDatabaseReadWriteTransaction *transaction) { - OWSContact *contact = [OWSContact new]; - OWSContactName *name = [OWSContactName new]; - contact.name = name; - name.givenName = @"Add Me To Your Contacts"; - OWSContactPhoneNumber *phoneNumber = [OWSContactPhoneNumber new]; - phoneNumber.phoneType = OWSContactPhoneType_Work; - phoneNumber.phoneNumber = @"+324602053911"; - contact.phoneNumbers = @[ - phoneNumber, - ]; - return contact; - }]]; - [actions addObject:[self fakeContactShareMessageAction:thread - label:@"System Contact w. Signal" - contactBlock:^(YapDatabaseReadWriteTransaction *transaction) { - OWSContact *contact = [OWSContact new]; - OWSContactName *name = [OWSContactName new]; - contact.name = name; - name.givenName = @"Add Me To Your Contacts"; - OWSContactPhoneNumber *phoneNumber = [OWSContactPhoneNumber new]; - phoneNumber.phoneType = OWSContactPhoneType_Work; - phoneNumber.phoneNumber = @"+32460205392"; - contact.phoneNumbers = @[ - phoneNumber, - ]; - return contact; - }]]; - - return actions; -} - -+ (DebugUIMessagesAction *)fakeAllContactShareAction:(TSThread *)thread -{ - OWSAssertDebug(thread); - - return - [DebugUIMessagesGroupAction allGroupActionWithLabel:@"All Fake Contact Shares" - subactions:[self allFakeContactShareActions:thread includeLabels:YES]]; -} - - -+ (DebugUIMessagesAction *)sendContactShareMessageAction:(TSThread *)thread - label:(NSString *)label - contactBlock:(OWSContactBlock)contactBlock -{ - OWSAssertDebug(thread); - - return [DebugUIMessagesSingleAction - actionWithLabel:[NSString stringWithFormat:@"Send Contact Share (%@)", label] - staggeredActionBlock:^(NSUInteger index, - YapDatabaseReadWriteTransaction *transaction, - ActionSuccessBlock success, - ActionFailureBlock failure) { - OWSContact *contact = contactBlock(transaction); - OWSLogVerbose(@"sending contact: %@", contact.debugDescription); - [ThreadUtil enqueueMessageWithContactShare:contact inThread:thread]; - - success(); - }]; -} - -+ (NSArray *)allSendContactShareActions:(TSThread *)thread includeLabels:(BOOL)includeLabels -{ - OWSAssertDebug(thread); - - NSMutableArray *actions = [NSMutableArray new]; - - if (includeLabels) { - [actions addObject:[self fakeOutgoingTextMessageAction:thread - messageState:TSOutgoingMessageStateSent - text:@"⚠️ Send Share Contact ⚠️"]]; - } - - [actions addObject:[self sendContactShareMessageAction:thread - label:@"Name & Number" - contactBlock:^(YapDatabaseReadWriteTransaction *transaction) { - OWSContact *contact = [OWSContact new]; - OWSContactName *name = [OWSContactName new]; - contact.name = name; - name.givenName = @"Alice"; - OWSContactPhoneNumber *phoneNumber = [OWSContactPhoneNumber new]; - phoneNumber.phoneType = OWSContactPhoneType_Home; - phoneNumber.phoneNumber = @"+13213214321"; - contact.phoneNumbers = @[ - phoneNumber, - ]; - return contact; - }]]; - [actions addObject:[self sendContactShareMessageAction:thread - label:@"Name & Email" - contactBlock:^(YapDatabaseReadWriteTransaction *transaction) { - OWSContact *contact = [OWSContact new]; - OWSContactName *name = [OWSContactName new]; - contact.name = name; - name.givenName = @"Bob"; - OWSContactEmail *email = [OWSContactEmail new]; - email.emailType = OWSContactEmailType_Home; - email.email = @"a@b.com"; - contact.emails = @[ - email, - ]; - return contact; - }]]; - [actions addObject:[self sendContactShareMessageAction:thread - label:@"Complicated" - contactBlock:^(YapDatabaseReadWriteTransaction *transaction) { - OWSContact *contact = [OWSContact new]; - OWSContactName *name = [OWSContactName new]; - contact.name = name; - name.givenName = @"Alice"; - name.familyName = @"Carol"; - name.middleName = @"Bob"; - name.namePrefix = @"Ms."; - name.nameSuffix = @"Esq."; - name.organizationName = @"Falafel Hut"; - - OWSContactPhoneNumber *phoneNumber1 = [OWSContactPhoneNumber new]; - phoneNumber1.phoneType = OWSContactPhoneType_Home; - phoneNumber1.phoneNumber = @"+13213214321"; - OWSContactPhoneNumber *phoneNumber2 = [OWSContactPhoneNumber new]; - phoneNumber2.phoneType = OWSContactPhoneType_Custom; - phoneNumber2.label = @"Carphone"; - phoneNumber2.phoneNumber = @"+13332221111"; - contact.phoneNumbers = @[ - phoneNumber1, - phoneNumber2, - ]; - - NSMutableArray *emails = [NSMutableArray new]; - for (NSUInteger i = 0; i < 16; i++) { - OWSContactEmail *email = [OWSContactEmail new]; - email.emailType = OWSContactEmailType_Home; - email.email = [NSString stringWithFormat:@"a%zd@b.com", i]; - [emails addObject:email]; - } - contact.emails = emails; - - OWSContactAddress *address1 = [OWSContactAddress new]; - address1.addressType = OWSContactAddressType_Home; - address1.street = @"123 home st."; - address1.neighborhood = @"round the bend."; - address1.city = @"homeville"; - address1.region = @"HO"; - address1.postcode = @"12345"; - address1.country = @"USA"; - OWSContactAddress *address2 = [OWSContactAddress new]; - address2.addressType = OWSContactAddressType_Custom; - address2.label = @"Otra casa"; - address2.pobox = @"caja 123"; - address2.street = @"123 casa calle"; - address2.city = @"barrio norte"; - address2.region = @"AB"; - address2.postcode = @"53421"; - address2.country = @"MX"; - contact.addresses = @[ - address1, - address2, - ]; - - UIImage *avatarImage = - [OWSAvatarBuilder buildRandomAvatarWithDiameter:200]; - [contact saveAvatarImage:avatarImage transaction:transaction]; - - return contact; - }]]; - [actions addObject:[self sendContactShareMessageAction:thread - label:@"Long values" - contactBlock:^(YapDatabaseReadWriteTransaction *transaction) { - OWSContact *contact = [OWSContact new]; - OWSContactName *name = [OWSContactName new]; - contact.name = name; - name.givenName = @"Bobasdjasdlkjasldkjas"; - name.familyName = @"Bobasdjasdlkjasldkjas"; - OWSContactEmail *email = [OWSContactEmail new]; - email.emailType = OWSContactEmailType_Mobile; - email.email = @"asdlakjsaldkjasldkjasdlkjasdlkjasdlkajsa@b.com"; - contact.emails = @[ - email, - ]; - return contact; - }]]; - [actions addObject:[self sendContactShareMessageAction:thread - label:@"System Contact w/o Signal" - contactBlock:^(YapDatabaseReadWriteTransaction *transaction) { - OWSContact *contact = [OWSContact new]; - OWSContactName *name = [OWSContactName new]; - contact.name = name; - name.givenName = @"Add Me To Your Contacts"; - OWSContactPhoneNumber *phoneNumber = [OWSContactPhoneNumber new]; - phoneNumber.phoneType = OWSContactPhoneType_Work; - phoneNumber.phoneNumber = @"+324602053911"; - contact.phoneNumbers = @[ - phoneNumber, - ]; - return contact; - }]]; - [actions addObject:[self sendContactShareMessageAction:thread - label:@"System Contact w. Signal" - contactBlock:^(YapDatabaseReadWriteTransaction *transaction) { - OWSContact *contact = [OWSContact new]; - OWSContactName *name = [OWSContactName new]; - contact.name = name; - name.givenName = @"Add Me To Your Contacts"; - OWSContactPhoneNumber *phoneNumber = [OWSContactPhoneNumber new]; - phoneNumber.phoneType = OWSContactPhoneType_Work; - phoneNumber.phoneNumber = @"+32460205392"; - contact.phoneNumbers = @[ - phoneNumber, - ]; - return contact; - }]]; - - return actions; -} - -+ (void)sendAllContacts:(TSThread *)thread -{ - NSArray *subactions = [self allSendContactShareActions:thread includeLabels:NO]; - DebugUIMessagesAction *action = - [DebugUIMessagesGroupAction allGroupActionWithLabel:@"Send All Contact Shares" subactions:subactions]; - [action prepareAndPerformNTimes:subactions.count]; -} - -#pragma mark - - -+ (NSString *)randomOversizeText -{ - NSMutableString *message = [NSMutableString new]; - while (message.length < kOversizeTextMessageSizeThreshold) { - [message appendString:@"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse rutrum, nulla " - @"vitae pretium hendrerit, tellus turpis pharetra libero, vitae sodales tortor ante vel " - @"sem. Fusce sed nisl a lorem gravida tincidunt. Suspendisse efficitur non quam ac " - @"sodales. Aenean ut velit maximus, posuere sem a, accumsan nunc. Donec ullamcorper " - @"turpis lorem. Quisque dignissim purus eu placerat ultricies. Proin at urna eget mi " - @"semper congue. Aenean non elementum ex. Praesent pharetra quam at sem vestibulum, " - @"vestibulum ornare dolor elementum. Vestibulum massa tortor, scelerisque sit amet " - @"pulvinar a, rhoncus vitae nisl. Sed mi nunc, tempus at varius in, malesuada vitae " - @"dui. Vivamus efficitur pulvinar erat vitae congue. Proin vehicula turpis non felis " - @"congue facilisis. Nullam aliquet dapibus ligula ac mollis. Etiam sit amet posuere " - @"lorem, in rhoncus nisi.\n\n"]; - } - return message; -} - -+ (void)sendOversizeTextMessage:(TSThread *)thread -{ - [self sendAttachment:nil thread:thread messageBody:[self randomOversizeText]]; -} - -+ (NSData *)createRandomNSDataOfSize:(size_t)size -{ - OWSAssertDebug(size % 4 == 0); - OWSAssertDebug(size < INT_MAX); - - return [Randomness generateRandomBytes:(int)size]; -} - -+ (void)sendRandomAttachment:(TSThread *)thread uti:(NSString *)uti -{ - [self sendRandomAttachment:thread uti:uti length:256]; -} - -+ (NSString *)randomCaptionText -{ - return [NSString stringWithFormat:@"%@ (caption)", [self randomText]]; -} - -+ (void)sendRandomAttachment:(TSThread *)thread uti:(NSString *)uti length:(NSUInteger)length -{ - DataSource *_Nullable dataSource = - [DataSourceValue dataSourceWithData:[self createRandomNSDataOfSize:length] utiType:uti]; - SignalAttachment *attachment = - [SignalAttachment attachmentWithDataSource:dataSource dataUTI:uti imageQuality:TSImageQualityOriginal]; - - if (arc4random_uniform(100) > 50) { - // give 1/2 our attachments captions, and add a hint that it's a caption since we - // style them indistinguishably from a separate text message. - attachment.captionText = [self randomCaptionText]; - } - [self sendAttachment:attachment thread:thread messageBody:nil]; -} - -+ (SSKProtoEnvelope *)createEnvelopeForThread:(TSThread *)thread -{ - OWSAssertDebug(thread); - - uint64_t timestamp = [NSDate ows_millisecondTimeStamp]; - NSString *source = ^{ - if ([thread isKindOfClass:[TSGroupThread class]]) { - TSGroupThread *gThread = (TSGroupThread *)thread; - return gThread.groupModel.groupMemberIds[0]; - } else if ([thread isKindOfClass:[TSContactThread class]]) { - TSContactThread *contactThread = (TSContactThread *)thread; - return contactThread.contactIdentifier; - } else { - OWSFailDebug(@"failure: unknown thread type"); - return @"unknown-source-id"; - } - }(); - - SSKProtoEnvelopeBuilder *envelopeBuilder = [SSKProtoEnvelope builderWithType:SSKProtoEnvelopeTypeCiphertext - timestamp:timestamp]; - [envelopeBuilder setSource:source]; - [envelopeBuilder setSourceDevice:1]; - NSError *error; - SSKProtoEnvelope *_Nullable envelope = [envelopeBuilder buildAndReturnError:&error]; - if (error || !envelope) { - OWSFailDebug(@"Could not construct envelope: %@.", error); - return nil; - } - return envelope; -} - -+ (NSArray *)unsavedSystemMessagesInThread:(TSThread *)thread -{ - OWSAssertDebug(thread); - - NSMutableArray *result = [NSMutableArray new]; - - [OWSPrimaryStorage.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - if ([thread isKindOfClass:[TSContactThread class]]) { - TSContactThread *contactThread = (TSContactThread *)thread; - - [result addObject:[[TSCall alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] - withCallNumber:@"+19174054215" - callType:RPRecentCallTypeIncoming - inThread:contactThread]]; - [result addObject:[[TSCall alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] - withCallNumber:@"+19174054215" - callType:RPRecentCallTypeOutgoing - inThread:contactThread]]; - [result addObject:[[TSCall alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] - withCallNumber:@"+19174054215" - callType:RPRecentCallTypeIncomingMissed - inThread:contactThread]]; - [result addObject:[[TSCall alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] - withCallNumber:@"+19174054215" - callType:RPRecentCallTypeIncomingMissedBecauseOfChangedIdentity - inThread:contactThread]]; - [result addObject:[[TSCall alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] - withCallNumber:@"+19174054215" - callType:RPRecentCallTypeOutgoingIncomplete - inThread:contactThread]]; - [result addObject:[[TSCall alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] - withCallNumber:@"+19174054215" - callType:RPRecentCallTypeIncomingIncomplete - inThread:contactThread]]; - [result addObject:[[TSCall alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] - withCallNumber:@"+19174054215" - callType:RPRecentCallTypeIncomingDeclined - inThread:contactThread]]; - [result addObject:[[TSCall alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] - withCallNumber:@"+19174054215" - callType:RPRecentCallTypeOutgoingMissed - inThread:contactThread]]; - } - - { - NSNumber *durationSeconds = [OWSDisappearingMessagesConfiguration validDurationsSeconds][0]; - OWSDisappearingMessagesConfiguration *disappearingMessagesConfiguration = - [[OWSDisappearingMessagesConfiguration alloc] initWithThreadId:thread.uniqueId - enabled:YES - durationSeconds:(uint32_t)[durationSeconds intValue]]; - // MJK - should be safe to remove this senderTimestamp - [result addObject:[[OWSDisappearingConfigurationUpdateInfoMessage alloc] - initWithTimestamp:[NSDate ows_millisecondTimeStamp] - thread:thread - configuration:disappearingMessagesConfiguration - createdByRemoteName:@"Alice" - createdInExistingGroup:NO]]; - } - - { - NSNumber *durationSeconds = [OWSDisappearingMessagesConfiguration validDurationsSeconds][0]; - OWSDisappearingMessagesConfiguration *disappearingMessagesConfiguration = - [[OWSDisappearingMessagesConfiguration alloc] initWithThreadId:thread.uniqueId - enabled:YES - durationSeconds:(uint32_t)[durationSeconds intValue]]; - // MJK - should be safe to remove this senderTimestamp - [result addObject:[[OWSDisappearingConfigurationUpdateInfoMessage alloc] - initWithTimestamp:[NSDate ows_millisecondTimeStamp] - thread:thread - configuration:disappearingMessagesConfiguration - createdByRemoteName:nil - createdInExistingGroup:YES]]; - } - - { - NSNumber *durationSeconds = [[OWSDisappearingMessagesConfiguration validDurationsSeconds] lastObject]; - OWSDisappearingMessagesConfiguration *disappearingMessagesConfiguration = - [[OWSDisappearingMessagesConfiguration alloc] initWithThreadId:thread.uniqueId - enabled:YES - durationSeconds:(uint32_t)[durationSeconds intValue]]; - // MJK TODO - remove senderTimestamp - [result addObject:[[OWSDisappearingConfigurationUpdateInfoMessage alloc] - initWithTimestamp:[NSDate ows_millisecondTimeStamp] - thread:thread - configuration:disappearingMessagesConfiguration - createdByRemoteName:@"Alice" - createdInExistingGroup:NO]]; - } - { - OWSDisappearingMessagesConfiguration *disappearingMessagesConfiguration = - [[OWSDisappearingMessagesConfiguration alloc] initWithThreadId:thread.uniqueId - enabled:NO - durationSeconds:0]; - // MJK TODO - remove senderTimestamp - [result addObject:[[OWSDisappearingConfigurationUpdateInfoMessage alloc] - initWithTimestamp:[NSDate ows_millisecondTimeStamp] - thread:thread - configuration:disappearingMessagesConfiguration - createdByRemoteName:@"Alice" - createdInExistingGroup:NO]]; - } - - [result addObject:[TSInfoMessage userNotRegisteredMessageInThread:thread recipientId:@"+19174054215"]]; - - // MJK - should be safe to remove this senderTimestamp - [result addObject:[[TSInfoMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] - inThread:thread - messageType:TSInfoMessageTypeSessionDidEnd]]; - // TODO: customMessage? - // MJK - should be safe to remove this senderTimestamp - [result addObject:[[TSInfoMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] - inThread:thread - messageType:TSInfoMessageTypeGroupUpdate]]; - // TODO: customMessage? - // MJK - should be safe to remove this senderTimestamp - [result addObject:[[TSInfoMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] - inThread:thread - messageType:TSInfoMessageTypeGroupQuit]]; - - // MJK - should be safe to remove this senderTimestamp - [result addObject:[[OWSVerificationStateChangeMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] - thread:thread - recipientId:@"+19174054215" - verificationState:OWSVerificationStateDefault - isLocalChange:YES]]; - - // MJK - should be safe to remove this senderTimestamp - [result addObject:[[OWSVerificationStateChangeMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] - thread:thread - recipientId:@"+19174054215" - verificationState:OWSVerificationStateVerified - isLocalChange:YES]]; - // MJK - should be safe to remove this senderTimestamp - [result - addObject:[[OWSVerificationStateChangeMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] - thread:thread - recipientId:@"+19174054215" - verificationState:OWSVerificationStateNoLongerVerified - isLocalChange:YES]]; - - // MJK - should be safe to remove this senderTimestamp - [result addObject:[[OWSVerificationStateChangeMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] - thread:thread - recipientId:@"+19174054215" - verificationState:OWSVerificationStateDefault - isLocalChange:NO]]; - // MJK - should be safe to remove this senderTimestamp - [result addObject:[[OWSVerificationStateChangeMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] - thread:thread - recipientId:@"+19174054215" - verificationState:OWSVerificationStateVerified - isLocalChange:NO]]; - // MJK - should be safe to remove this senderTimestamp - [result - addObject:[[OWSVerificationStateChangeMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] - thread:thread - recipientId:@"+19174054215" - verificationState:OWSVerificationStateNoLongerVerified - isLocalChange:NO]]; - - [result addObject:[TSErrorMessage missingSessionWithEnvelope:[self createEnvelopeForThread:thread] - withTransaction:transaction]]; - [result addObject:[TSErrorMessage invalidKeyExceptionWithEnvelope:[self createEnvelopeForThread:thread] - withTransaction:transaction]]; - [result addObject:[TSErrorMessage invalidVersionWithEnvelope:[self createEnvelopeForThread:thread] - withTransaction:transaction]]; - [result addObject:[TSErrorMessage corruptedMessageWithEnvelope:[self createEnvelopeForThread:thread] - withTransaction:transaction]]; - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - TSInvalidIdentityKeyReceivingErrorMessage *_Nullable blockingSNChangeMessage = - [TSInvalidIdentityKeyReceivingErrorMessage untrustedKeyWithEnvelope:[self createEnvelopeForThread:thread] - withTransaction:transaction]; -#pragma clang diagnostic pop - - OWSAssertDebug(blockingSNChangeMessage); - [result addObject:blockingSNChangeMessage]; - // MJK TODO - should be safe to remove this senderTimestamp - [result addObject:[[TSErrorMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] - inThread:thread - failedMessageType:TSErrorMessageNonBlockingIdentityChange - recipientId:@"+19174054215"]]; - }]; - - return result; -} - -+ (void)createSystemMessagesInThread:(TSThread *)thread -{ - OWSAssertDebug(thread); - - NSArray *messages = [self unsavedSystemMessagesInThread:thread]; - [OWSPrimaryStorage.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - for (TSInteraction *message in messages) { - [message saveWithTransaction:transaction]; - } - }]; -} - -+ (void)createSystemMessageInThread:(TSThread *)thread -{ - OWSAssertDebug(thread); - - NSArray *messages = [self unsavedSystemMessagesInThread:thread]; - TSInteraction *message = messages[(NSUInteger)arc4random_uniform((uint32_t)messages.count)]; - [OWSPrimaryStorage.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [message saveWithTransaction:transaction]; - }]; -} - -+ (void)sendTextAndSystemMessages:(NSUInteger)counter thread:(TSThread *)thread -{ - if (counter < 1) { - return; - } - if (arc4random_uniform(2) == 0) { - [self sendTextMessageInThread:thread counter:counter]; - } else { - [self createSystemMessageInThread:thread]; - } - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)1.f * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ - [self sendTextAndSystemMessages:counter - 1 thread:thread]; - }); -} - -+ (NSString *)randomText -{ - NSArray *randomTexts = @[ - @"Lorem ipsum dolor sit amet, consectetur adipiscing elit. ", - (@"Lorem ipsum dolor sit amet, consectetur adipiscing elit. " - @"Suspendisse rutrum, nulla vitae pretium hendrerit, tellus " - @"turpis pharetra libero, vitae sodales tortor ante vel sem."), - @"In a time of universal deceit - telling the truth is a revolutionary act.", - @"If you want a vision of the future, imagine a boot stamping on a human face - forever.", - @"Who controls the past controls the future. Who controls the present controls the past.", - @"All animals are equal, but some animals are more equal than others.", - @"War is peace. Freedom is slavery. Ignorance is strength.", - (@"All the war-propaganda, all the screaming and lies and hatred, comes invariably from people who are not " - @"fighting."), - (@"Political language. . . is designed to make lies sound truthful and murder respectable, and to give an " - @"appearance of solidity to pure wind."), - (@"The nationalist not only does not disapprove of atrocities committed by his own side, but he has a " - @"remarkable capacity for not even hearing about them."), - (@"Every generation imagines itself to be more intelligent than the one that went before it, and wiser than " - @"the " - @"one that comes after it."), - @"War against a foreign country only happens when the moneyed classes think they are going to profit from it.", - @"People have only as much liberty as they have the intelligence to want and the courage to take.", - (@"You cannot buy the revolution. You cannot make the revolution. You can only be the revolution. It is in your " - @"spirit, or it is nowhere."), - (@"That is what I have always understood to be the essence of anarchism: the conviction that the burden of " - @"proof has to be placed on authority, and that it should be dismantled if that burden cannot be met."), - (@"Ask for work. If they don't give you work, ask for bread. If they do not give you work or bread, then take " - @"bread."), - @"Every society has the criminals it deserves.", - (@"Anarchism is founded on the observation that since few men are wise enough to rule themselves, even fewer " - @"are wise enough to rule others."), - @"If you would know who controls you see who you may not criticise.", - @"At one time in the world there were woods that no one owned." - ]; - NSString *randomText = randomTexts[(NSUInteger)arc4random_uniform((uint32_t)randomTexts.count)]; - return randomText; -} - -+ (void)createFakeThreads:(NSUInteger)threadCount withFakeMessages:(NSUInteger)messageCount -{ - [DebugContactsUtils - createRandomContacts:threadCount - contactHandler:^(CNContact *_Nonnull contact, NSUInteger idx, BOOL *_Nonnull stop) { - NSString *phoneNumberText = contact.phoneNumbers.firstObject.value.stringValue; - OWSAssertDebug(phoneNumberText); - PhoneNumber *phoneNumber = [PhoneNumber tryParsePhoneNumberFromUserSpecifiedText:phoneNumberText]; - OWSAssertDebug(phoneNumber); - OWSAssertDebug(phoneNumber.toE164); - - TSContactThread *contactThread = [TSContactThread getOrCreateThreadWithContactId:phoneNumber.toE164]; - [self sendFakeMessages:messageCount thread:contactThread]; - OWSLogError(@"Create fake thread: %@, interactions: %lu", - phoneNumber.toE164, - (unsigned long)contactThread.numberOfInteractions); - }]; -} - -+ (void)sendFakeMessages:(NSUInteger)counter thread:(TSThread *)thread -{ - [self sendFakeMessages:counter thread:thread isTextOnly:NO]; -} - -+ (void)sendFakeMessages:(NSUInteger)counter thread:(TSThread *)thread isTextOnly:(BOOL)isTextOnly -{ - const NSUInteger kMaxBatchSize = 2500; - if (counter < kMaxBatchSize) { - [OWSPrimaryStorage.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [self sendFakeMessages:counter thread:thread isTextOnly:isTextOnly transaction:transaction]; - }]; - } else { - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - NSUInteger remainder = counter; - while (remainder > 0) { - NSUInteger batchSize = MIN(kMaxBatchSize, remainder); - [OWSPrimaryStorage.dbReadWriteConnection - readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [self sendFakeMessages:batchSize thread:thread isTextOnly:isTextOnly transaction:transaction]; - }]; - remainder -= batchSize; - OWSLogInfo(@"sendFakeMessages %lu / %lu", (unsigned long)(counter - remainder), (unsigned long)counter); - } - }); - } -} - -+ (void)thrashInsertAndDeleteForThread:(TSThread *)thread counter:(NSUInteger)counter -{ - if (counter == 0) { - return; - } - uint32_t sendDelay = arc4random_uniform((uint32_t)(0.01 * NSEC_PER_SEC)); - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, sendDelay), dispatch_get_main_queue(), ^{ - [self sendFakeMessages:1 thread:thread]; - }); - - uint32_t deleteDelay = arc4random_uniform((uint32_t)(0.01 * NSEC_PER_SEC)); - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, deleteDelay), dispatch_get_main_queue(), ^{ - [OWSPrimaryStorage.sharedManager.dbReadWriteConnection - asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { - [self deleteRandomMessages:1 thread:thread transaction:transaction]; - }]; - [self thrashInsertAndDeleteForThread:thread counter:counter - 1]; - }); -} - -// TODO: Remove. -+ (void)sendFakeMessages:(NSUInteger)counter - thread:(TSThread *)thread - isTextOnly:(BOOL)isTextOnly - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSLogInfo(@"sendFakeMessages: %lu", (unsigned long)counter); - - for (NSUInteger i = 0; i < counter; i++) { - NSString *randomText = [[self randomText] stringByAppendingFormat:@" (sequence: %lu)", (unsigned long)i + 1]; - switch (arc4random_uniform(isTextOnly ? 2 : 4)) { - case 0: { - // MJK - should be safe to remove this senderTimestamp - TSIncomingMessage *message = - [[TSIncomingMessage alloc] initIncomingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp] - inThread:thread - authorId:@"+19174054215" - sourceDeviceId:0 - messageBody:randomText - attachmentIds:@[] - expiresInSeconds:0 - quotedMessage:nil - contactShare:nil - linkPreview:nil - serverTimestamp:nil - wasReceivedByUD:NO]; - [message markAsReadNowWithSendReadReceipt:NO transaction:transaction]; - break; - } - case 1: { - [self createFakeOutgoingMessage:thread - messageBody:randomText - fakeAssetLoader:nil - messageState:TSOutgoingMessageStateFailed - isDelivered:NO - isRead:NO - quotedMessage:nil - contactShare:nil - linkPreview:nil - transaction:transaction]; - break; - } - case 2: { - UInt32 filesize = 64; - TSAttachmentPointer *pointer = - [[TSAttachmentPointer alloc] initWithServerId:237391539706350548 - key:[self createRandomNSDataOfSize:filesize] - digest:nil - byteCount:filesize - contentType:@"audio/mp3" - sourceFilename:@"test.mp3" - caption:nil - albumMessageId:nil - attachmentType:TSAttachmentTypeDefault - mediaSize:CGSizeZero]; - pointer.state = TSAttachmentPointerStateFailed; - [pointer saveWithTransaction:transaction]; - // MJK - should be safe to remove this senderTimestamp - TSIncomingMessage *message = - [[TSIncomingMessage alloc] initIncomingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp] - inThread:thread - authorId:@"+19174054215" - sourceDeviceId:0 - messageBody:nil - attachmentIds:@[ - pointer.uniqueId, - ] - expiresInSeconds:0 - quotedMessage:nil - contactShare:nil - linkPreview:nil - serverTimestamp:nil - wasReceivedByUD:NO]; - [message markAsReadNowWithSendReadReceipt:NO transaction:transaction]; - break; - } - case 3: { - NSString *filename = @"test.mp3"; - UInt32 filesize = 16; - - TSAttachmentStream *attachmentStream = [[TSAttachmentStream alloc] initWithContentType:@"audio/mp3" - byteCount:filesize - sourceFilename:filename - caption:nil - albumMessageId:nil]; - - NSError *error; - BOOL success = [attachmentStream writeData:[self createRandomNSDataOfSize:filesize] error:&error]; - OWSAssertDebug(success && !error); - [attachmentStream saveWithTransaction:transaction]; - - [self createFakeOutgoingMessage:thread - messageBody:nil - attachmentId:attachmentStream.uniqueId - filename:filename - messageState:TSOutgoingMessageStateFailed - isDelivered:NO - isRead:NO - isVoiceMessage:NO - quotedMessage:nil - contactShare:nil - linkPreview:nil - transaction:transaction]; - break; - } - } - } -} - -#pragma mark - - -+ (void)createNewGroups:(NSUInteger)counter recipientId:(NSString *)recipientId -{ - if (counter < 1) { - return; - } - - NSString *groupName = [NSUUID UUID].UUIDString; - NSMutableArray *recipientIds = [@[ - recipientId, - TSAccountManager.localNumber, - ] mutableCopy]; - NSData *groupId = [Randomness generateRandomBytes:kGroupIdLength]; - TSGroupModel *groupModel = [[TSGroupModel alloc] initWithTitle:groupName memberIds:recipientIds image:nil groupId:groupId groupType:closedGroup adminIds:@[ TSAccountManager.localNumber ]]; - - __block TSGroupThread *thread; - [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { - thread = [TSGroupThread getOrCreateThreadWithGroupModel:groupModel transaction:transaction]; - OWSAssertDebug(thread); - - TSOutgoingMessage *message = [TSOutgoingMessage outgoingMessageInThread:thread - groupMetaMessage:TSGroupMetaMessageNew - expiresInSeconds:0]; - [message updateWithCustomMessage:NSLocalizedString(@"GROUP_CREATED", nil) transaction:transaction]; - - [self.messageSenderJobQueue addMessage:message transaction:transaction]; - }]; - - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)1.f * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ - [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [ThreadUtil enqueueMessageWithText:[@(counter) description] - inThread:thread - quotedReplyModel:nil - linkPreviewDraft:nil - transaction:transaction]; - }]; - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)1.f * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ - [self createNewGroups:counter - 1 recipientId:recipientId]; - }); - }); -} - -+ (void)injectFakeIncomingMessages:(NSUInteger)counter thread:(TSThread *)thread -{ - // Wait 5 seconds so debug user has time to navigate to another - // view before message processing occurs. - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.f * NSEC_PER_SEC)), - dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), - ^{ - for (NSUInteger i = 0; i < counter; i++) { - [self injectIncomingMessageInThread:thread counter:counter - i]; - } - }); -} - -+ (void)injectIncomingMessageInThread:(TSThread *)thread counter:(NSUInteger)counter -{ - OWSAssertDebug(thread); - - OWSLogInfo(@"injectIncomingMessageInThread: %lu", (unsigned long)counter); - - NSString *randomText = [self randomText]; - NSString *text = [[[@(counter) description] stringByAppendingString:@" "] stringByAppendingString:randomText]; - - SSKProtoDataMessageBuilder *dataMessageBuilder = [SSKProtoDataMessage builder]; - [dataMessageBuilder setBody:text]; - - if ([thread isKindOfClass:[TSGroupThread class]]) { - TSGroupThread *groupThread = (TSGroupThread *)thread; - SSKProtoGroupContextBuilder *groupBuilder = - [SSKProtoGroupContext builderWithId:groupThread.groupModel.groupId type:SSKProtoGroupContextTypeDeliver]; - [dataMessageBuilder setGroup:groupBuilder.buildIgnoringErrors]; - } - - SSKProtoContentBuilder *payloadBuilder = [SSKProtoContent builder]; - [payloadBuilder setDataMessage:dataMessageBuilder.buildIgnoringErrors]; - NSData *plaintextData = [payloadBuilder buildIgnoringErrors].serializedDataIgnoringErrors; - - // Try to use an arbitrary member of the current thread that isn't - // ourselves as the sender. - NSString *_Nullable recipientId = [[thread recipientIdentifiers] firstObject]; - // This might be an "empty" group with no other members. If so, use a fake - // sender id. - if (!recipientId) { - recipientId = @"+12345678901"; - } - - uint64_t timestamp = [NSDate ows_millisecondTimeStamp]; - NSString *source = recipientId; - uint32_t sourceDevice = 1; - SSKProtoEnvelopeType envelopeType = SSKProtoEnvelopeTypeCiphertext; - NSData *content = plaintextData; - - SSKProtoEnvelopeBuilder *envelopeBuilder = [SSKProtoEnvelope builderWithType:envelopeType timestamp:timestamp]; - [envelopeBuilder setSource:source]; - [envelopeBuilder setSourceDevice:sourceDevice]; - envelopeBuilder.content = content; - NSError *error; - NSData *_Nullable envelopeData = [envelopeBuilder buildSerializedDataAndReturnError:&error]; - if (error || !envelopeData) { - OWSFailDebug(@"Could not serialize envelope: %@.", error); - return; - } - - [OWSPrimaryStorage.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [SSKEnvironment.shared.batchMessageProcessor enqueueEnvelopeData:envelopeData - plaintextData:plaintextData - wasReceivedByUD:NO - transaction:transaction]; - }]; -} - -+ (void)performRandomActions:(NSUInteger)counter thread:(TSThread *)thread -{ - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.f * NSEC_PER_SEC)), - dispatch_get_main_queue(), - ^{ - [self performRandomActionInThread:thread counter:counter]; - if (counter > 0) { - [self performRandomActions:counter - 1 thread:thread]; - } - }); -} - -+ (void)performRandomActionInThread:(TSThread *)thread counter:(NSUInteger)counter -{ - typedef void (^TransactionBlock)(YapDatabaseReadWriteTransaction *transaction); - NSArray *actionBlocks = @[ - ^(YapDatabaseReadWriteTransaction *transaction) { - // injectIncomingMessageInThread doesn't take a transaction. - dispatch_async(dispatch_get_main_queue(), ^{ - [self injectIncomingMessageInThread:thread counter:counter]; - }); - }, - ^(YapDatabaseReadWriteTransaction *transaction) { - // sendTextMessageInThread doesn't take a transaction. - dispatch_async(dispatch_get_main_queue(), ^{ - [self sendTextMessageInThread:thread counter:counter]; - }); - }, - ^(YapDatabaseReadWriteTransaction *transaction) { - NSUInteger messageCount = (NSUInteger)(1 + arc4random_uniform(4)); - [self sendFakeMessages:messageCount thread:thread isTextOnly:NO transaction:transaction]; - }, - ^(YapDatabaseReadWriteTransaction *transaction) { - NSUInteger messageCount = (NSUInteger)(1 + arc4random_uniform(4)); - [self deleteRandomMessages:messageCount thread:thread transaction:transaction]; - }, - ^(YapDatabaseReadWriteTransaction *transaction) { - NSUInteger messageCount = (NSUInteger)(1 + arc4random_uniform(4)); - [self deleteLastMessages:messageCount thread:thread transaction:transaction]; - }, - ^(YapDatabaseReadWriteTransaction *transaction) { - NSUInteger messageCount = (NSUInteger)(1 + arc4random_uniform(4)); - [self deleteRandomRecentMessages:messageCount thread:thread transaction:transaction]; - }, - ^(YapDatabaseReadWriteTransaction *transaction) { - NSUInteger messageCount = (NSUInteger)(1 + arc4random_uniform(4)); - [self insertAndDeleteNewOutgoingMessages:messageCount thread:thread transaction:transaction]; - }, - ^(YapDatabaseReadWriteTransaction *transaction) { - NSUInteger messageCount = (NSUInteger)(1 + arc4random_uniform(4)); - [self resurrectNewOutgoingMessages1:messageCount thread:thread transaction:transaction]; - }, - ^(YapDatabaseReadWriteTransaction *transaction) { - NSUInteger messageCount = (NSUInteger)(1 + arc4random_uniform(4)); - [self resurrectNewOutgoingMessages2:messageCount thread:thread transaction:transaction]; - }, - ]; - [OWSPrimaryStorage.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - NSUInteger actionCount = 1 + (NSUInteger)arc4random_uniform(3); - for (NSUInteger actionIdx = 0; actionIdx < actionCount; actionIdx++) { - TransactionBlock actionBlock = actionBlocks[(NSUInteger)arc4random_uniform((uint32_t)actionBlocks.count)]; - actionBlock(transaction); - } - }]; -} - -+ (void)deleteRandomMessages:(NSUInteger)count - thread:(TSThread *)thread - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSLogInfo(@"deleteRandomMessages: %zd", count); - - YapDatabaseViewTransaction *interactionsByThread = [transaction ext:TSMessageDatabaseViewExtensionName]; - NSUInteger messageCount = [interactionsByThread numberOfItemsInGroup:thread.uniqueId]; - - NSMutableArray *messageIndices = [NSMutableArray new]; - for (NSUInteger messageIdx = 0; messageIdx < messageCount; messageIdx++) { - [messageIndices addObject:@(messageIdx)]; - } - NSMutableArray *interactions = [NSMutableArray new]; - for (NSUInteger i = 0; i < count && messageIndices.count > 0; i++) { - NSUInteger idx = (NSUInteger)arc4random_uniform((uint32_t)messageIndices.count); - NSNumber *messageIdx = messageIndices[idx]; - [messageIndices removeObjectAtIndex:idx]; - - TSInteraction *_Nullable interaction = - [interactionsByThread objectAtIndex:messageIdx.unsignedIntegerValue inGroup:thread.uniqueId]; - OWSAssertDebug(interaction); - [interactions addObject:interaction]; - } - - for (TSInteraction *interaction in interactions) { - [interaction removeWithTransaction:transaction]; - } -} - -+ (void)deleteLastMessages:(NSUInteger)count - thread:(TSThread *)thread - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSLogInfo(@"deleteLastMessages"); - - YapDatabaseViewTransaction *interactionsByThread = [transaction ext:TSMessageDatabaseViewExtensionName]; - NSUInteger messageCount = (NSUInteger)[interactionsByThread numberOfItemsInGroup:thread.uniqueId]; - - NSMutableArray *messageIndices = [NSMutableArray new]; - for (NSUInteger i = 0; i < count && i < messageCount; i++) { - NSUInteger messageIdx = messageCount - (1 + i); - [messageIndices addObject:@(messageIdx)]; - } - NSMutableArray *interactions = [NSMutableArray new]; - for (NSNumber *messageIdx in messageIndices) { - TSInteraction *_Nullable interaction = - [interactionsByThread objectAtIndex:messageIdx.unsignedIntegerValue inGroup:thread.uniqueId]; - OWSAssertDebug(interaction); - [interactions addObject:interaction]; - } - for (TSInteraction *interaction in interactions) { - [interaction removeWithTransaction:transaction]; - } -} - -+ (void)deleteRandomRecentMessages:(NSUInteger)count - thread:(TSThread *)thread - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSLogInfo(@"deleteRandomRecentMessages: %zd", count); - - YapDatabaseViewTransaction *interactionsByThread = [transaction ext:TSMessageDatabaseViewExtensionName]; - NSInteger messageCount = (NSInteger)[interactionsByThread numberOfItemsInGroup:thread.uniqueId]; - - NSMutableArray *messageIndices = [NSMutableArray new]; - const NSInteger kRecentMessageCount = 10; - for (NSInteger i = 0; i < kRecentMessageCount; i++) { - NSInteger messageIdx = messageCount - (1 + i); - if (messageIdx >= 0) { - [messageIndices addObject:@(messageIdx)]; - } - } - NSMutableArray *interactions = [NSMutableArray new]; - for (NSUInteger i = 0; i < count && messageIndices.count > 0; i++) { - NSUInteger idx = (NSUInteger)arc4random_uniform((uint32_t)messageIndices.count); - NSNumber *messageIdx = messageIndices[idx]; - [messageIndices removeObjectAtIndex:idx]; - - TSInteraction *_Nullable interaction = - [interactionsByThread objectAtIndex:messageIdx.unsignedIntegerValue inGroup:thread.uniqueId]; - OWSAssertDebug(interaction); - [interactions addObject:interaction]; - } - for (TSInteraction *interaction in interactions) { - [interaction removeWithTransaction:transaction]; - } -} - -+ (void)insertAndDeleteNewOutgoingMessages:(NSUInteger)count - thread:(TSThread *)thread - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSLogInfo(@"insertAndDeleteNewOutgoingMessages: %zd", count); - - NSMutableArray *messages = [NSMutableArray new]; - for (NSUInteger i =0; i < count; i++) { - NSString *text = [self randomText]; - OWSDisappearingMessagesConfiguration *configuration = - [OWSDisappearingMessagesConfiguration fetchObjectWithUniqueID:thread.uniqueId transaction:transaction]; - - uint32_t expiresInSeconds = (configuration.isEnabled ? configuration.durationSeconds : 0); - TSOutgoingMessage *message = [TSOutgoingMessage outgoingMessageInThread:thread - messageBody:text - attachmentId:nil - expiresInSeconds:expiresInSeconds]; - OWSLogError(@"insertAndDeleteNewOutgoingMessages timestamp: %llu.", message.timestamp); - [messages addObject:message]; - } - - for (TSOutgoingMessage *message in messages) { - [message saveWithTransaction:transaction]; - } - for (TSOutgoingMessage *message in messages) { - [message removeWithTransaction:transaction]; - } -} - -+ (void)resurrectNewOutgoingMessages1:(NSUInteger)count - thread:(TSThread *)thread - transaction:(YapDatabaseReadWriteTransaction *)initialTransaction -{ - OWSLogInfo(@"resurrectNewOutgoingMessages1.1: %zd", count); - - NSMutableArray *messages = [NSMutableArray new]; - for (NSUInteger i =0; i < count; i++) { - NSString *text = [self randomText]; - OWSDisappearingMessagesConfiguration *configuration = - [OWSDisappearingMessagesConfiguration fetchObjectWithUniqueID:thread.uniqueId - transaction:initialTransaction]; - - uint32_t expiresInSeconds = (configuration.isEnabled ? configuration.durationSeconds : 0); - TSOutgoingMessage *message = [TSOutgoingMessage outgoingMessageInThread:thread - messageBody:text - attachmentId:nil - expiresInSeconds:expiresInSeconds]; - OWSLogError(@"resurrectNewOutgoingMessages1 timestamp: %llu.", message.timestamp); - [messages addObject:message]; - } - - for (TSOutgoingMessage *message in messages) { - [message saveWithTransaction:initialTransaction]; - } - - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ - OWSLogInfo(@"resurrectNewOutgoingMessages1.2: %zd", count); - [OWSPrimaryStorage.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - for (TSOutgoingMessage *message in messages) { - [message removeWithTransaction:transaction]; - } - for (TSOutgoingMessage *message in messages) { - [message saveWithTransaction:transaction]; - } - }]; - }); -} - -+ (void)resurrectNewOutgoingMessages2:(NSUInteger)count - thread:(TSThread *)thread - transaction:(YapDatabaseReadWriteTransaction *)initialTransaction -{ - OWSLogInfo(@"resurrectNewOutgoingMessages2.1: %zd", count); - - NSMutableArray *messages = [NSMutableArray new]; - for (NSUInteger i =0; i < count; i++) { - NSString *text = [self randomText]; - OWSDisappearingMessagesConfiguration *configuration = - [OWSDisappearingMessagesConfiguration fetchObjectWithUniqueID:thread.uniqueId - transaction:initialTransaction]; - // MJK TODO - remove senderTimestamp - TSOutgoingMessage *message = [[TSOutgoingMessage alloc] - initOutgoingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp] - inThread:thread - messageBody:text - attachmentIds:[NSMutableArray new] - expiresInSeconds:(configuration.isEnabled ? configuration.durationSeconds - : 0)expireStartedAt:0 - isVoiceMessage:NO - groupMetaMessage:TSGroupMetaMessageUnspecified - quotedMessage:nil - contactShare:nil - linkPreview:nil]; - OWSLogError(@"resurrectNewOutgoingMessages2 timestamp: %llu.", message.timestamp); - [messages addObject:message]; - } - - for (TSOutgoingMessage *message in messages) { - [message updateWithFakeMessageState:TSOutgoingMessageStateSending transaction:initialTransaction]; - [message saveWithTransaction:initialTransaction]; - } - - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ - OWSLogInfo(@"resurrectNewOutgoingMessages2.2: %zd", count); - [OWSPrimaryStorage.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - for (TSOutgoingMessage *message in messages) { - [message removeWithTransaction:transaction]; - } - }]; - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ - OWSLogInfo(@"resurrectNewOutgoingMessages2.3: %zd", count); - [OWSPrimaryStorage.dbReadWriteConnection - readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - for (TSOutgoingMessage *message in messages) { - [message saveWithTransaction:transaction]; - } - }]; - }); - }); -} - -+ (void)createTimestampMessagesInThread:(TSThread *)thread -{ - OWSAssertDebug(thread); - - long long now = (long long)[NSDate ows_millisecondTimeStamp]; - NSArray *timestamps = @[ - @(now + 1 * (long long)kHourInMs), - @(now), - @(now - 1 * (long long)kHourInMs), - @(now - 12 * (long long)kHourInMs), - @(now - 1 * (long long)kDayInMs), - @(now - 2 * (long long)kDayInMs), - @(now - 3 * (long long)kDayInMs), - @(now - 6 * (long long)kDayInMs), - @(now - 7 * (long long)kDayInMs), - @(now - 8 * (long long)kDayInMs), - @(now - 2 * (long long)kWeekInMs), - @(now - 1 * (long long)kMonthInMs), - @(now - 2 * (long long)kMonthInMs), - ]; - NSMutableArray *recipientIds = [thread.recipientIdentifiers mutableCopy]; - [recipientIds removeObject:TSAccountManager.localNumber]; - NSString *recipientId = (recipientIds.count > 0 ? recipientIds.firstObject : @"+19174054215"); - - [OWSPrimaryStorage.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - for (NSNumber *timestamp in timestamps) { - NSString *randomText = [self randomText]; - { - // Legit usage of SenderTimestamp to backdate incoming sent messages for Debug - TSIncomingMessage *message = - [[TSIncomingMessage alloc] initIncomingMessageWithTimestamp:timestamp.unsignedLongLongValue - inThread:thread - authorId:recipientId - sourceDeviceId:0 - messageBody:randomText - attachmentIds:[NSMutableArray new] - expiresInSeconds:0 - quotedMessage:nil - contactShare:nil - linkPreview:nil - serverTimestamp:nil - wasReceivedByUD:NO]; - [message markAsReadNowWithSendReadReceipt:NO transaction:transaction]; - } - { - // MJK TODO - this might be the one place we actually use senderTimestamp - TSOutgoingMessage *message = - [[TSOutgoingMessage alloc] initOutgoingMessageWithTimestamp:timestamp.unsignedLongLongValue - inThread:thread - messageBody:randomText - attachmentIds:[NSMutableArray new] - expiresInSeconds:0 - expireStartedAt:0 - isVoiceMessage:NO - groupMetaMessage:TSGroupMetaMessageUnspecified - quotedMessage:nil - contactShare:nil - linkPreview:nil]; - [message saveWithTransaction:transaction]; - [message updateWithFakeMessageState:TSOutgoingMessageStateSent transaction:transaction]; - [message updateWithSentRecipient:recipientId wasSentByUD:NO transaction:transaction]; - [message updateWithDeliveredRecipient:recipientId deliveryTimestamp:timestamp transaction:transaction]; - [message updateWithReadRecipientId:recipientId - readTimestamp:timestamp.unsignedLongLongValue - transaction:transaction]; - } - } - }]; -} - -+ (void)createDisappearingMessagesWhichFailedToStartInThread:(TSThread *)thread -{ - uint64_t now = [NSDate ows_millisecondTimeStamp]; - - // MJK TODO - should be safe to remove this senderTimestamp - TSIncomingMessage *message = [[TSIncomingMessage alloc] - initIncomingMessageWithTimestamp:now - inThread:thread - authorId:thread.recipientIdentifiers.firstObject - sourceDeviceId:0 - messageBody:[NSString - stringWithFormat:@"Should disappear 60s after %lu", (unsigned long)now] - attachmentIds:[NSMutableArray new] - expiresInSeconds:60 - quotedMessage:nil - contactShare:nil - linkPreview:nil - serverTimestamp:nil - wasReceivedByUD:NO]; - // private setter to avoid starting expire machinery. - message.read = YES; - [message save]; -} - -+ (void)testLinkificationInThread:(TSThread *)thread -{ - NSArray *strings = @[@"google.com", - @"foo.google.com", - @"https://foo.google.com", - @"https://foo.google.com/some/path.html", - @"http://кц.com", - @"кц.com", - @"http://asĸ.com", - @"кц.рф", - @"кц.рф/some/path", - @"https://кц.рф/some/path", - @"http://foo.кц.рф"]; - - [OWSPrimaryStorage.sharedManager.dbReadWriteConnection - readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - for (NSString *string in strings) { - // DO NOT log these strings with the debugger attached. - // OWSLogInfo(@"%@", string); - - { - [self createFakeIncomingMessage:thread - messageBody:string - fakeAssetLoader:nil - isAttachmentDownloaded:NO - quotedMessage:nil - transaction:transaction]; - } - { - NSString *recipientId = @"+1323555555"; - NSString *groupName = string; - NSMutableArray *recipientIds = [@[ - recipientId, - TSAccountManager.localNumber, - ] mutableCopy]; - NSData *groupId = [Randomness generateRandomBytes:kGroupIdLength]; - // TODO: Figure out if this is correct - TSGroupModel *groupModel = - [[TSGroupModel alloc] initWithTitle:groupName memberIds:recipientIds image:nil groupId:groupId groupType:closedGroup adminIds:@[ TSAccountManager.localNumber ]]; - - TSGroupThread *groupThread = - [TSGroupThread getOrCreateThreadWithGroupModel:groupModel transaction:transaction]; - OWSAssertDebug(groupThread); - } - } - }]; -} - -+ (void)testIndicScriptsInThread:(TSThread *)thread -{ - NSArray *strings = @[ - @"\u0C1C\u0C4D\u0C1E\u200C\u0C3E", - @"\u09B8\u09CD\u09B0\u200C\u09C1", - @"non-crashing string", - ]; - - [OWSPrimaryStorage.sharedManager.dbReadWriteConnection - readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - for (NSString *string in strings) { - // DO NOT log these strings with the debugger attached. - // OWSLogInfo(@"%@", string); - - { - [self createFakeIncomingMessage:thread - messageBody:string - fakeAssetLoader:nil - isAttachmentDownloaded:NO - quotedMessage:nil - transaction:transaction]; - } - { - NSString *recipientId = @"+19174054215"; - NSString *groupName = string; - NSMutableArray *recipientIds = [@[ - recipientId, - TSAccountManager.localNumber, - ] mutableCopy]; - NSData *groupId = [Randomness generateRandomBytes:kGroupIdLength]; - // TODO: Figure out if this is correct - TSGroupModel *groupModel = - [[TSGroupModel alloc] initWithTitle:groupName memberIds:recipientIds image:nil groupId:groupId groupType:closedGroup adminIds:@[ TSAccountManager.localNumber ]]; - - TSGroupThread *groupThread = - [TSGroupThread getOrCreateThreadWithGroupModel:groupModel transaction:transaction]; - OWSAssertDebug(groupThread); - } - } - }]; -} - -+ (void)testZalgoTextInThread:(TSThread *)thread -{ - NSArray *strings = @[ - @"Ṱ̴̤̺̣͚͚̭̰̤̮̑̓̀͂͘͡h̵̢̤͔̼̗̦̖̬͌̀͒̀͘i̴̮̤͎͎̝̖̻͓̅̆͆̓̎͘͡ͅŝ̡̡̳͔̓͗̾̀̇͒͘͢͢͡͡ ỉ̛̲̩̫̝͉̀̒͐͋̾͘͢͡͞s̶̨̫̞̜̹͛́̇͑̅̒̊̈ s̵͍̲̗̠̗͈̦̬̉̿͂̏̐͆̾͐͊̾ǫ̶͍̼̝̉͊̉͢͜͞͝ͅͅṁ̵̡̨̬̤̝͔̣̄̍̋͊̿̄͋̈ͅe̪̪̻̱͖͚͈̲̍̃͘͠͝ z̷̢̢̛̩̦̱̺̼͑́̉̾ą͕͎̠̮̹̱̓̔̓̈̈́̅̐͢l̵̨͚̜͉̟̜͉͎̃͆͆͒͑̍̈̚͜͞ğ͔̖̫̞͎͍̒̂́̒̿̽̆͟o̶̢̬͚̘̤̪͇̻̒̋̇̊̏͢͡͡͠ͅ t̡̛̥̦̪̮̅̓̑̈́̉̓̽͛͢͡ȩ̡̩͓͈̩͎͗̔͑̌̓͊͆͝x̫̦͓̤͓̘̝̪͊̆͌͊̽̃̏͒͘͘͢ẗ̶̢̨̛̰̯͕͔́̐͗͌͟͠.̷̩̼̼̩̞̘̪́͗̅͊̎̾̅̏̀̕͟ͅ", - @"This is some normal text", - ]; - - [OWSPrimaryStorage.sharedManager.dbReadWriteConnection - readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - for (NSString *string in strings) { - OWSLogInfo(@"sending zalgo"); - - { - [self createFakeIncomingMessage:thread - messageBody:string - fakeAssetLoader:nil - isAttachmentDownloaded:NO - quotedMessage:nil - transaction:transaction]; - } - { - NSString *recipientId = @"+19174054215"; - NSString *groupName = string; - NSMutableArray *recipientIds = [@[ - recipientId, - TSAccountManager.localNumber, - ] mutableCopy]; - NSData *groupId = [Randomness generateRandomBytes:kGroupIdLength]; - // TODO: Figure out if this is correct - TSGroupModel *groupModel = - [[TSGroupModel alloc] initWithTitle:groupName memberIds:recipientIds image:nil groupId:groupId groupType:closedGroup adminIds:@[ TSAccountManager.localNumber ]]; - - TSGroupThread *groupThread = - [TSGroupThread getOrCreateThreadWithGroupModel:groupModel transaction:transaction]; - OWSAssertDebug(groupThread); - } - } - }]; -} - -+ (void)testDirectionalFilenamesInThread:(TSThread *)thread -{ - NSMutableArray *filenames = [@[ - @"a_test\u202Dabc.exe", - @"b_test\u202Eabc.exe", - @"c_testabc.exe", - ] mutableCopy]; - __block void (^sendUnsafeFile)(void); - sendUnsafeFile = ^{ - if (filenames.count < 1) { - return; - } - NSString *filename = filenames.lastObject; - [filenames removeLastObject]; - NSString *utiType = (NSString *)kUTTypeData; - const NSUInteger kDataLength = 32; - DataSource *_Nullable dataSource = - [DataSourceValue dataSourceWithData:[self createRandomNSDataOfSize:kDataLength] utiType:utiType]; - [dataSource setSourceFilename:filename]; - SignalAttachment *attachment = - [SignalAttachment attachmentWithDataSource:dataSource dataUTI:utiType imageQuality:TSImageQualityOriginal]; - - OWSAssertDebug(attachment); - if ([attachment hasError]) { - OWSLogError(@"attachment[%@]: %@", [attachment sourceFilename], [attachment errorName]); - [DDLog flushLog]; - } - OWSAssertDebug(![attachment hasError]); - [self sendAttachment:attachment thread:thread messageBody:nil]; - - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ - sendUnsafeFile(); - sendUnsafeFile = nil; - }); - }; -} - -+ (void)deleteAllMessagesInThread:(TSThread *)thread -{ - [OWSPrimaryStorage.sharedManager.newDatabaseConnection - readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [thread removeAllThreadInteractionsWithTransaction:transaction]; - }]; -} - -#pragma mark - Utility - -+ (NSString *)actionLabelForHasCaption:(BOOL)hasCaption - outgoingMessageState:(TSOutgoingMessageState)outgoingMessageState - isDelivered:(BOOL)isDelivered - isRead:(BOOL)isRead -{ - NSMutableString *label = [NSMutableString new]; - if (hasCaption) { - [label appendString:@" 🔤"]; - } - if (outgoingMessageState == TSOutgoingMessageStateFailed) { - [label appendString:@" (Unsent)"]; - } else if (outgoingMessageState == TSOutgoingMessageStateSending) { - [label appendString:@" (Sending)"]; - } else if (outgoingMessageState == TSOutgoingMessageStateSent) { - if (isRead) { - [label appendString:@" (Read)"]; - } else if (isDelivered) { - [label appendString:@" (Delivered)"]; - } else { - [label appendString:@" (Sent)"]; - } - } else { - OWSFailDebug(@"unknown message state."); - } - return label; -} - -+ (TSOutgoingMessage *)createFakeOutgoingMessage:(TSThread *)thread - messageBody:(nullable NSString *)messageBody - fakeAssetLoader:(nullable DebugUIMessagesAssetLoader *)fakeAssetLoader - messageState:(TSOutgoingMessageState)messageState - isDelivered:(BOOL)isDelivered - isRead:(BOOL)isRead - quotedMessage:(nullable TSQuotedMessage *)quotedMessage - contactShare:(nullable OWSContact *)contactShare - linkPreview:(nullable OWSLinkPreview *)linkPreview - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSAssertDebug(thread); - - // Seamlessly convert oversize text messages to oversize text attachments. - if ([messageBody lengthOfBytesUsingEncoding:NSUTF8StringEncoding] >= kOversizeTextMessageSizeThreshold) { - OWSAssertDebug(!fakeAssetLoader); - fakeAssetLoader = [DebugUIMessagesAssetLoader oversizeTextInstanceWithText:messageBody]; - messageBody = nil; - } - - TSAttachment *_Nullable attachment = nil; - if (fakeAssetLoader) { - attachment = [self createFakeAttachment:fakeAssetLoader isAttachmentDownloaded:YES transaction:transaction]; - } - - return [self createFakeOutgoingMessage:thread - messageBody:messageBody - attachmentId:attachment.uniqueId - filename:fakeAssetLoader.filename - messageState:messageState - isDelivered:isDelivered - isRead:isRead - isVoiceMessage:attachment.isVoiceMessage - quotedMessage:quotedMessage - contactShare:contactShare - linkPreview:linkPreview - transaction:transaction]; -} - -+ (TSOutgoingMessage *)createFakeOutgoingMessage:(TSThread *)thread - messageBody:(nullable NSString *)messageBody - attachmentId:(nullable NSString *)attachmentId - filename:(nullable NSString *)filename - messageState:(TSOutgoingMessageState)messageState - isDelivered:(BOOL)isDelivered - isRead:(BOOL)isRead - isVoiceMessage:(BOOL)isVoiceMessage - quotedMessage:(nullable TSQuotedMessage *)quotedMessage - contactShare:(nullable OWSContact *)contactShare - linkPreview:(nullable OWSLinkPreview *)linkPreview - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSAssertDebug(thread); - OWSAssertDebug(transaction); - OWSAssertDebug(messageBody.length > 0 || attachmentId.length > 0 || contactShare); - - NSMutableArray *attachmentIds = [NSMutableArray new]; - if (attachmentId) { - [attachmentIds addObject:attachmentId]; - } - - // MJK TODO - remove senderTimestamp - TSOutgoingMessage *message = - [[TSOutgoingMessage alloc] initOutgoingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp] - inThread:thread - messageBody:messageBody - attachmentIds:attachmentIds - expiresInSeconds:0 - expireStartedAt:0 - isVoiceMessage:isVoiceMessage - groupMetaMessage:TSGroupMetaMessageUnspecified - quotedMessage:quotedMessage - contactShare:contactShare - linkPreview:linkPreview]; - - if (attachmentId.length > 0 && filename.length > 0) { - message.attachmentFilenameMap[attachmentId] = filename; - } - - [message saveWithTransaction:transaction]; - [message updateWithFakeMessageState:messageState transaction:transaction]; - if (isDelivered) { - NSString *_Nullable recipientId = thread.recipientIdentifiers.lastObject; - OWSAssertDebug(recipientId.length > 0); - [message updateWithDeliveredRecipient:recipientId - deliveryTimestamp:@([NSDate ows_millisecondTimeStamp]) - transaction:transaction]; - } - if (isRead) { - NSString *_Nullable recipientId = thread.recipientIdentifiers.lastObject; - OWSAssertDebug(recipientId.length > 0); - [message updateWithReadRecipientId:recipientId - readTimestamp:[NSDate ows_millisecondTimeStamp] - transaction:transaction]; - } - return message; -} - -+ (TSIncomingMessage *)createFakeIncomingMessage:(TSThread *)thread - messageBody:(nullable NSString *)messageBody - fakeAssetLoader:(nullable DebugUIMessagesAssetLoader *)fakeAssetLoader - isAttachmentDownloaded:(BOOL)isAttachmentDownloaded - quotedMessage:(nullable TSQuotedMessage *)quotedMessage - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSAssertDebug(thread); - - // Seamlessly convert oversize text messages to oversize text attachments. - if ([messageBody lengthOfBytesUsingEncoding:NSUTF8StringEncoding] >= kOversizeTextMessageSizeThreshold) { - OWSAssertDebug(!fakeAssetLoader); - fakeAssetLoader = [DebugUIMessagesAssetLoader oversizeTextInstanceWithText:messageBody]; - messageBody = nil; - } - - TSAttachment *_Nullable attachment = nil; - if (fakeAssetLoader) { - attachment = [self createFakeAttachment:fakeAssetLoader - isAttachmentDownloaded:isAttachmentDownloaded - transaction:transaction]; - } - - return [self createFakeIncomingMessage:thread - messageBody:messageBody - attachmentId:attachment.uniqueId - filename:fakeAssetLoader.filename - isAttachmentDownloaded:isAttachmentDownloaded - quotedMessage:quotedMessage - transaction:transaction]; -} - -+ (TSIncomingMessage *)createFakeIncomingMessage:(TSThread *)thread - messageBody:(nullable NSString *)messageBody - attachmentId:(nullable NSString *)attachmentId - filename:(nullable NSString *)filename - isAttachmentDownloaded:(BOOL)isAttachmentDownloaded - quotedMessage:(nullable TSQuotedMessage *)quotedMessage - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSAssertDebug(thread); - OWSAssertDebug(transaction); - OWSAssertDebug(messageBody.length > 0 || attachmentId.length > 0); - - NSMutableArray *attachmentIds = [NSMutableArray new]; - if (attachmentId) { - [attachmentIds addObject:attachmentId]; - } - - // // Random time within last n years. Helpful for filling out a media gallery over time. - // double yearsMillis = 4.0 * kYearsInMs; - // uint64_t millisAgo = (uint64_t)(((double)arc4random() / ((double)0xffffffff)) * yearsMillis); - // uint64_t timestamp = [NSDate ows_millisecondTimeStamp] - millisAgo; - - // MJK TODO - should be safe to remove this senderTimestamp - TSIncomingMessage *message = - [[TSIncomingMessage alloc] initIncomingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp] - inThread:thread - authorId:@"+19174054215" - sourceDeviceId:0 - messageBody:messageBody - attachmentIds:attachmentIds - expiresInSeconds:0 - quotedMessage:quotedMessage - contactShare:nil - linkPreview:nil - serverTimestamp:nil - wasReceivedByUD:NO]; - [message markAsReadNowWithSendReadReceipt:NO transaction:transaction]; - return message; -} - -+ (TSAttachment *)createFakeAttachment:(DebugUIMessagesAssetLoader *)fakeAssetLoader - isAttachmentDownloaded:(BOOL)isAttachmentDownloaded - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSAssertDebug(fakeAssetLoader); - OWSAssertDebug(fakeAssetLoader.filePath); - OWSAssertDebug(transaction); - - if (isAttachmentDownloaded) { - DataSource *dataSource = - [DataSourcePath dataSourceWithFilePath:fakeAssetLoader.filePath shouldDeleteOnDeallocation:NO]; - NSString *filename = dataSource.sourceFilename; - // To support "fake missing" attachments, we sometimes lie about the - // length of the data. - UInt32 nominalDataLength = (UInt32)MAX((NSUInteger)1, dataSource.dataLength); - TSAttachmentStream *attachmentStream = [[TSAttachmentStream alloc] initWithContentType:fakeAssetLoader.mimeType - byteCount:nominalDataLength - sourceFilename:filename - caption:nil - albumMessageId:nil]; - NSError *error; - BOOL success = [attachmentStream writeData:dataSource.data error:&error]; - OWSAssertDebug(success && !error); - [attachmentStream saveWithTransaction:transaction]; - return attachmentStream; - } else { - UInt32 filesize = 64; - TSAttachmentPointer *attachmentPointer = - [[TSAttachmentPointer alloc] initWithServerId:237391539706350548 - key:[self createRandomNSDataOfSize:filesize] - digest:nil - byteCount:filesize - contentType:fakeAssetLoader.mimeType - sourceFilename:fakeAssetLoader.filename - caption:nil - albumMessageId:nil - attachmentType:TSAttachmentTypeDefault - mediaSize:CGSizeZero]; - attachmentPointer.state = TSAttachmentPointerStateFailed; - [attachmentPointer saveWithTransaction:transaction]; - return attachmentPointer; - } -} - -+ (void)sendMediaAlbumInThread:(TSThread *)thread -{ - OWSLogInfo(@""); - - const uint32_t kMinImageCount = 2; - const uint32_t kMaxImageCount = 10; - uint32_t imageCount = kMinImageCount + arc4random_uniform(kMaxImageCount - kMinImageCount); - NSString *_Nullable messageBody = (arc4random_uniform(2) > 0 ? @"This is the media gallery title..." : nil); - [self sendMediaAlbumInThread:thread imageCount:imageCount messageBody:messageBody]; -} - -+ (void)sendExemplaryMediaGalleriesInThread:(TSThread *)thread -{ - OWSLogInfo(@""); - - [self sendMediaAlbumInThread:thread imageCount:2 messageBody:nil]; - [self sendMediaAlbumInThread:thread imageCount:3 messageBody:nil]; - [self sendMediaAlbumInThread:thread imageCount:4 messageBody:nil]; - [self sendMediaAlbumInThread:thread imageCount:5 messageBody:nil]; - [self sendMediaAlbumInThread:thread imageCount:6 messageBody:nil]; - [self sendMediaAlbumInThread:thread imageCount:7 messageBody:nil]; - NSString *messageBody = @"This is the media gallery title..."; - [self sendMediaAlbumInThread:thread imageCount:2 messageBody:messageBody]; - [self sendMediaAlbumInThread:thread imageCount:3 messageBody:messageBody]; - [self sendMediaAlbumInThread:thread imageCount:4 messageBody:messageBody]; - [self sendMediaAlbumInThread:thread imageCount:5 messageBody:messageBody]; - [self sendMediaAlbumInThread:thread imageCount:6 messageBody:messageBody]; - [self sendMediaAlbumInThread:thread imageCount:7 messageBody:messageBody]; -} - -+ (void)sendMediaAlbumInThread:(TSThread *)thread - imageCount:(uint32_t)imageCount - messageBody:(nullable NSString *)messageBody - fakeAssetLoaders:(NSArray *)fakeAssetLoaders -{ - OWSAssertDebug(imageCount > 0); - OWSLogInfo(@""); - - NSMutableArray *attachments = [NSMutableArray new]; - for (uint32_t i = 0; i < imageCount; i++) { - DebugUIMessagesAssetLoader *fakeAssetLoader - = fakeAssetLoaders[arc4random_uniform((uint32_t)fakeAssetLoaders.count)]; - OWSAssertDebug([NSFileManager.defaultManager fileExistsAtPath:fakeAssetLoader.filePath]); - DataSource *dataSource = - [DataSourcePath dataSourceWithFilePath:fakeAssetLoader.filePath shouldDeleteOnDeallocation:NO]; - SignalAttachment *attachment = - [SignalAttachment attachmentWithDataSource:dataSource - dataUTI:[MIMETypeUtil utiTypeForMIMEType:fakeAssetLoader.mimeType] - imageQuality:TSImageQualityOriginal]; - if (arc4random_uniform(2) == 0) { - attachment.captionText = [self randomText]; - } - [attachments addObject:attachment]; - } - - [self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - TSOutgoingMessage *message = [ThreadUtil enqueueMessageWithText:messageBody - mediaAttachments:attachments - inThread:thread - quotedReplyModel:nil - linkPreviewDraft:nil - transaction:transaction]; - OWSLogDebug(@"timestamp: %llu.", message.timestamp); - }]; -} - -+ (void)sendMediaAlbumInThread:(TSThread *)thread - imageCount:(uint32_t)imageCount - messageBody:(nullable NSString *)messageBody -{ - OWSAssertDebug(thread); - - NSArray *fakeAssetLoaders = @[ - [DebugUIMessagesAssetLoader jpegInstance], - [DebugUIMessagesAssetLoader largePngInstance], - [DebugUIMessagesAssetLoader tinyPngInstance], - [DebugUIMessagesAssetLoader gifInstance], - [DebugUIMessagesAssetLoader mp4Instance], - ]; - [DebugUIMessagesAssetLoader prepareAssetLoaders:fakeAssetLoaders - success:^{ - [self sendMediaAlbumInThread:thread - imageCount:imageCount - messageBody:messageBody - fakeAssetLoaders:fakeAssetLoaders]; - } - failure:^{ - OWSLogError(@"Could not prepare fake asset loaders."); - }]; -} - -#endif - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/src/ViewControllers/DebugUI/DebugUIMessagesAction.h b/Session/src/ViewControllers/DebugUI/DebugUIMessagesAction.h deleted file mode 100644 index 44f69c54f..000000000 --- a/Session/src/ViewControllers/DebugUI/DebugUIMessagesAction.h +++ /dev/null @@ -1,62 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "DebugUIMessagesUtils.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface DebugUIMessagesAction : NSObject - -@property (nonatomic) NSString *label; - -- (void)prepareAndPerformNTimes:(NSUInteger)count; - -@end - -#pragma mark - - -@interface DebugUIMessagesSingleAction : DebugUIMessagesAction - -+ (DebugUIMessagesAction *)actionWithLabel:(NSString *)label - staggeredActionBlock:(StaggeredActionBlock)staggeredActionBlock; - -+ (DebugUIMessagesAction *)actionWithLabel:(NSString *)label - unstaggeredActionBlock:(UnstaggeredActionBlock)unstaggeredActionBlock; - -+ (DebugUIMessagesAction *)actionWithLabel:(NSString *)label - staggeredActionBlock:(StaggeredActionBlock)staggeredActionBlock - prepareBlock:(ActionPrepareBlock)prepareBlock; - -+ (DebugUIMessagesAction *)actionWithLabel:(NSString *)label - unstaggeredActionBlock:(UnstaggeredActionBlock)unstaggeredActionBlock - prepareBlock:(ActionPrepareBlock)prepareBlock; - -@end - -#pragma mark - - -typedef NS_ENUM(NSUInteger, SubactionMode) { - SubactionMode_Random = 0, - SubactionMode_Ordered, -}; - -@interface DebugUIMessagesGroupAction : DebugUIMessagesAction - -@property (nonatomic, readonly) SubactionMode subactionMode; -@property (nonatomic, readonly, nullable) NSArray *subactions; - -// Given a group of subactions, perform a single random subaction each time. -+ (DebugUIMessagesAction *)randomGroupActionWithLabel:(NSString *)label - subactions:(NSArray *)subactions; - -// Given a group of subactions, perform the subactions in order. -// -// If prepareAndPerformNTimes: is called with count == subactions.count, all of the subactions -// are performed exactly once. -+ (DebugUIMessagesAction *)allGroupActionWithLabel:(NSString *)label - subactions:(NSArray *)subactions; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/src/ViewControllers/DebugUI/DebugUIMessagesAction.m b/Session/src/ViewControllers/DebugUI/DebugUIMessagesAction.m deleted file mode 100644 index 6aaaadc59..000000000 --- a/Session/src/ViewControllers/DebugUI/DebugUIMessagesAction.m +++ /dev/null @@ -1,288 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "DebugUIMessagesAction.h" -#import - -NS_ASSUME_NONNULL_BEGIN - -@class DebugUIMessagesSingleAction; - -@interface DebugUIMessagesAction () - -@end - -#pragma mark - - -@interface DebugUIMessagesSingleAction () - -@property (nonatomic, nullable) ActionPrepareBlock prepareBlock; - -// "Single" actions should have exactly one "staggered" or "unstaggered" action block. -@property (nonatomic, nullable) StaggeredActionBlock staggeredActionBlock; -@property (nonatomic, nullable) UnstaggeredActionBlock unstaggeredActionBlock; - -@end - -#pragma mark - - -@implementation DebugUIMessagesAction - -- (DebugUIMessagesSingleAction *)nextActionToPerform -{ - return (DebugUIMessagesSingleAction *)self; -} - -- (void)prepare:(ActionSuccessBlock)success failure:(ActionFailureBlock)failure -{ - OWSAssertDebug(success); - OWSAssertDebug(failure); - - OWSAbstractMethod(); - - success(); -} - -- (void)prepareAndPerformNTimes:(NSUInteger)count -{ - OWSLogInfo(@"%@ prepareAndPerformNTimes: %zd", self.label, count); - [DDLog flushLog]; - - [self prepare:^{ - [self performNTimes:count - success:^{ - } - failure:^{ - }]; - } - failure:^{ - }]; -} - -- (void)performNTimes:(NSUInteger)countParam success:(ActionSuccessBlock)success failure:(ActionFailureBlock)failure -{ - OWSAssertDebug(success); - OWSAssertDebug(failure); - - OWSLogInfo(@"%@ performNTimes: %zd", self.label, countParam); - [DDLog flushLog]; - - if (countParam < 1) { - success(); - return; - } - - __block NSUInteger count = countParam; - [OWSPrimaryStorage.sharedManager.newDatabaseConnection readWriteWithBlock:^( - YapDatabaseReadWriteTransaction *transaction) { - NSUInteger batchSize = 0; - while (count > 0) { - NSUInteger index = count; - - DebugUIMessagesSingleAction *action = [self nextActionToPerform]; - OWSAssertDebug([action isKindOfClass:[DebugUIMessagesSingleAction class]]); - - if (action.staggeredActionBlock) { - OWSAssertDebug(!action.unstaggeredActionBlock); - action.staggeredActionBlock(index, - transaction, - ^{ - dispatch_after( - dispatch_time(DISPATCH_TIME_NOW, (int64_t)1.f * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ - OWSLogInfo(@"%@ performNTimes success: %zd", self.label, count); - [self performNTimes:count - 1 success:success failure:failure]; - }); - }, - failure); - - break; - } else { - OWSAssertDebug(action.unstaggeredActionBlock); - - // TODO: We could check result for failure. - action.unstaggeredActionBlock(index, transaction); - - const NSUInteger kMaxBatchSize = 2500; - batchSize++; - if (batchSize >= kMaxBatchSize) { - dispatch_after( - dispatch_time(DISPATCH_TIME_NOW, (int64_t)1.f * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ - OWSLogInfo(@"%@ performNTimes success: %zd", self.label, count); - [self performNTimes:count - 1 success:success failure:failure]; - }); - - break; - } - count--; - } - } - }]; -} - -@end - -#pragma mark - - -@implementation DebugUIMessagesSingleAction - -+ (DebugUIMessagesAction *)actionWithLabel:(NSString *)label - staggeredActionBlock:(StaggeredActionBlock)staggeredActionBlock -{ - OWSAssertDebug(label.length > 0); - OWSAssertDebug(staggeredActionBlock); - - DebugUIMessagesSingleAction *instance = [DebugUIMessagesSingleAction new]; - instance.label = label; - instance.staggeredActionBlock = staggeredActionBlock; - return instance; -} - -+ (DebugUIMessagesAction *)actionWithLabel:(NSString *)label - unstaggeredActionBlock:(UnstaggeredActionBlock)unstaggeredActionBlock -{ - OWSAssertDebug(label.length > 0); - OWSAssertDebug(unstaggeredActionBlock); - - DebugUIMessagesSingleAction *instance = [DebugUIMessagesSingleAction new]; - instance.label = label; - instance.unstaggeredActionBlock = unstaggeredActionBlock; - return instance; -} - -+ (DebugUIMessagesAction *)actionWithLabel:(NSString *)label - staggeredActionBlock:(StaggeredActionBlock)staggeredActionBlock - prepareBlock:(ActionPrepareBlock)prepareBlock -{ - OWSAssertDebug(label.length > 0); - OWSAssertDebug(staggeredActionBlock); - OWSAssertDebug(prepareBlock); - - DebugUIMessagesSingleAction *instance = [DebugUIMessagesSingleAction new]; - instance.label = label; - instance.staggeredActionBlock = staggeredActionBlock; - instance.prepareBlock = prepareBlock; - return instance; -} - -+ (DebugUIMessagesAction *)actionWithLabel:(NSString *)label - unstaggeredActionBlock:(UnstaggeredActionBlock)unstaggeredActionBlock - prepareBlock:(ActionPrepareBlock)prepareBlock -{ - OWSAssertDebug(label.length > 0); - OWSAssertDebug(unstaggeredActionBlock); - OWSAssertDebug(prepareBlock); - - DebugUIMessagesSingleAction *instance = [DebugUIMessagesSingleAction new]; - instance.label = label; - instance.unstaggeredActionBlock = unstaggeredActionBlock; - instance.prepareBlock = prepareBlock; - return instance; -} - -- (void)prepare:(ActionSuccessBlock)success failure:(ActionFailureBlock)failure -{ - OWSAssertDebug(success); - OWSAssertDebug(failure); - - if (self.prepareBlock) { - self.prepareBlock(success, failure); - } else { - success(); - } -} - -@end - -#pragma mark - - -@interface DebugUIMessagesGroupAction () - -@property (nonatomic) SubactionMode subactionMode; -@property (nonatomic, nullable) NSArray *subactions; -@property (nonatomic) NSUInteger subactionIndex; - -@end - -#pragma mark - - -@implementation DebugUIMessagesGroupAction - -- (DebugUIMessagesSingleAction *)nextActionToPerform -{ - OWSAssertDebug(self.subactions.count > 0); - - switch (self.subactionMode) { - case SubactionMode_Random: { - DebugUIMessagesAction *subaction = self.subactions[arc4random_uniform((uint32_t)self.subactions.count)]; - OWSAssertDebug(subaction); - return subaction.nextActionToPerform; - } - case SubactionMode_Ordered: { - DebugUIMessagesAction *subaction = self.subactions[self.subactionIndex]; - OWSAssertDebug(subaction); - self.subactionIndex = (self.subactionIndex + 1) % self.subactions.count; - return subaction.nextActionToPerform; - } - } -} - -- (void)prepare:(ActionSuccessBlock)success failure:(ActionFailureBlock)failure -{ - OWSAssertDebug(success); - OWSAssertDebug(failure); - - [DebugUIMessagesGroupAction prepareSubactions:[self.subactions mutableCopy] success:success failure:failure]; -} - -+ (void)prepareSubactions:(NSMutableArray *)unpreparedSubactions - success:(ActionSuccessBlock)success - failure:(ActionFailureBlock)failure -{ - OWSAssertDebug(success); - OWSAssertDebug(failure); - - if (unpreparedSubactions.count < 1) { - return success(); - } - - DebugUIMessagesAction *nextAction = unpreparedSubactions.lastObject; - [unpreparedSubactions removeLastObject]; - OWSLogInfo(@"preparing: %@", nextAction.label); - [DDLog flushLog]; - [nextAction prepare:^{ - [self prepareSubactions:unpreparedSubactions success:success failure:failure]; - } - failure:^{ - }]; -} - -+ (DebugUIMessagesAction *)randomGroupActionWithLabel:(NSString *)label - subactions:(NSArray *)subactions -{ - OWSAssertDebug(label.length > 0); - OWSAssertDebug(subactions.count > 0); - - DebugUIMessagesGroupAction *instance = [DebugUIMessagesGroupAction new]; - instance.label = label; - instance.subactions = subactions; - instance.subactionMode = SubactionMode_Random; - return instance; -} - -+ (DebugUIMessagesAction *)allGroupActionWithLabel:(NSString *)label - subactions:(NSArray *)subactions -{ - OWSAssertDebug(label.length > 0); - OWSAssertDebug(subactions.count > 0); - - DebugUIMessagesGroupAction *instance = [DebugUIMessagesGroupAction new]; - instance.label = label; - instance.subactions = subactions; - instance.subactionMode = SubactionMode_Ordered; - return instance; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/src/ViewControllers/DebugUI/DebugUIMessagesAssetLoader.h b/Session/src/ViewControllers/DebugUI/DebugUIMessagesAssetLoader.h deleted file mode 100644 index ff3ba42f4..000000000 --- a/Session/src/ViewControllers/DebugUI/DebugUIMessagesAssetLoader.h +++ /dev/null @@ -1,52 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "DebugUIMessagesUtils.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface DebugUIMessagesAssetLoader : NSObject - -@property (nonatomic) NSString *filename; -@property (nonatomic) NSString *mimeType; - -@property (nonatomic) ActionPrepareBlock prepareBlock; - -@property (nonatomic, nullable) NSString *filePath; - -- (NSString *)labelEmoji; - -#pragma mark - - -+ (instancetype)jpegInstance; -+ (instancetype)gifInstance; -+ (instancetype)largeGifInstance; -+ (instancetype)mp3Instance; -+ (instancetype)mp4Instance; -+ (instancetype)compactPortraitPngInstance; -+ (instancetype)compactLandscapePngInstance; -+ (instancetype)tallPortraitPngInstance; -+ (instancetype)wideLandscapePngInstance; -+ (instancetype)largePngInstance; -+ (instancetype)tinyPngInstance; -+ (instancetype)pngInstanceWithSize:(CGSize)size - backgroundColor:(UIColor *)backgroundColor - textColor:(UIColor *)textColor - label:(NSString *)label; -+ (instancetype)tinyPdfInstance; -+ (instancetype)largePdfInstance; -+ (instancetype)missingPngInstance; -+ (instancetype)missingPdfInstance; -+ (instancetype)oversizeTextInstance; -+ (instancetype)oversizeTextInstanceWithText:(NSString *)text; - -#pragma mark - - -+ (void)prepareAssetLoaders:(NSArray *)assetLoaders - success:(dispatch_block_t)success - failure:(dispatch_block_t)failure; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/src/ViewControllers/DebugUI/DebugUIMessagesAssetLoader.m b/Session/src/ViewControllers/DebugUI/DebugUIMessagesAssetLoader.m deleted file mode 100644 index ac01a2aa9..000000000 --- a/Session/src/ViewControllers/DebugUI/DebugUIMessagesAssetLoader.m +++ /dev/null @@ -1,628 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "DebugUIMessagesAssetLoader.h" -#import -#import -#import -#import -#import -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@implementation DebugUIMessagesAssetLoader - -- (NSString *)labelEmoji -{ - return [TSAttachment emojiForMimeType:self.mimeType]; -} - -+ (DebugUIMessagesAssetLoader *)fakeAssetLoaderWithUrl:(NSString *)fileUrl mimeType:(NSString *)mimeType -{ - OWSAssertDebug(fileUrl.length > 0); - OWSAssertDebug(mimeType.length > 0); - - DebugUIMessagesAssetLoader *instance = [DebugUIMessagesAssetLoader new]; - instance.mimeType = mimeType; - instance.filename = [NSURL URLWithString:fileUrl].lastPathComponent; - __weak DebugUIMessagesAssetLoader *weakSelf = instance; - instance.prepareBlock = ^(ActionSuccessBlock success, ActionFailureBlock failure) { - [weakSelf ensureURLAssetLoaded:fileUrl success:success failure:failure]; - }; - return instance; -} - -- (void)ensureURLAssetLoaded:(NSString *)fileUrl success:(ActionSuccessBlock)success failure:(ActionFailureBlock)failure -{ - OWSAssertDebug(success); - OWSAssertDebug(failure); - OWSAssertDebug(self.filename.length > 0); - OWSAssertDebug(self.mimeType.length > 0); - - if (self.filePath) { - success(); - return; - } - - // Use a predictable file path so that we reuse the cache between app launches. - NSString *temporaryDirectory = OWSTemporaryDirectory(); - NSString *cacheDirectory = [temporaryDirectory stringByAppendingPathComponent:@"cached_random_files"]; - [OWSFileSystem ensureDirectoryExists:cacheDirectory]; - NSString *filePath = [cacheDirectory stringByAppendingPathComponent:self.filename]; - if ([NSFileManager.defaultManager fileExistsAtPath:filePath]) { - self.filePath = filePath; - return success(); - } - - NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; - AFHTTPSessionManager *sessionManager = [[AFHTTPSessionManager alloc] initWithSessionConfiguration:configuration]; - sessionManager.responseSerializer = [AFHTTPResponseSerializer serializer]; - OWSAssertDebug(sessionManager.responseSerializer); - [sessionManager GET:fileUrl - parameters:nil - progress:nil - success:^(NSURLSessionDataTask *task, NSData *_Nullable responseObject) { - if ([responseObject writeToFile:filePath atomically:YES]) { - self.filePath = filePath; - OWSAssertDebug([NSFileManager.defaultManager fileExistsAtPath:filePath]); - success(); - } else { - OWSFailDebug(@"Error write url response [%@]: %@", fileUrl, filePath); - failure(); - } - } - failure:^(NSURLSessionDataTask *_Nullable task, NSError *requestError) { - OWSFailDebug(@"Error downloading url[%@]: %@", fileUrl, requestError); - failure(); - }]; -} - -#pragma mark - - -+ (DebugUIMessagesAssetLoader *)fakePngAssetLoaderWithImageSize:(CGSize)imageSize - backgroundColor:(UIColor *)backgroundColor - textColor:(UIColor *)textColor - label:(NSString *)label -{ - OWSAssertDebug(imageSize.width > 0); - OWSAssertDebug(imageSize.height > 0); - OWSAssertDebug(backgroundColor); - OWSAssertDebug(textColor); - OWSAssertDebug(label.length > 0); - - DebugUIMessagesAssetLoader *instance = [DebugUIMessagesAssetLoader new]; - instance.mimeType = OWSMimeTypeImagePng; - instance.filename = @"image.png"; - __weak DebugUIMessagesAssetLoader *weakSelf = instance; - instance.prepareBlock = ^(ActionSuccessBlock success, ActionFailureBlock failure) { - [weakSelf ensurePngAssetLoaded:imageSize - backgroundColor:backgroundColor - textColor:textColor - label:label - success:success - failure:failure]; - }; - return instance; -} - -- (void)ensurePngAssetLoaded:(CGSize)imageSize - backgroundColor:(UIColor *)backgroundColor - textColor:(UIColor *)textColor - label:(NSString *)label - success:(ActionSuccessBlock)success - failure:(ActionFailureBlock)failure -{ - OWSAssertDebug(success); - OWSAssertDebug(failure); - OWSAssertDebug(self.filename.length > 0); - OWSAssertDebug(self.mimeType.length > 0); - OWSAssertDebug(imageSize.width > 0 && imageSize.height > 0); - OWSAssertDebug(backgroundColor); - OWSAssertDebug(textColor); - OWSAssertDebug(label.length > 0); - - if (self.filePath) { - success(); - return; - } - - @autoreleasepool { - NSString *filePath = [OWSFileSystem temporaryFilePathWithFileExtension:@"png"]; - UIImage *image = - [self createRandomPngWithSize:imageSize backgroundColor:backgroundColor textColor:textColor label:label]; - NSData *pngData = UIImagePNGRepresentation(image); - [pngData writeToFile:filePath atomically:YES]; - self.filePath = filePath; - OWSAssertDebug([NSFileManager.defaultManager fileExistsAtPath:filePath]); - success(); - } -} - -- (nullable UIImage *)createRandomPngWithSize:(CGSize)imageSize - backgroundColor:(UIColor *)backgroundColor - textColor:(UIColor *)textColor - label:(NSString *)label -{ - OWSAssertDebug(imageSize.width > 0 && imageSize.height > 0); - OWSAssertDebug(backgroundColor); - OWSAssertDebug(textColor); - OWSAssertDebug(label.length > 0); - - @autoreleasepool { - imageSize.width /= UIScreen.mainScreen.scale; - imageSize.height /= UIScreen.mainScreen.scale; - - CGRect frame = CGRectZero; - frame.size = imageSize; - CGFloat smallDimension = MIN(imageSize.width, imageSize.height); - UIFont *font = [UIFont boldSystemFontOfSize:smallDimension * 0.5f]; - NSDictionary *textAttributes = @{ NSFontAttributeName : font, NSForegroundColorAttributeName : textColor }; - - CGRect textFrame = - [label boundingRectWithSize:frame.size - options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading) - attributes:textAttributes - context:nil]; - - UIGraphicsBeginImageContextWithOptions(frame.size, NO, [UIScreen mainScreen].scale); - CGContextRef context = UIGraphicsGetCurrentContext(); - - CGContextSetFillColorWithColor(context, backgroundColor.CGColor); - CGContextFillRect(context, frame); - [label drawAtPoint:CGPointMake(CGRectGetMidX(frame) - CGRectGetMidX(textFrame), - CGRectGetMidY(frame) - CGRectGetMidY(textFrame)) - withAttributes:textAttributes]; - - UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - - return image; - } -} - -#pragma mark - - -+ (DebugUIMessagesAssetLoader *)fakeRandomAssetLoaderWithLength:(NSUInteger)dataLength mimeType:(NSString *)mimeType -{ - OWSAssertDebug(dataLength > 0); - OWSAssertDebug(mimeType.length > 0); - - DebugUIMessagesAssetLoader *instance = [DebugUIMessagesAssetLoader new]; - instance.mimeType = mimeType; - NSString *fileExtension = [MIMETypeUtil fileExtensionForMIMEType:mimeType]; - OWSAssertDebug(fileExtension.length > 0); - instance.filename = [@"attachment" stringByAppendingPathExtension:fileExtension]; - __weak DebugUIMessagesAssetLoader *weakSelf = instance; - instance.prepareBlock = ^(ActionSuccessBlock success, ActionFailureBlock failure) { - [weakSelf ensureRandomAssetLoaded:dataLength success:success failure:failure]; - }; - return instance; -} - -- (void)ensureRandomAssetLoaded:(NSUInteger)dataLength - success:(ActionSuccessBlock)success - failure:(ActionFailureBlock)failure -{ - OWSAssertDebug(dataLength > 0); - OWSAssertDebug(dataLength < INT_MAX); - OWSAssertDebug(success); - OWSAssertDebug(failure); - OWSAssertDebug(self.filename.length > 0); - OWSAssertDebug(self.mimeType.length > 0); - - if (self.filePath) { - success(); - return; - } - - @autoreleasepool { - NSString *fileExtension = [MIMETypeUtil fileExtensionForMIMEType:self.mimeType]; - OWSAssertDebug(fileExtension.length > 0); - NSData *data = [Randomness generateRandomBytes:(int)dataLength]; - OWSAssertDebug(data); - NSString *filePath = [OWSFileSystem temporaryFilePathWithFileExtension:fileExtension]; - BOOL didWrite = [data writeToFile:filePath atomically:YES]; - OWSAssertDebug(didWrite); - self.filePath = filePath; - OWSAssertDebug([NSFileManager.defaultManager fileExistsAtPath:filePath]); - } - - success(); -} - -#pragma mark - - -+ (DebugUIMessagesAssetLoader *)fakeMissingAssetLoaderWithMimeType:(NSString *)mimeType -{ - OWSAssertDebug(mimeType.length > 0); - - DebugUIMessagesAssetLoader *instance = [DebugUIMessagesAssetLoader new]; - instance.mimeType = mimeType; - NSString *fileExtension = [MIMETypeUtil fileExtensionForMIMEType:mimeType]; - OWSAssertDebug(fileExtension.length > 0); - instance.filename = [@"attachment" stringByAppendingPathExtension:fileExtension]; - __weak DebugUIMessagesAssetLoader *weakSelf = instance; - instance.prepareBlock = ^(ActionSuccessBlock success, ActionFailureBlock failure) { - [weakSelf ensureMissingAssetLoaded:success failure:failure]; - }; - return instance; -} - -- (void)ensureMissingAssetLoaded:(ActionSuccessBlock)success failure:(ActionFailureBlock)failure -{ - OWSAssertDebug(success); - OWSAssertDebug(failure); - OWSAssertDebug(self.filename.length > 0); - OWSAssertDebug(self.mimeType.length > 0); - - if (self.filePath) { - success(); - return; - } - - NSString *fileExtension = [MIMETypeUtil fileExtensionForMIMEType:self.mimeType]; - OWSAssertDebug(fileExtension.length > 0); - NSString *filePath = [OWSFileSystem temporaryFilePathWithFileExtension:fileExtension]; - BOOL didCreate = [NSFileManager.defaultManager createFileAtPath:filePath contents:nil attributes:nil]; - OWSAssertDebug(didCreate); - self.filePath = filePath; - OWSAssertDebug([NSFileManager.defaultManager fileExistsAtPath:filePath]); - - success(); -} - -#pragma mark - - -+ (DebugUIMessagesAssetLoader *)fakeOversizeTextAssetLoader -{ - DebugUIMessagesAssetLoader *instance = [DebugUIMessagesAssetLoader new]; - instance.mimeType = OWSMimeTypeOversizeTextMessage; - instance.filename = @"attachment.txt"; - __weak DebugUIMessagesAssetLoader *weakSelf = instance; - instance.prepareBlock = ^(ActionSuccessBlock success, ActionFailureBlock failure) { - [weakSelf ensureOversizeTextAssetLoaded:success failure:failure]; - }; - return instance; -} - -- (void)ensureOversizeTextAssetLoaded:(ActionSuccessBlock)success failure:(ActionFailureBlock)failure -{ - OWSAssertDebug(success); - OWSAssertDebug(failure); - OWSAssertDebug(self.filename.length > 0); - OWSAssertDebug(self.mimeType.length > 0); - - if (self.filePath) { - success(); - return; - } - - NSMutableString *message = [NSMutableString new]; - for (NSUInteger i = 0; i < 32; i++) { - [message appendString:@"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse rutrum, nulla " - @"vitae pretium hendrerit, tellus turpis pharetra libero, vitae sodales tortor ante vel " - @"sem. Fusce sed nisl a lorem gravida tincidunt. Suspendisse efficitur non quam ac " - @"sodales. Aenean ut velit maximus, posuere sem a, accumsan nunc. Donec ullamcorper " - @"turpis lorem. Quisque dignissim purus eu placerat ultricies. Proin at urna eget mi " - @"semper congue. Aenean non elementum ex. Praesent pharetra quam at sem vestibulum, " - @"vestibulum ornare dolor elementum. Vestibulum massa tortor, scelerisque sit amet " - @"pulvinar a, rhoncus vitae nisl. Sed mi nunc, tempus at varius in, malesuada vitae " - @"dui. Vivamus efficitur pulvinar erat vitae congue. Proin vehicula turpis non felis " - @"congue facilisis. Nullam aliquet dapibus ligula ac mollis. Etiam sit amet posuere " - @"lorem, in rhoncus nisi.\n\n"]; - } - - NSString *fileExtension = @"txt"; - NSString *filePath = [OWSFileSystem temporaryFilePathWithFileExtension:fileExtension]; - NSData *data = [message dataUsingEncoding:NSUTF8StringEncoding]; - OWSAssertDebug(data); - BOOL didWrite = [data writeToFile:filePath atomically:YES]; - OWSAssertDebug(didWrite); - self.filePath = filePath; - OWSAssertDebug([NSFileManager.defaultManager fileExistsAtPath:filePath]); - - success(); -} - -#pragma mark - - -+ (DebugUIMessagesAssetLoader *)fakeOversizeTextAssetLoaderWithText:(NSString *)text -{ - DebugUIMessagesAssetLoader *instance = [DebugUIMessagesAssetLoader new]; - instance.mimeType = OWSMimeTypeOversizeTextMessage; - instance.filename = @"attachment.txt"; - __weak DebugUIMessagesAssetLoader *weakSelf = instance; - instance.prepareBlock = ^(ActionSuccessBlock success, ActionFailureBlock failure) { - [weakSelf ensureOversizeTextAssetLoadedWithText:text success:success failure:failure]; - }; - return instance; -} - -- (void)ensureOversizeTextAssetLoadedWithText:(NSString *)text - success:(ActionSuccessBlock)success - failure:(ActionFailureBlock)failure -{ - OWSAssertDebug(success); - OWSAssertDebug(failure); - OWSAssertDebug(self.filename.length > 0); - OWSAssertDebug(self.mimeType.length > 0); - - if (self.filePath) { - success(); - return; - } - - NSString *fileExtension = @"txt"; - NSString *filePath = [OWSFileSystem temporaryFilePathWithFileExtension:fileExtension]; - NSData *data = [text dataUsingEncoding:NSUTF8StringEncoding]; - OWSAssertDebug(data); - BOOL didWrite = [data writeToFile:filePath atomically:YES]; - OWSAssertDebug(didWrite); - self.filePath = filePath; - OWSAssertDebug([NSFileManager.defaultManager fileExistsAtPath:filePath]); - - success(); -} - -#pragma mark - - -+ (instancetype)jpegInstance -{ - static DebugUIMessagesAssetLoader *instance = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - instance = [DebugUIMessagesAssetLoader - fakeAssetLoaderWithUrl:@"https://s3.amazonaws.com/ows-data/example_attachment_media/random-jpg.JPG" - mimeType:OWSMimeTypeImageJpeg]; - }); - return instance; -} - -+ (instancetype)gifInstance -{ - static DebugUIMessagesAssetLoader *instance = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - instance = [DebugUIMessagesAssetLoader - fakeAssetLoaderWithUrl:@"https://s3.amazonaws.com/ows-data/example_attachment_media/random-gif.gif" - mimeType:OWSMimeTypeImageGif]; - }); - return instance; -} - -+ (instancetype)largeGifInstance -{ - static DebugUIMessagesAssetLoader *instance = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - instance = - [DebugUIMessagesAssetLoader fakeAssetLoaderWithUrl:@"https://i.giphy.com/media/LTw0F3GAdaao8/source.gif" - mimeType:OWSMimeTypeImageGif]; - }); - return instance; -} - -+ (instancetype)mp3Instance -{ - static DebugUIMessagesAssetLoader *instance = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - instance = [DebugUIMessagesAssetLoader - fakeAssetLoaderWithUrl:@"https://s3.amazonaws.com/ows-data/example_attachment_media/random-mp3.mp3" - mimeType:@"audio/mp3"]; - }); - return instance; -} - -+ (instancetype)mp4Instance -{ - static DebugUIMessagesAssetLoader *instance = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - instance = [DebugUIMessagesAssetLoader - fakeAssetLoaderWithUrl:@"https://s3.amazonaws.com/ows-data/example_attachment_media/random-mp4.mp4" - mimeType:@"video/mp4"]; - }); - return instance; -} - -+ (instancetype)compactPortraitPngInstance -{ - static DebugUIMessagesAssetLoader *instance = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - instance = [DebugUIMessagesAssetLoader fakePngAssetLoaderWithImageSize:CGSizeMake(60, 100) - backgroundColor:[UIColor blueColor] - textColor:[UIColor whiteColor] - label:@"P"]; - }); - return instance; -} - -+ (instancetype)compactLandscapePngInstance -{ - static DebugUIMessagesAssetLoader *instance = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - instance = [DebugUIMessagesAssetLoader fakePngAssetLoaderWithImageSize:CGSizeMake(100, 60) - backgroundColor:[UIColor greenColor] - textColor:[UIColor whiteColor] - label:@"L"]; - }); - return instance; -} - -+ (instancetype)tallPortraitPngInstance -{ - static DebugUIMessagesAssetLoader *instance = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - instance = [DebugUIMessagesAssetLoader fakePngAssetLoaderWithImageSize:CGSizeMake(10, 100) - backgroundColor:[UIColor yellowColor] - textColor:[UIColor whiteColor] - label:@"P"]; - }); - return instance; -} - -+ (instancetype)wideLandscapePngInstance -{ - static DebugUIMessagesAssetLoader *instance = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - instance = [DebugUIMessagesAssetLoader fakePngAssetLoaderWithImageSize:CGSizeMake(100, 10) - backgroundColor:[UIColor purpleColor] - textColor:[UIColor whiteColor] - label:@"L"]; - }); - return instance; -} - -+ (instancetype)largePngInstance -{ - static DebugUIMessagesAssetLoader *instance = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - instance = [DebugUIMessagesAssetLoader fakePngAssetLoaderWithImageSize:CGSizeMake(4000, 4000) - backgroundColor:[UIColor brownColor] - textColor:[UIColor whiteColor] - label:@"B"]; - }); - return instance; -} - -+ (instancetype)tinyPngInstance -{ - static DebugUIMessagesAssetLoader *instance = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - instance = [DebugUIMessagesAssetLoader fakePngAssetLoaderWithImageSize:CGSizeMake(2, 2) - backgroundColor:[UIColor cyanColor] - textColor:[UIColor whiteColor] - label:@"T"]; - }); - return instance; -} - -+ (instancetype)pngInstanceWithSize:(CGSize)size - backgroundColor:(UIColor *)backgroundColor - textColor:(UIColor *)textColor - label:(NSString *)label -{ - return [DebugUIMessagesAssetLoader fakePngAssetLoaderWithImageSize:size - backgroundColor:backgroundColor - textColor:textColor - label:label]; -} - -+ (instancetype)tinyPdfInstance -{ - static DebugUIMessagesAssetLoader *instance = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - instance = [DebugUIMessagesAssetLoader fakeRandomAssetLoaderWithLength:256 mimeType:@"application/pdf"]; - }); - return instance; -} - -+ (instancetype)largePdfInstance -{ - static DebugUIMessagesAssetLoader *instance = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - instance = - [DebugUIMessagesAssetLoader fakeRandomAssetLoaderWithLength:4 * 1024 * 1024 mimeType:@"application/pdf"]; - }); - return instance; -} - -+ (instancetype)missingPngInstance -{ - static DebugUIMessagesAssetLoader *instance = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - instance = [DebugUIMessagesAssetLoader fakeMissingAssetLoaderWithMimeType:OWSMimeTypeImagePng]; - }); - return instance; -} - -+ (instancetype)missingPdfInstance -{ - static DebugUIMessagesAssetLoader *instance = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - instance = [DebugUIMessagesAssetLoader fakeMissingAssetLoaderWithMimeType:@"application/pdf"]; - }); - return instance; -} - -+ (instancetype)oversizeTextInstance -{ - static DebugUIMessagesAssetLoader *instance = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - instance = [DebugUIMessagesAssetLoader fakeOversizeTextAssetLoader]; - }); - return instance; -} - -+ (instancetype)oversizeTextInstanceWithText:(NSString *)text -{ - static DebugUIMessagesAssetLoader *instance = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - instance = [DebugUIMessagesAssetLoader fakeOversizeTextAssetLoaderWithText:text]; - }); - return instance; -} - -#pragma mark - - -+ (void)prepareAssetLoaders:(NSArray *)assetLoaders - success:(dispatch_block_t)success - failure:(dispatch_block_t)failure -{ - - NSMutableArray *promises = [NSMutableArray array]; - NSMutableArray *errors = [NSMutableArray array]; - - for (DebugUIMessagesAssetLoader *assetLoader in assetLoaders) { - // Use chained promises to make the code more readable. - AnyPromise *promise = [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) { - assetLoader.prepareBlock( - ^{ - // The value doesn't matter, we just need any non-NSError value. - resolve(@(1)); - }, - ^{ - NSError *error = - [NSError errorWithDomain:@"DebugUI" - code:0 - userInfo:@{ NSLocalizedDescriptionKey : @"Could not prepare fake assets." }]; - @synchronized(errors) { - [errors addObject:error]; - } - resolve(error); - }); - }]; - [promises addObject:promise]; - } - - // We could use PMKJoin() or PMKWhen(). - [PMKJoin(promises) - .then(^(id value) { - success(); - }) - .catch(^(id error) { - OWSLogError(@"Could not prepare fake asset loaders: %@.", error); - failure(); - }) retainUntilComplete]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/src/ViewControllers/DebugUI/DebugUIMessagesUtils.h b/Session/src/ViewControllers/DebugUI/DebugUIMessagesUtils.h deleted file mode 100644 index 261b8587b..000000000 --- a/Session/src/ViewControllers/DebugUI/DebugUIMessagesUtils.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -NS_ASSUME_NONNULL_BEGIN - -@class YapDatabaseReadWriteTransaction; - -typedef void (^ActionSuccessBlock)(void); -typedef void (^ActionFailureBlock)(void); -typedef void (^ActionPrepareBlock)(ActionSuccessBlock success, ActionFailureBlock failure); -typedef void (^StaggeredActionBlock)(NSUInteger index, - YapDatabaseReadWriteTransaction *transaction, - ActionSuccessBlock success, - ActionFailureBlock failure); -typedef void (^UnstaggeredActionBlock)(NSUInteger index, YapDatabaseReadWriteTransaction *transaction); - -NS_ASSUME_NONNULL_END diff --git a/Session/src/ViewControllers/DebugUI/DebugUIMisc.h b/Session/src/ViewControllers/DebugUI/DebugUIMisc.h deleted file mode 100644 index c890d2657..000000000 --- a/Session/src/ViewControllers/DebugUI/DebugUIMisc.h +++ /dev/null @@ -1,13 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "DebugUIPage.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface DebugUIMisc : DebugUIPage - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/src/ViewControllers/DebugUI/DebugUIMisc.m b/Session/src/ViewControllers/DebugUI/DebugUIMisc.m deleted file mode 100644 index ab86ea35e..000000000 --- a/Session/src/ViewControllers/DebugUI/DebugUIMisc.m +++ /dev/null @@ -1,337 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "DebugUIMisc.h" -#import "DebugUIMessagesAssetLoader.h" -#import "OWSBackup.h" -#import "OWSCountryMetadata.h" -#import "OWSTableViewController.h" -#import "Session-Swift.h" -#import "ThreadUtil.h" -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface OWSStorage (DebugUI) - -- (NSData *)databasePassword; - -@end - -#pragma mark - - -@implementation DebugUIMisc - -#pragma mark - Dependencies - -+ (YapDatabaseConnection *)dbConnection -{ - return [OWSPrimaryStorage.sharedManager dbReadWriteConnection]; -} - -#pragma mark - Factory Methods - -- (NSString *)name -{ - return @"Misc."; -} - -- (nullable OWSTableSection *)sectionForThread:(nullable TSThread *)thread -{ - NSMutableArray *items = [NSMutableArray new]; - [items addObject:[OWSTableItem itemWithTitle:@"Enable Manual Censorship Circumvention" - actionBlock:^{ - [DebugUIMisc setManualCensorshipCircumventionEnabled:YES]; - }]]; - [items addObject:[OWSTableItem itemWithTitle:@"Disable Manual Censorship Circumvention" - actionBlock:^{ - [DebugUIMisc setManualCensorshipCircumventionEnabled:NO]; - }]]; - [items addObject:[OWSTableItem itemWithTitle:@"Clear experience upgrades (works once per launch)" - actionBlock:^{ - [ExperienceUpgrade removeAllObjectsInCollection]; - }]]; - [items addObject:[OWSTableItem itemWithTitle:@"Clear hasDismissedOffers" - actionBlock:^{ - [DebugUIMisc clearHasDismissedOffers]; - }]]; - - [items addObject:[OWSTableItem itemWithTitle:@"Delete disappearing messages config" - actionBlock:^{ - [[OWSPrimaryStorage sharedManager].newDatabaseConnection readWriteWithBlock:^( - YapDatabaseReadWriteTransaction *_Nonnull transaction) { - OWSDisappearingMessagesConfiguration *config = - [OWSDisappearingMessagesConfiguration - fetchOrBuildDefaultWithThreadId:thread.uniqueId - transaction:transaction]; - [config removeWithTransaction:transaction]; - }]; - }]]; - - [items addObject:[OWSTableItem - itemWithTitle:@"Re-register" - actionBlock:^{ - [OWSAlerts - showConfirmationAlertWithTitle:@"Re-register?" - message:@"If you proceed, you will not lose any of your " - @"current messages, but your account will be " - @"deactivated until you complete re-registration." - proceedTitle:@"Proceed" - proceedAction:^(UIAlertAction *_Nonnull action) { - [DebugUIMisc reregister]; - }]; - }]]; - - - if (thread) { - [items addObject:[OWSTableItem itemWithTitle:@"Send Encrypted Database" - actionBlock:^{ - [DebugUIMisc sendEncryptedDatabase:thread]; - }]]; - [items addObject:[OWSTableItem itemWithTitle:@"Send Unencrypted Database" - actionBlock:^{ - [DebugUIMisc sendUnencryptedDatabase:thread]; - }]]; - } - - [items addObject:[OWSTableItem itemWithTitle:@"Reset 2FA Repetition Interval" - actionBlock:^() { - [OWS2FAManager.sharedManager setDefaultRepetitionInterval]; - }]]; - -#ifdef DEBUG - [items addObject:[OWSTableItem subPageItemWithText:@"Share UIImage" - actionBlock:^(UIViewController *viewController) { - UIImage *image = - [UIImage imageWithColor:UIColor.redColor size:CGSizeMake(1.f, 1.f)]; - [AttachmentSharing showShareUIForUIImage:image]; - }]]; - [items addObject:[OWSTableItem subPageItemWithText:@"Share 2 Images" - actionBlock:^(UIViewController *viewController) { - [DebugUIMisc shareImages:2]; - }]]; - [items addObject:[OWSTableItem subPageItemWithText:@"Share 2 Videos" - actionBlock:^(UIViewController *viewController) { - [DebugUIMisc shareVideos:2]; - }]]; - [items addObject:[OWSTableItem subPageItemWithText:@"Share 2 PDFs" - actionBlock:^(UIViewController *viewController) { - [DebugUIMisc sharePDFs:2]; - }]]; -#endif - - [items - addObject:[OWSTableItem - itemWithTitle:@"Increment Database Extension Versions" - actionBlock:^() { - for (NSString *extensionName in OWSPrimaryStorage.sharedManager.registeredExtensionNames) { - [OWSStorage incrementVersionOfDatabaseExtension:extensionName]; - } - }]]; - - [items addObject:[OWSTableItem itemWithTitle:@"Fetch system contacts" - actionBlock:^() { - [Environment.shared.contactsManager requestSystemContactsOnce]; - }]]; - - [items addObject:[OWSTableItem itemWithTitle:@"Cycle websockets" - actionBlock:^() { - [SSKEnvironment.shared.socketManager cycleSocket]; - }]]; - - return [OWSTableSection sectionWithTitle:self.name items:items]; -} - -+ (void)reregister -{ - -} - -+ (void)setManualCensorshipCircumventionEnabled:(BOOL)isEnabled -{ - OWSCountryMetadata *countryMetadata = nil; - NSString *countryCode = OWSSignalService.sharedInstance.manualCensorshipCircumventionCountryCode; - if (countryCode) { - countryMetadata = [OWSCountryMetadata countryMetadataForCountryCode:countryCode]; - } - - if (!countryMetadata) { - countryCode = [PhoneNumber defaultCountryCode]; - if (countryCode) { - countryMetadata = [OWSCountryMetadata countryMetadataForCountryCode:countryCode]; - } - } - - if (!countryMetadata) { - countryCode = @"US"; - countryMetadata = [OWSCountryMetadata countryMetadataForCountryCode:countryCode]; - } - - OWSAssertDebug(countryMetadata); - OWSSignalService.sharedInstance.manualCensorshipCircumventionCountryCode = countryCode; - OWSSignalService.sharedInstance.isCensorshipCircumventionManuallyActivated = isEnabled; -} - -+ (void)clearHasDismissedOffers -{ - [OWSPrimaryStorage.dbReadWriteConnection - readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { - NSMutableArray *contactThreads = [NSMutableArray new]; - [transaction - enumerateKeysAndObjectsInCollection:[TSThread collection] - usingBlock:^(NSString *_Nonnull key, id _Nonnull object, BOOL *_Nonnull stop) { - TSThread *thread = object; - if (thread.isGroupThread) { - return; - } - TSContactThread *contactThread = object; - [contactThreads addObject:contactThread]; - }]; - for (TSContactThread *contactThread in contactThreads) { - if (contactThread.hasDismissedOffers) { - contactThread.hasDismissedOffers = NO; - [contactThread saveWithTransaction:transaction]; - } - } - }]; -} - -+ (void)sendEncryptedDatabase:(TSThread *)thread -{ - NSString *filePath = [OWSFileSystem temporaryFilePathWithFileExtension:@"sqlite"]; - NSString *fileName = filePath.lastPathComponent; - - __block BOOL success; - [OWSPrimaryStorage.sharedManager.newDatabaseConnection - readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - NSError *error; - success = [[NSFileManager defaultManager] copyItemAtPath:OWSPrimaryStorage.databaseFilePath - toPath:filePath - error:&error]; - if (!success || error) { - OWSFailDebug(@"Could not copy database file: %@.", error); - success = NO; - } - }]; - - if (!success) { - return; - } - - NSString *utiType = [MIMETypeUtil utiTypeForFileExtension:fileName.pathExtension]; - DataSource *_Nullable dataSource = [DataSourcePath dataSourceWithFilePath:filePath shouldDeleteOnDeallocation:YES]; - [dataSource setSourceFilename:fileName]; - SignalAttachment *attachment = [SignalAttachment attachmentWithDataSource:dataSource dataUTI:utiType]; - NSData *databasePassword = [OWSPrimaryStorage.sharedManager databasePassword]; - attachment.captionText = [databasePassword hexadecimalString]; - [self sendAttachment:attachment thread:thread]; -} - -+ (void)sendAttachment:(SignalAttachment *)attachment thread:(TSThread *)thread -{ - if (!attachment || [attachment hasError]) { - OWSFailDebug(@"attachment[%@]: %@", [attachment sourceFilename], [attachment errorName]); - return; - } - [self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) { - [ThreadUtil enqueueMessageWithText:nil - mediaAttachments:@[ attachment ] - inThread:thread - quotedReplyModel:nil - linkPreviewDraft:nil - transaction:transaction]; - }]; -} - -+ (void)sendUnencryptedDatabase:(TSThread *)thread -{ - NSString *filePath = [OWSFileSystem temporaryFilePathWithFileExtension:@"sqlite"]; - NSString *fileName = filePath.lastPathComponent; - - NSError *error = [OWSPrimaryStorage.sharedManager.newDatabaseConnection backupToPath:filePath]; - if (error) { - OWSFailDebug(@"Could not copy database file: %@.", error); - return; - } - - NSString *utiType = [MIMETypeUtil utiTypeForFileExtension:fileName.pathExtension]; - DataSource *_Nullable dataSource = [DataSourcePath dataSourceWithFilePath:filePath shouldDeleteOnDeallocation:YES]; - [dataSource setSourceFilename:fileName]; - SignalAttachment *attachment = [SignalAttachment attachmentWithDataSource:dataSource dataUTI:utiType]; - [self sendAttachment:attachment thread:thread]; -} - -#ifdef DEBUG - -+ (void)shareAssets:(NSUInteger)count - fromAssetLoaders:(NSArray *)assetLoaders -{ - [DebugUIMessagesAssetLoader prepareAssetLoaders:assetLoaders - success:^{ - [self shareAssets:count - fromPreparedAssetLoaders:assetLoaders]; - } - failure:^{ - OWSLogError(@"Could not prepare asset loaders."); - }]; -} - -+ (void)shareAssets:(NSUInteger)count - fromPreparedAssetLoaders:(NSArray *)assetLoaders -{ - __block NSMutableArray *urls = [NSMutableArray new]; - for (NSUInteger i = 0;i < count;i++) { - DebugUIMessagesAssetLoader *assetLoader = assetLoaders[arc4random_uniform((uint32_t) assetLoaders.count)]; - NSString *filePath = [OWSFileSystem temporaryFilePathWithFileExtension:assetLoader.filePath.pathExtension]; - NSError *error; - [[NSFileManager defaultManager] copyItemAtPath:assetLoader.filePath toPath:filePath error:&error]; - OWSAssertDebug(!error); - [urls addObject:[NSURL fileURLWithPath:filePath]]; - } - OWSLogVerbose(@"urls: %@", urls); - [AttachmentSharing showShareUIForURLs:urls completion:^{ - urls = nil; - }]; -} - -+ (void)shareImages:(NSUInteger)count -{ - [self shareAssets:count - fromAssetLoaders:@[ - [DebugUIMessagesAssetLoader jpegInstance], - [DebugUIMessagesAssetLoader tinyPngInstance], - ]]; -} - -+ (void)shareVideos:(NSUInteger)count -{ - [self shareAssets:count - fromAssetLoaders:@[ - [DebugUIMessagesAssetLoader mp4Instance], - ]]; -} - -+ (void)sharePDFs:(NSUInteger)count -{ - [self shareAssets:count - fromAssetLoaders:@[ - [DebugUIMessagesAssetLoader tinyPdfInstance], - ]]; -} - -#endif - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/src/ViewControllers/DebugUI/DebugUINotifications.swift b/Session/src/ViewControllers/DebugUI/DebugUINotifications.swift deleted file mode 100644 index d6a9f180d..000000000 --- a/Session/src/ViewControllers/DebugUI/DebugUINotifications.swift +++ /dev/null @@ -1,174 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -import Foundation -import SignalUtilitiesKit -import SignalUtilitiesKit -import PromiseKit - -class DebugUINotifications: DebugUIPage { - - // MARK: Dependencies - - var notificationPresenter: NotificationPresenter { - return AppEnvironment.shared.notificationPresenter - } - var messageSender: MessageSender { - return SSKEnvironment.shared.messageSender - } - var contactsManager: OWSContactsManager { - return Environment.shared.contactsManager - } - - // MARK: Overrides - - override func name() -> String { - return "Notifications" - } - - override func section(thread: TSThread?) -> OWSTableSection? { - guard let thread = thread else { - owsFailDebug("Notifications must specify thread.") - return nil - } - - var sectionItems: [OWSTableItem] = [] - -// if let contactThread = thread as? TSContactThread { -// sectionItems += [ -// OWSTableItem(title: "All Notifications in Sequence") { [weak self] in -// self?.notifyForEverythingInSequence(contactThread: contactThread).retainUntilComplete() -// }, -// OWSTableItem(title: "Incoming Call") { [weak self] in -// self?.notifyForIncomingCall(thread: contactThread).retainUntilComplete() -// }, -// OWSTableItem(title: "Call Missed") { [weak self] in -// self?.notifyForMissedCall(thread: contactThread).retainUntilComplete() -// }, -// OWSTableItem(title: "Call Rejected: New Safety Number") { [weak self] in -// self?.notifyForMissedCallBecauseOfNewIdentity(thread: contactThread).retainUntilComplete() -// }, -// OWSTableItem(title: "Call Rejected: No Longer Verified") { [weak self] in -// self?.notifyForMissedCallBecauseOfNoLongerVerifiedIdentity(thread: contactThread).retainUntilComplete() -// } -// ] -// } - -// sectionItems += [ -// OWSTableItem(title: "Last Incoming Message") { [weak self] in -// self?.notifyForIncomingMessage(thread: thread).retainUntilComplete() -// }, -// -// OWSTableItem(title: "Notify For Error Message") { [weak self] in -// self?.notifyForErrorMessage(thread: thread).retainUntilComplete() -// }, -// -// OWSTableItem(title: "Notify For Threadless Error Message") { [weak self] in -// self?.notifyUserForThreadlessErrorMessage().retainUntilComplete() -// } -// ] - - return OWSTableSection(title: "Notifications have delay: \(kNotificationDelay)s", items: sectionItems) - } - - // MARK: Helpers - - func readWrite(_ block: @escaping (YapDatabaseReadWriteTransaction) -> Void) { - OWSPrimaryStorage.shared().dbReadWriteConnection.readWrite(block) - } - - // After enqueing the notification you may want to background the app or lock the screen before it triggers, so - // we give a little delay. - let kNotificationDelay: TimeInterval = 5 - - func delayedNotificationDispatch(block: @escaping () -> Void) -> Guarantee { - Logger.info("delaying for \(kNotificationDelay) seconds") - - // Notifications won't sound if the app is suspended. - let taskIdentifier = UIApplication.shared.beginBackgroundTask(expirationHandler: nil) - - return after(seconds: kNotificationDelay).done { - block() - }.then { - after(seconds: 2.0) - }.done { - // We don't want to endBackgroundTask until *after* the notifications manager is done, - // but it dispatches async without a completion handler, so we just wait a while extra. - // This is fragile, but it's only for debug UI. - UIApplication.shared.endBackgroundTask(taskIdentifier) - } - } - -// func delayedNotificationDispatchWithFakeCall(thread: TSContactThread, callBlock: @escaping (SignalCall) -> Void) -> Guarantee { -// let call = SignalCall.incomingCall(localId: UUID(), remotePhoneNumber: thread.contactIdentifier(), signalingId: 0) -// -// return delayedNotificationDispatch { -// callBlock(call) -// } -// } - - // MARK: Notification Methods - -// func notifyForEverythingInSequence(contactThread: TSContactThread) -> Guarantee { -// let taskIdentifier = UIApplication.shared.beginBackgroundTask(expirationHandler: nil) -// return firstly { -// self.notifyForIncomingCall(thread: contactThread) -// }.then { -// self.notifyForMissedCall(thread: contactThread) -// }.then { -// self.notifyForMissedCallBecauseOfNewIdentity(thread: contactThread) -// }.then { -// self.notifyForMissedCallBecauseOfNoLongerVerifiedIdentity(thread: contactThread) -// }.then -// return firstly { -// self.notifyForIncomingMessage(thread: contactThread) -// }.then { -// self.notifyForErrorMessage(thread: contactThread) -// }.then { -// self.notifyUserForThreadlessErrorMessage() -// }.done { -// UIApplication.shared.endBackgroundTask(taskIdentifier) -// } -// } - -// func notifyForIncomingCall(thread: TSContactThread) -> Guarantee { -// Logger.info("⚠️ will present notification after delay") -// return delayedNotificationDispatchWithFakeCall(thread: thread) { call in -// self.notificationPresenter.presentIncomingCall(call, callerName: thread.name()) -// } -// } -// -// func notifyForMissedCall(thread: TSContactThread) -> Guarantee { -// Logger.info("⚠️ will present notification after delay") -// return delayedNotificationDispatchWithFakeCall(thread: thread) { call in -// self.notificationPresenter.presentMissedCall(call, callerName: thread.name()) -// } -// } -// -// func notifyForMissedCallBecauseOfNewIdentity(thread: TSContactThread) -> Guarantee { -// Logger.info("⚠️ will present notification after delay") -// return delayedNotificationDispatchWithFakeCall(thread: thread) { call in -// self.notificationPresenter.presentMissedCallBecauseOfNewIdentity(call: call, callerName: thread.name()) -// } -// } -// -// func notifyForMissedCallBecauseOfNoLongerVerifiedIdentity(thread: TSContactThread) -> Guarantee { -// Logger.info("⚠️ will present notification after delay") -// return delayedNotificationDispatchWithFakeCall(thread: thread) { call in -// self.notificationPresenter.presentMissedCallBecauseOfNoLongerVerifiedIdentity(call: call, callerName: thread.name()) -// } -// } - - func notifyUserForThreadlessErrorMessage() -> Guarantee { - Logger.info("⚠️ will present notification after delay") - return delayedNotificationDispatch { - self.readWrite { transaction in - let errorMessage = TSErrorMessage.corruptedMessageInUnknownThread() - - self.notificationPresenter.notifyUser(forThreadlessErrorMessage: errorMessage, - transaction: transaction) - } - } - } -} diff --git a/Session/src/ViewControllers/DebugUI/DebugUIPage.h b/Session/src/ViewControllers/DebugUI/DebugUIPage.h deleted file mode 100644 index d56c8fd75..000000000 --- a/Session/src/ViewControllers/DebugUI/DebugUIPage.h +++ /dev/null @@ -1,27 +0,0 @@ -// -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. -// - -#import "DebugUIPage.h" - -// This preprocessor symbol controls whether or not the Debug UI is active. -// -// To show the DebugUI in production builds, comment out the #ifdef and #endif -#ifdef DEBUG -#define USE_DEBUG_UI -#endif - -NS_ASSUME_NONNULL_BEGIN - -@class OWSTableSection; -@class TSThread; - -@interface DebugUIPage : NSObject - -- (NSString *)name; - -- (nullable OWSTableSection *)sectionForThread:(nullable TSThread *)thread NS_SWIFT_NAME(section(thread:)); - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/src/ViewControllers/DebugUI/DebugUIPage.m b/Session/src/ViewControllers/DebugUI/DebugUIPage.m deleted file mode 100644 index a18f531c7..000000000 --- a/Session/src/ViewControllers/DebugUI/DebugUIPage.m +++ /dev/null @@ -1,30 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "DebugUIPage.h" -#import "OWSTableViewController.h" - -NS_ASSUME_NONNULL_BEGIN - -@implementation DebugUIPage - -#pragma mark - Factory Methods - -- (NSString *)name -{ - OWSFailDebug(@"This method should be overriden in subclasses."); - - return nil; -} - -- (nullable OWSTableSection *)sectionForThread:(nullable TSThread *)thread -{ - OWSFailDebug(@"This method should be overriden in subclasses."); - - return nil; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/src/ViewControllers/DebugUI/DebugUIProfile.swift b/Session/src/ViewControllers/DebugUI/DebugUIProfile.swift deleted file mode 100644 index 15b84a540..000000000 --- a/Session/src/ViewControllers/DebugUI/DebugUIProfile.swift +++ /dev/null @@ -1,62 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -import Foundation -import SignalUtilitiesKit -import SignalUtilitiesKit - -class DebugUIProfile: DebugUIPage { - - // MARK: - Dependencies - - var messageSender: MessageSender { - return SSKEnvironment.shared.messageSender - } - var profileManager: OWSProfileManager { - return OWSProfileManager.shared() - } - - // MARK: - Overrides - - override func name() -> String { - return "Profile" - } - - override func section(thread aThread: TSThread?) -> OWSTableSection? { - let profileManager = self.profileManager - let sectionItems = [ - OWSTableItem(title: "Clear Profile Whitelist") { - profileManager.clearProfileWhitelist() - }, - OWSTableItem(title: "Log Profile Whitelist") { - profileManager.logProfileWhitelist() - }, - OWSTableItem(title: "Log User Profiles") { - profileManager.logUserProfiles() - }, - OWSTableItem(title: "Log Profile Key") { - let localProfileKey = profileManager.localProfileKey() - Logger.info("localProfileKey: \(localProfileKey.keyData.hexadecimalString)") - profileManager.logUserProfiles() - }, - OWSTableItem(title: "Regenerate Profile/ProfileKey") { - profileManager.regenerateLocalProfile() - }, - OWSTableItem(title: "Send Profile Key Message") { [weak self] in - guard let strongSelf = self else { return } - - // MJK TODO - should be safe to remove this senderTimestamp - let message = OWSProfileKeyMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: aThread) - strongSelf.messageSender.sendPromise(message: message).done { - Logger.info("Successfully sent profile key message to thread: \(String(describing: aThread))") - }.catch { _ in - owsFailDebug("Failed to send profile key message to thread: \(String(describing: aThread))") - }.retainUntilComplete() - } - ] - - return OWSTableSection(title: "Profile", items: sectionItems) - } - -} diff --git a/Session/src/ViewControllers/DebugUI/DebugUISessionState.h b/Session/src/ViewControllers/DebugUI/DebugUISessionState.h deleted file mode 100644 index 5c7e257d5..000000000 --- a/Session/src/ViewControllers/DebugUI/DebugUISessionState.h +++ /dev/null @@ -1,15 +0,0 @@ -// -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. -// - -#import "DebugUIPage.h" - -NS_ASSUME_NONNULL_BEGIN - -@class TSContactThread; - -@interface DebugUISessionState : DebugUIPage - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/src/ViewControllers/DebugUI/DebugUISessionState.m b/Session/src/ViewControllers/DebugUI/DebugUISessionState.m deleted file mode 100644 index cc13af0ea..000000000 --- a/Session/src/ViewControllers/DebugUI/DebugUISessionState.m +++ /dev/null @@ -1,141 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "DebugUISessionState.h" -#import "OWSTableViewController.h" -#import "Session-Swift.h" -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@implementation DebugUISessionState - -- (NSString *)name -{ - return @"Session State"; -} - -- (nullable OWSTableSection *)sectionForThread:(nullable TSThread *)threadParameter -{ - NSMutableArray *items = [NSMutableArray new]; - if ([threadParameter isKindOfClass:[TSContactThread class]]) { - TSContactThread *thread = (TSContactThread *)threadParameter; - [items addObjectsFromArray:@[ - [OWSTableItem itemWithTitle:@"Log All Recipient Identities" - actionBlock:^{ - [OWSRecipientIdentity printAllIdentities]; - }], - [OWSTableItem itemWithTitle:@"Log All Sessions" - actionBlock:^{ - [[OWSPrimaryStorage sharedManager] printAllSessions]; - }], - [OWSTableItem itemWithTitle:@"Toggle Key Change" - actionBlock:^{ - OWSLogError(@"Flipping identity Key. Flip again to return."); - - OWSIdentityManager *identityManager = [OWSIdentityManager sharedManager]; - NSString *recipientId = [thread contactIdentifier]; - - NSData *currentKey = [identityManager identityKeyForRecipientId:recipientId]; - NSMutableData *flippedKey = [NSMutableData new]; - const char *currentKeyBytes = currentKey.bytes; - for (NSUInteger i = 0; i < currentKey.length; i++) { - const char xorByte = currentKeyBytes[i] ^ 0xff; - [flippedKey appendBytes:&xorByte length:1]; - } - OWSAssertDebug(flippedKey.length == currentKey.length); - [identityManager saveRemoteIdentity:flippedKey recipientId:recipientId]; - }], - [OWSTableItem itemWithTitle:@"Delete all sessions" - actionBlock:^{ - [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [[OWSPrimaryStorage sharedManager] - deleteAllSessionsForContact:thread.contactIdentifier - protocolContext:transaction]; - }]; - }], - [OWSTableItem itemWithTitle:@"Archive all sessions" - actionBlock:^{ - [self.dbConnection - readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [[OWSPrimaryStorage sharedManager] - archiveAllSessionsForContact:thread.contactIdentifier - protocolContext:transaction]; - }]; - }], - [OWSTableItem itemWithTitle:@"Send session reset" - actionBlock:^{ - [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [self.sessionResetJobQueue addContactThread:thread transaction:transaction]; - }]; - }], - ]]; - } - -#if DEBUG - [items addObjectsFromArray:@[ - [OWSTableItem itemWithTitle:@"Clear Session and Identity Store" - actionBlock:^{ - [DebugUISessionState clearSessionAndIdentityStore]; - }], - [OWSTableItem itemWithTitle:@"Snapshot Session and Identity Store" - actionBlock:^{ - [DebugUISessionState snapshotSessionAndIdentityStore]; - }], - [OWSTableItem itemWithTitle:@"Restore Session and Identity Store" - actionBlock:^{ - [DebugUISessionState restoreSessionAndIdentityStore]; - }] - ]]; -#endif - - return [OWSTableSection sectionWithTitle:self.name items:items]; -} - -#pragma mark - Dependencies - -- (OWSSessionResetJobQueue *)sessionResetJobQueue -{ - return AppEnvironment.shared.sessionResetJobQueue; -} - -- (YapDatabaseConnection *)dbConnection -{ - return SSKEnvironment.shared.primaryStorage.dbReadWriteConnection; -} - -#if DEBUG -+ (void)clearSessionAndIdentityStore -{ - [OWSPrimaryStorage.sharedManager.newDatabaseConnection - readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [[OWSPrimaryStorage sharedManager] resetSessionStore:transaction]; - [[OWSIdentityManager sharedManager] clearIdentityState:transaction]; - }]; -} - -+ (void)snapshotSessionAndIdentityStore -{ - [OWSPrimaryStorage.sharedManager.newDatabaseConnection - readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [[OWSPrimaryStorage sharedManager] snapshotSessionStore:transaction]; - [[OWSIdentityManager sharedManager] snapshotIdentityState:transaction]; - }]; -} - -+ (void)restoreSessionAndIdentityStore -{ - [OWSPrimaryStorage.sharedManager.newDatabaseConnection - readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [[OWSPrimaryStorage sharedManager] restoreSessionStore:transaction]; - [[OWSIdentityManager sharedManager] restoreIdentityState:transaction]; - }]; -} -#endif - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/src/ViewControllers/DebugUI/DebugUIStress.h b/Session/src/ViewControllers/DebugUI/DebugUIStress.h deleted file mode 100644 index 6a9aa1dbe..000000000 --- a/Session/src/ViewControllers/DebugUI/DebugUIStress.h +++ /dev/null @@ -1,15 +0,0 @@ -// -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. -// - -#import "DebugUIPage.h" - -NS_ASSUME_NONNULL_BEGIN - -@class TSThread; - -@interface DebugUIStress : DebugUIPage - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/src/ViewControllers/DebugUI/DebugUIStress.m b/Session/src/ViewControllers/DebugUI/DebugUIStress.m deleted file mode 100644 index 73ec756fc..000000000 --- a/Session/src/ViewControllers/DebugUI/DebugUIStress.m +++ /dev/null @@ -1,580 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "DebugUIStress.h" -#import "OWSMessageSender.h" -#import "OWSTableViewController.h" -#import "SignalApp.h" -#import "ThreadUtil.h" -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@implementation DebugUIStress - -#pragma mark - Dependencies - -+ (SSKMessageSenderJobQueue *)messageSenderJobQueue -{ - return SSKEnvironment.shared.messageSenderJobQueue; -} - -- (SSKMessageSenderJobQueue *)messageSenderJobQueue -{ - return self.class.messageSenderJobQueue; -} - -- (YapDatabaseConnection *)dbConnection -{ - return self.class.dbConnection; -} - -+ (YapDatabaseConnection *)dbConnection -{ - return SSKEnvironment.shared.primaryStorage.dbReadWriteConnection; -} - -+ (TSAccountManager *)tsAccountManager -{ - return TSAccountManager.sharedInstance; -} - -#pragma mark - Factory Methods - -- (NSString *)name -{ - return @"Stress"; -} - -- (nullable OWSTableSection *)sectionForThread:(nullable TSThread *)thread -{ - OWSAssertDebug(thread); - - NSMutableArray *items = [NSMutableArray new]; - -#ifdef DEBUG - - [items addObject:[OWSTableItem itemWithTitle:@"Send empty message" - actionBlock:^{ - [DebugUIStress sendStressMessage:thread block:^(SignalRecipient *recipient) { - return [NSData new]; - }]; - }]]; - [items addObject:[OWSTableItem itemWithTitle:@"Send random noise message" - actionBlock:^{ - [DebugUIStress - sendStressMessage:thread - block:^(SignalRecipient *recipient) { - NSUInteger contentLength = arc4random_uniform(32); - return [Cryptography generateRandomBytes:contentLength]; - }]; - }]]; - [items addObject:[OWSTableItem itemWithTitle:@"Send no payload message" - actionBlock:^{ - [DebugUIStress sendStressMessage:thread - block:^(SignalRecipient *recipient) { - SSKProtoContentBuilder *contentBuilder = - [SSKProtoContent builder]; - return [[contentBuilder buildIgnoringErrors] - serializedDataIgnoringErrors]; - }]; - }]]; - [items addObject:[OWSTableItem itemWithTitle:@"Send empty null message" - actionBlock:^{ - [DebugUIStress sendStressMessage:thread - block:^(SignalRecipient *recipient) { - SSKProtoContentBuilder *contentBuilder = - [SSKProtoContent builder]; - SSKProtoNullMessageBuilder *nullMessageBuilder = - [SSKProtoNullMessage builder]; - contentBuilder.nullMessage = - [nullMessageBuilder buildIgnoringErrors]; - return [[contentBuilder buildIgnoringErrors] - serializedDataIgnoringErrors]; - }]; - }]]; - [items addObject:[OWSTableItem itemWithTitle:@"Send random null message" - actionBlock:^{ - [DebugUIStress - sendStressMessage:thread - block:^(SignalRecipient *recipient) { - SSKProtoContentBuilder *contentBuilder = - [SSKProtoContent builder]; - SSKProtoNullMessageBuilder *nullMessageBuilder = - [SSKProtoNullMessage builder]; - NSUInteger contentLength = arc4random_uniform(32); - nullMessageBuilder.padding = - [Cryptography generateRandomBytes:contentLength]; - contentBuilder.nullMessage = - [nullMessageBuilder buildIgnoringErrors]; - return [[contentBuilder buildIgnoringErrors] - serializedDataIgnoringErrors]; - }]; - }]]; - [items addObject:[OWSTableItem itemWithTitle:@"Send empty sync message" - actionBlock:^{ - [DebugUIStress sendStressMessage:thread - block:^(SignalRecipient *recipient) { - SSKProtoContentBuilder *contentBuilder = - [SSKProtoContent builder]; - SSKProtoSyncMessageBuilder *syncMessageBuilder = - [SSKProtoSyncMessage builder]; - contentBuilder.syncMessage = - [syncMessageBuilder buildIgnoringErrors]; - return [[contentBuilder buildIgnoringErrors] - serializedDataIgnoringErrors]; - }]; - }]]; - [items addObject:[OWSTableItem itemWithTitle:@"Send empty sync sent message" - actionBlock:^{ - [DebugUIStress sendStressMessage:thread - block:^(SignalRecipient *recipient) { - SSKProtoContentBuilder *contentBuilder = - [SSKProtoContent builder]; - SSKProtoSyncMessageBuilder *syncMessageBuilder = - [SSKProtoSyncMessage builder]; - SSKProtoSyncMessageSentBuilder *sentBuilder = - [SSKProtoSyncMessageSent builder]; - syncMessageBuilder.sent = - [sentBuilder buildIgnoringErrors]; - contentBuilder.syncMessage = - [syncMessageBuilder buildIgnoringErrors]; - return [[contentBuilder buildIgnoringErrors] - serializedDataIgnoringErrors]; - }]; - }]]; - [items addObject:[OWSTableItem itemWithTitle:@"Send whitespace text data message" - actionBlock:^{ - [DebugUIStress - sendStressMessage:thread - block:^(SignalRecipient *recipient) { - SSKProtoContentBuilder *contentBuilder = - [SSKProtoContent builder]; - SSKProtoDataMessageBuilder *dataBuilder = - [SSKProtoDataMessage builder]; - dataBuilder.body = @" "; - [DebugUIStress ensureGroupOfDataBuilder:dataBuilder - thread:thread]; - contentBuilder.dataMessage = - [dataBuilder buildIgnoringErrors]; - return [[contentBuilder buildIgnoringErrors] - serializedDataIgnoringErrors]; - }]; - }]]; - [items - addObject:[OWSTableItem - itemWithTitle:@"Send bad attachment data message" - actionBlock:^{ - [DebugUIStress - sendStressMessage:thread - block:^(SignalRecipient *recipient) { - SSKProtoContentBuilder *contentBuilder = [SSKProtoContent builder]; - SSKProtoDataMessageBuilder *dataBuilder = [SSKProtoDataMessage builder]; - SSKProtoAttachmentPointerBuilder *attachmentPointer = - [SSKProtoAttachmentPointer - builderWithId:arc4random_uniform(32) + 1]; - [attachmentPointer setContentType:@"1"]; - [attachmentPointer setSize:arc4random_uniform(32) + 1]; - [attachmentPointer setDigest:[Cryptography generateRandomBytes:1]]; - [attachmentPointer setFileName:@" "]; - [DebugUIStress ensureGroupOfDataBuilder:dataBuilder thread:thread]; - contentBuilder.dataMessage = [dataBuilder buildIgnoringErrors]; - return - [[contentBuilder buildIgnoringErrors] serializedDataIgnoringErrors]; - }]; - }]]; - [items addObject:[OWSTableItem itemWithTitle:@"Send normal text data message" - actionBlock:^{ - [DebugUIStress - sendStressMessage:thread - block:^(SignalRecipient *recipient) { - SSKProtoContentBuilder *contentBuilder = - [SSKProtoContent builder]; - SSKProtoDataMessageBuilder *dataBuilder = - [SSKProtoDataMessage builder]; - dataBuilder.body = @"alice"; - [DebugUIStress ensureGroupOfDataBuilder:dataBuilder - thread:thread]; - contentBuilder.dataMessage = - [dataBuilder buildIgnoringErrors]; - return [[contentBuilder buildIgnoringErrors] - serializedDataIgnoringErrors]; - }]; - }]]; - [items addObject:[OWSTableItem itemWithTitle:@"Send N text messages with same timestamp" - actionBlock:^{ - uint64_t timestamp = [NSDate ows_millisecondTimeStamp]; - for (int i = 0; i < 3; i++) { - [DebugUIStress - sendStressMessage:thread - timestamp:timestamp - block:^(SignalRecipient *recipient) { - SSKProtoContentBuilder *contentBuilder = - [SSKProtoContent builder]; - SSKProtoDataMessageBuilder *dataBuilder = - [SSKProtoDataMessage builder]; - dataBuilder.body = [NSString stringWithFormat:@"%@ %d", - [NSUUID UUID].UUIDString, - i]; - [DebugUIStress ensureGroupOfDataBuilder:dataBuilder - thread:thread]; - contentBuilder.dataMessage = - [dataBuilder buildIgnoringErrors]; - return [[contentBuilder buildIgnoringErrors] - serializedDataIgnoringErrors]; - }]; - } - }]]; - [items addObject:[OWSTableItem - itemWithTitle:@"Send text message with current timestamp" - actionBlock:^{ - uint64_t timestamp = [NSDate ows_millisecondTimeStamp]; - [DebugUIStress - sendStressMessage:thread - timestamp:timestamp - block:^(SignalRecipient *recipient) { - SSKProtoContentBuilder *contentBuilder = [SSKProtoContent builder]; - SSKProtoDataMessageBuilder *dataBuilder = - [SSKProtoDataMessage builder]; - dataBuilder.body = - [[NSUUID UUID].UUIDString stringByAppendingString:@" now"]; - [DebugUIStress ensureGroupOfDataBuilder:dataBuilder thread:thread]; - contentBuilder.dataMessage = [dataBuilder buildIgnoringErrors]; - return [[contentBuilder buildIgnoringErrors] - serializedDataIgnoringErrors]; - }]; - }]]; - [items addObject:[OWSTableItem - itemWithTitle:@"Send text message with future timestamp" - actionBlock:^{ - uint64_t timestamp = [NSDate ows_millisecondTimeStamp]; - timestamp += kHourInMs; - [DebugUIStress - sendStressMessage:thread - timestamp:timestamp - block:^(SignalRecipient *recipient) { - SSKProtoContentBuilder *contentBuilder = [SSKProtoContent builder]; - SSKProtoDataMessageBuilder *dataBuilder = - [SSKProtoDataMessage builder]; - dataBuilder.body = - [[NSUUID UUID].UUIDString stringByAppendingString:@" now"]; - [DebugUIStress ensureGroupOfDataBuilder:dataBuilder thread:thread]; - contentBuilder.dataMessage = [dataBuilder buildIgnoringErrors]; - return [[contentBuilder buildIgnoringErrors] - serializedDataIgnoringErrors]; - }]; - }]]; - [items addObject:[OWSTableItem - itemWithTitle:@"Send text message with past timestamp" - actionBlock:^{ - uint64_t timestamp = [NSDate ows_millisecondTimeStamp]; - timestamp -= kHourInMs; - [DebugUIStress - sendStressMessage:thread - timestamp:timestamp - block:^(SignalRecipient *recipient) { - SSKProtoContentBuilder *contentBuilder = [SSKProtoContent builder]; - SSKProtoDataMessageBuilder *dataBuilder = - [SSKProtoDataMessage builder]; - dataBuilder.body = - [[NSUUID UUID].UUIDString stringByAppendingString:@" now"]; - [DebugUIStress ensureGroupOfDataBuilder:dataBuilder thread:thread]; - contentBuilder.dataMessage = [dataBuilder buildIgnoringErrors]; - return [[contentBuilder buildIgnoringErrors] - serializedDataIgnoringErrors]; - }]; - }]]; - [items addObject:[OWSTableItem itemWithTitle:@"Send N text messages with same timestamp" - actionBlock:^{ - SSKProtoContentBuilder *contentBuilder = [SSKProtoContent builder]; - SSKProtoDataMessageBuilder *dataBuilder = [SSKProtoDataMessage builder]; - dataBuilder.body = @"alice"; - contentBuilder.dataMessage = [dataBuilder buildIgnoringErrors]; - [DebugUIStress ensureGroupOfDataBuilder:dataBuilder thread:thread]; - NSData *data = - [[contentBuilder buildIgnoringErrors] serializedDataIgnoringErrors]; - - uint64_t timestamp = [NSDate ows_millisecondTimeStamp]; - - for (int i = 0; i < 3; i++) { - [DebugUIStress sendStressMessage:thread - timestamp:timestamp - block:^(SignalRecipient *recipient) { - return data; - }]; - } - }]]; - [items - addObject:[OWSTableItem - itemWithTitle:@"Send malformed sync sent message 1" - actionBlock:^{ - [DebugUIStress - sendStressMessage:thread - block:^(SignalRecipient *recipient) { - SSKProtoContentBuilder *contentBuilder = [SSKProtoContent builder]; - SSKProtoSyncMessageBuilder *syncMessageBuilder = - [SSKProtoSyncMessage builder]; - SSKProtoSyncMessageSentBuilder *sentBuilder = - [SSKProtoSyncMessageSent builder]; - sentBuilder.destination = @"abc"; - sentBuilder.timestamp = arc4random_uniform(32) + 1; - SSKProtoDataMessageBuilder *dataBuilder = [SSKProtoDataMessage builder]; - sentBuilder.message = [dataBuilder buildIgnoringErrors]; - syncMessageBuilder.sent = [sentBuilder buildIgnoringErrors]; - contentBuilder.syncMessage = [syncMessageBuilder buildIgnoringErrors]; - return - [[contentBuilder buildIgnoringErrors] serializedDataIgnoringErrors]; - }]; - }]]; - [items - addObject:[OWSTableItem - itemWithTitle:@"Send malformed sync sent message 2" - actionBlock:^{ - [DebugUIStress - sendStressMessage:thread - block:^(SignalRecipient *recipient) { - SSKProtoContentBuilder *contentBuilder = [SSKProtoContent builder]; - SSKProtoSyncMessageBuilder *syncMessageBuilder = - [SSKProtoSyncMessage builder]; - SSKProtoSyncMessageSentBuilder *sentBuilder = - [SSKProtoSyncMessageSent builder]; - sentBuilder.destination = @"abc"; - sentBuilder.timestamp = 0; - SSKProtoDataMessageBuilder *dataBuilder = [SSKProtoDataMessage builder]; - sentBuilder.message = [dataBuilder buildIgnoringErrors]; - syncMessageBuilder.sent = [sentBuilder buildIgnoringErrors]; - contentBuilder.syncMessage = [syncMessageBuilder buildIgnoringErrors]; - return - [[contentBuilder buildIgnoringErrors] serializedDataIgnoringErrors]; - }]; - }]]; - [items - addObject:[OWSTableItem - itemWithTitle:@"Send malformed sync sent message 3" - actionBlock:^{ - [DebugUIStress - sendStressMessage:thread - block:^(SignalRecipient *recipient) { - SSKProtoContentBuilder *contentBuilder = [SSKProtoContent builder]; - SSKProtoSyncMessageBuilder *syncMessageBuilder = - [SSKProtoSyncMessage builder]; - SSKProtoSyncMessageSentBuilder *sentBuilder = - [SSKProtoSyncMessageSent builder]; - sentBuilder.destination = @"abc"; - sentBuilder.timestamp = 0; - SSKProtoDataMessageBuilder *dataBuilder = [SSKProtoDataMessage builder]; - dataBuilder.body = @" "; - sentBuilder.message = [dataBuilder buildIgnoringErrors]; - syncMessageBuilder.sent = [sentBuilder buildIgnoringErrors]; - contentBuilder.syncMessage = [syncMessageBuilder buildIgnoringErrors]; - return - [[contentBuilder buildIgnoringErrors] serializedDataIgnoringErrors]; - }]; - }]]; - [items - addObject:[OWSTableItem - itemWithTitle:@"Send malformed sync sent message 4" - actionBlock:^{ - [DebugUIStress - sendStressMessage:thread - block:^(SignalRecipient *recipient) { - SSKProtoContentBuilder *contentBuilder = [SSKProtoContent builder]; - SSKProtoSyncMessageBuilder *syncMessageBuilder = - [SSKProtoSyncMessage builder]; - SSKProtoSyncMessageSentBuilder *sentBuilder = - [SSKProtoSyncMessageSent builder]; - sentBuilder.destination = @"abc"; - sentBuilder.timestamp = 0; - SSKProtoDataMessageBuilder *dataBuilder = [SSKProtoDataMessage builder]; - dataBuilder.body = @" "; - SSKProtoGroupContextBuilder *groupBuilder = [SSKProtoGroupContext - builderWithId:[Cryptography generateRandomBytes:1] - type:SSKProtoGroupContextTypeDeliver]; - dataBuilder.group = [groupBuilder buildIgnoringErrors]; - sentBuilder.message = [dataBuilder buildIgnoringErrors]; - syncMessageBuilder.sent = [sentBuilder buildIgnoringErrors]; - contentBuilder.syncMessage = [syncMessageBuilder buildIgnoringErrors]; - return - [[contentBuilder buildIgnoringErrors] serializedDataIgnoringErrors]; - }]; - }]]; - [items - addObject:[OWSTableItem - itemWithTitle:@"Send malformed sync sent message 5" - actionBlock:^{ - [DebugUIStress - sendStressMessage:thread - block:^(SignalRecipient *recipient) { - SSKProtoContentBuilder *contentBuilder = [SSKProtoContent builder]; - SSKProtoSyncMessageBuilder *syncMessageBuilder = - [SSKProtoSyncMessage builder]; - SSKProtoSyncMessageSentBuilder *sentBuilder = - [SSKProtoSyncMessageSent builder]; - sentBuilder.destination = @"abc"; - sentBuilder.timestamp = 0; - SSKProtoDataMessageBuilder *dataBuilder = [SSKProtoDataMessage builder]; - dataBuilder.body = @" "; - SSKProtoGroupContextBuilder *groupBuilder = [SSKProtoGroupContext - builderWithId:[Cryptography generateRandomBytes:1] - type:SSKProtoGroupContextTypeDeliver]; - dataBuilder.group = [groupBuilder buildIgnoringErrors]; - sentBuilder.message = [dataBuilder buildIgnoringErrors]; - syncMessageBuilder.sent = [sentBuilder buildIgnoringErrors]; - contentBuilder.syncMessage = [syncMessageBuilder buildIgnoringErrors]; - return - [[contentBuilder buildIgnoringErrors] serializedDataIgnoringErrors]; - }]; - }]]; - [items addObject:[OWSTableItem itemWithTitle:@"Send empty sync sent message 6" - actionBlock:^{ - [DebugUIStress sendStressMessage:thread - block:^(SignalRecipient *recipient) { - SSKProtoContentBuilder *contentBuilder = - [SSKProtoContent builder]; - SSKProtoSyncMessageBuilder *syncMessageBuilder = - [SSKProtoSyncMessage builder]; - SSKProtoSyncMessageSentBuilder *sentBuilder = - [SSKProtoSyncMessageSent builder]; - sentBuilder.destination = @"abc"; - syncMessageBuilder.sent = - [sentBuilder buildIgnoringErrors]; - contentBuilder.syncMessage = - [syncMessageBuilder buildIgnoringErrors]; - return [[contentBuilder buildIgnoringErrors] - serializedDataIgnoringErrors]; - }]; - }]]; - - if ([thread isKindOfClass:[TSGroupThread class]]) { - TSGroupThread *groupThread = (TSGroupThread *)thread; - [items addObject:[OWSTableItem itemWithTitle:@"Hallucinate twin group" - actionBlock:^{ - [DebugUIStress hallucinateTwinGroup:groupThread]; - }]]; - } - - [items addObject:[OWSTableItem itemWithTitle:@"Make group w. unregistered users" - actionBlock:^{ - [DebugUIStress makeUnregisteredGroup]; - }]]; - -#endif - - return [OWSTableSection sectionWithTitle:self.name items:items]; -} - -#ifdef DEBUG - -+ (void)ensureGroupOfDataBuilder:(SSKProtoDataMessageBuilder *)dataBuilder thread:(TSThread *)thread -{ - OWSAssertDebug(dataBuilder); - OWSAssertDebug(thread); - - if (![thread isKindOfClass:[TSGroupThread class]]) { - return; - } - - TSGroupThread *groupThread = (TSGroupThread *)thread; - SSKProtoGroupContextBuilder *groupBuilder = - [SSKProtoGroupContext builderWithId:groupThread.groupModel.groupId type:SSKProtoGroupContextTypeDeliver]; - [groupBuilder setId:groupThread.groupModel.groupId]; - [dataBuilder setGroup:groupBuilder.buildIgnoringErrors]; -} - -+ (void)sendStressMessage:(TSOutgoingMessage *)message -{ - OWSAssertDebug(message); - - [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { - [self.messageSenderJobQueue addMessage:message transaction:transaction]; - }]; -} - -+ (void)sendStressMessage:(TSThread *)thread - block:(DynamicOutgoingMessageBlock)block -{ - OWSAssertDebug(thread); - OWSAssertDebug(block); - - OWSDynamicOutgoingMessage *message = - [[OWSDynamicOutgoingMessage alloc] initWithPlainTextDataBlock:block thread:thread]; - - [self sendStressMessage:message]; -} - -+ (void)sendStressMessage:(TSThread *)thread timestamp:(uint64_t)timestamp block:(DynamicOutgoingMessageBlock)block -{ - OWSAssertDebug(thread); - OWSAssertDebug(block); - - OWSDynamicOutgoingMessage *message = - [[OWSDynamicOutgoingMessage alloc] initWithPlainTextDataBlock:block timestamp:timestamp thread:thread]; - - [self sendStressMessage:message]; -} - -// Creates a new group (by cloning the current group) without informing the, -// other members. This can be used to test "group info requests", etc. -+ (void)hallucinateTwinGroup:(TSGroupThread *)groupThread -{ - __block TSGroupThread *thread; - [OWSPrimaryStorage.dbReadWriteConnection - readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { - TSGroupModel *groupModel = - [[TSGroupModel alloc] initWithTitle:[groupThread.groupModel.groupName stringByAppendingString:@" Copy"] - memberIds:groupThread.groupModel.groupMemberIds - image:groupThread.groupModel.groupImage - groupId:[Randomness generateRandomBytes:kGroupIdLength] - groupType:closedGroup - adminIds:groupThread.groupModel.groupAdminIds]; - thread = [TSGroupThread getOrCreateThreadWithGroupModel:groupModel transaction:transaction]; - }]; - OWSAssertDebug(thread); - - [SignalApp.sharedApp presentConversationForThread:thread animated:YES]; -} - -+ (void)makeUnregisteredGroup -{ - NSMutableArray *recipientIds = [NSMutableArray new]; - for (int i = 0; i < 3; i++) { - NSMutableString *recipientId = [@"+1999" mutableCopy]; - for (int j = 0; j < 3; j++) { - uint32_t digit = arc4random_uniform(10); - [recipientId appendFormat:@"%d", (int)digit]; - } - [recipientIds addObject:recipientId]; - } - [recipientIds addObject:self.tsAccountManager.localNumber]; - - __block TSGroupThread *thread; - [OWSPrimaryStorage.dbReadWriteConnection readWriteWithBlock:^( - YapDatabaseReadWriteTransaction *_Nonnull transaction) { - TSGroupModel *groupModel = [[TSGroupModel alloc] initWithTitle:NSUUID.UUID.UUIDString - memberIds:recipientIds - image:nil - groupId:[Randomness generateRandomBytes:kGroupIdLength] - groupType:closedGroup adminIds:@[ self.tsAccountManager.localNumber ]]; - thread = [TSGroupThread getOrCreateThreadWithGroupModel:groupModel transaction:transaction]; - }]; - OWSAssertDebug(thread); - - [SignalApp.sharedApp presentConversationForThread:thread animated:YES]; -} - -#endif - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/src/ViewControllers/DebugUI/DebugUISyncMessages.h b/Session/src/ViewControllers/DebugUI/DebugUISyncMessages.h deleted file mode 100644 index c9d7f5776..000000000 --- a/Session/src/ViewControllers/DebugUI/DebugUISyncMessages.h +++ /dev/null @@ -1,15 +0,0 @@ -// -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. -// - -#import "DebugUIPage.h" - -NS_ASSUME_NONNULL_BEGIN - -@class TSThread; - -@interface DebugUISyncMessages : DebugUIPage - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/src/ViewControllers/DebugUI/DebugUISyncMessages.m b/Session/src/ViewControllers/DebugUI/DebugUISyncMessages.m deleted file mode 100644 index 356a2ebe4..000000000 --- a/Session/src/ViewControllers/DebugUI/DebugUISyncMessages.m +++ /dev/null @@ -1,126 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "DebugUISyncMessages.h" -#import "DebugUIContacts.h" -#import "OWSTableViewController.h" -#import "Session-Swift.h" -#import "ThreadUtil.h" -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@implementation DebugUISyncMessages - -#pragma mark - Factory Methods - -- (NSString *)name -{ - return @"Sync Messages"; -} - -- (nullable OWSTableSection *)sectionForThread:(nullable TSThread *)thread -{ - NSArray *items = @[ - [OWSTableItem itemWithTitle:@"Send Contacts Sync Message" - actionBlock:^{ - [DebugUISyncMessages sendContactsSyncMessage]; - }], - [OWSTableItem itemWithTitle:@"Send Groups Sync Message" - actionBlock:^{ - [DebugUISyncMessages sendGroupSyncMessage]; - }], - [OWSTableItem itemWithTitle:@"Send Blocklist Sync Message" - actionBlock:^{ - [DebugUISyncMessages sendBlockListSyncMessage]; - }], - [OWSTableItem itemWithTitle:@"Send Configuration Sync Message" - actionBlock:^{ - [DebugUISyncMessages sendConfigurationSyncMessage]; - }], - ]; - return [OWSTableSection sectionWithTitle:self.name items:items]; -} - -+ (SSKMessageSenderJobQueue *)messageSenderJobQueue -{ - return SSKEnvironment.shared.messageSenderJobQueue; -} - -+ (OWSContactsManager *)contactsManager -{ - return Environment.shared.contactsManager; -} - -+ (OWSIdentityManager *)identityManager -{ - return [OWSIdentityManager sharedManager]; -} - -+ (OWSBlockingManager *)blockingManager -{ - return [OWSBlockingManager sharedManager]; -} - -+ (OWSProfileManager *)profileManager -{ - return [OWSProfileManager sharedManager]; -} - -+ (YapDatabaseConnection *)dbConnection -{ - return [OWSPrimaryStorage.sharedManager newDatabaseConnection]; -} - -+ (id)syncManager -{ - OWSAssertDebug(SSKEnvironment.shared.syncManager); - - return SSKEnvironment.shared.syncManager; -} - -#pragma mark - - -+ (void)sendContactsSyncMessage -{ - [[self.syncManager syncAllContacts] retainUntilComplete]; -} - -+ (void)sendGroupSyncMessage -{ - [[self.syncManager syncAllGroups] retainUntilComplete]; -} - -+ (void)sendBlockListSyncMessage -{ - [self.blockingManager syncBlockList]; -} - -+ (void)sendConfigurationSyncMessage -{ - [SSKEnvironment.shared.syncManager sendConfigurationSyncMessage]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/src/ViewControllers/DebugUI/DebugUITableViewController.h b/Session/src/ViewControllers/DebugUI/DebugUITableViewController.h deleted file mode 100644 index 12ad42344..000000000 --- a/Session/src/ViewControllers/DebugUI/DebugUITableViewController.h +++ /dev/null @@ -1,20 +0,0 @@ -// -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. -// - -#import "DebugUIPage.h" -#import "OWSTableViewController.h" - -NS_ASSUME_NONNULL_BEGIN - -@class TSThread; - -@interface DebugUITableViewController : OWSTableViewController - -+ (void)presentDebugUIFromViewController:(UIViewController *)fromViewController; - -+ (void)presentDebugUIForThread:(TSThread *)thread fromViewController:(UIViewController *)fromViewController; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/src/ViewControllers/DebugUI/DebugUITableViewController.m b/Session/src/ViewControllers/DebugUI/DebugUITableViewController.m deleted file mode 100644 index 839a274da..000000000 --- a/Session/src/ViewControllers/DebugUI/DebugUITableViewController.m +++ /dev/null @@ -1,152 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "DebugUITableViewController.h" -#import "DebugUIBackup.h" -#import "DebugUIContacts.h" -#import "DebugUIDiskUsage.h" -#import "DebugUIMessages.h" -#import "DebugUIMisc.h" -#import "DebugUISessionState.h" -#import "DebugUIStress.h" -#import "DebugUISyncMessages.h" -#import "Session-Swift.h" -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@implementation DebugUITableViewController - -- (void)viewWillAppear:(BOOL)animated -{ - [super viewWillAppear:animated]; - - // Block device from sleeping while in the Debug UI. - // - // This is useful if you're using long-running actions in the - // Debug UI, like "send 1k messages", etc. - [DeviceSleepManager.sharedInstance addBlockWithBlockObject:self]; -} - -- (void)viewWillDisappear:(BOOL)animated -{ - [super viewWillDisappear:animated]; - - [DeviceSleepManager.sharedInstance removeBlockWithBlockObject:self]; -} - -#pragma mark - Factory Methods - -- (void)pushPageWithSection:(OWSTableSection *)section -{ - DebugUITableViewController *viewController = [DebugUITableViewController new]; - OWSTableContents *contents = [OWSTableContents new]; - contents.title = section.headerTitle; - [contents addSection:section]; - viewController.contents = contents; - [self.navigationController pushViewController:viewController animated:YES]; -} - -+ (OWSTableItem *)itemForSubsection:(DebugUIPage *)page - viewController:(DebugUITableViewController *)viewController - thread:(nullable TSThread *)thread -{ - OWSAssertDebug(page); - OWSAssertDebug(viewController); - - __weak DebugUITableViewController *weakSelf = viewController; - return [OWSTableItem disclosureItemWithText:page.name - actionBlock:^{ - [weakSelf pushPageWithSection:[page sectionForThread:thread]]; - }]; -} - -+ (void)presentDebugUIForThread:(TSThread *)thread fromViewController:(UIViewController *)fromViewController -{ - OWSAssertDebug(thread); - OWSAssertDebug(fromViewController); - - DebugUITableViewController *viewController = [DebugUITableViewController new]; - - OWSTableContents *contents = [OWSTableContents new]; - contents.title = @"Debug: Conversation"; - - NSMutableArray *subsectionItems = [NSMutableArray new]; - - [subsectionItems - addObject:[self itemForSubsection:[DebugUIMessages new] viewController:viewController thread:thread]]; - [subsectionItems - addObject:[self itemForSubsection:[DebugUIContacts new] viewController:viewController thread:thread]]; - [subsectionItems - addObject:[self itemForSubsection:[DebugUIDiskUsage new] viewController:viewController thread:thread]]; - [subsectionItems - addObject:[self itemForSubsection:[DebugUISessionState new] viewController:viewController thread:thread]]; - if ([thread isKindOfClass:[TSContactThread class]]) { - [subsectionItems - addObject:[self itemForSubsection:[DebugUICalling new] viewController:viewController thread:thread]]; - } - [subsectionItems - addObject:[self itemForSubsection:[DebugUINotifications new] viewController:viewController thread:thread]]; - [subsectionItems addObject:[self itemForSubsection:[DebugUIProfile new] viewController:viewController thread:thread]]; - [subsectionItems - addObject:[self itemForSubsection:[DebugUIStress new] viewController:viewController thread:thread]]; - [subsectionItems - addObject:[self itemForSubsection:[DebugUISyncMessages new] viewController:viewController thread:thread]]; - OWSTableItem *sharedDataFileBrowserItem = [OWSTableItem - disclosureItemWithText:@"📁 Shared Container" - actionBlock:^{ - NSURL *baseURL = [NSURL URLWithString:[OWSFileSystem appSharedDataDirectoryPath]]; - DebugUIFileBrowser *fileBrowser = [[DebugUIFileBrowser alloc] initWithFileURL:baseURL]; - [viewController.navigationController pushViewController:fileBrowser animated:YES]; - }]; - [subsectionItems addObject:sharedDataFileBrowserItem]; - OWSTableItem *documentsFileBrowserItem = [OWSTableItem - disclosureItemWithText:@"📁 App Container" - actionBlock:^{ - NSString *libraryPath = [OWSFileSystem appLibraryDirectoryPath]; - NSString *containerPath = [libraryPath stringByDeletingLastPathComponent]; - NSURL *baseURL = [NSURL fileURLWithPath:containerPath]; - DebugUIFileBrowser *fileBrowser = [[DebugUIFileBrowser alloc] initWithFileURL:baseURL]; - [viewController.navigationController pushViewController:fileBrowser animated:YES]; - }]; - [subsectionItems addObject:documentsFileBrowserItem]; - [subsectionItems - addObject:[self itemForSubsection:[DebugUIBackup new] viewController:viewController thread:thread]]; - [subsectionItems addObject:[self itemForSubsection:[DebugUIMisc new] viewController:viewController thread:thread]]; - - [contents addSection:[OWSTableSection sectionWithTitle:@"Sections" items:subsectionItems]]; - - viewController.contents = contents; - [viewController presentFromViewController:fromViewController]; -} - -+ (void)presentDebugUIFromViewController:(UIViewController *)fromViewController -{ - OWSAssertDebug(fromViewController); - - DebugUITableViewController *viewController = [DebugUITableViewController new]; - - OWSTableContents *contents = [OWSTableContents new]; - contents.title = @"Debug UI"; - - NSMutableArray *subsectionItems = [NSMutableArray new]; - [subsectionItems addObject:[self itemForSubsection:[DebugUIContacts new] viewController:viewController thread:nil]]; - [subsectionItems - addObject:[self itemForSubsection:[DebugUIDiskUsage new] viewController:viewController thread:nil]]; - [subsectionItems - addObject:[self itemForSubsection:[DebugUISessionState new] viewController:viewController thread:nil]]; - [subsectionItems - addObject:[self itemForSubsection:[DebugUISyncMessages new] viewController:viewController thread:nil]]; - [subsectionItems addObject:[self itemForSubsection:[DebugUIBackup new] viewController:viewController thread:nil]]; - [subsectionItems addObject:[self itemForSubsection:[DebugUIMisc new] viewController:viewController thread:nil]]; - [contents addSection:[OWSTableSection sectionWithTitle:@"Sections" items:subsectionItems]]; - - viewController.contents = contents; - [viewController presentFromViewController:fromViewController]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/test/Assets/test-gif.gif b/Session/test/Assets/test-gif.gif deleted file mode 100644 index 0dcdebc80..000000000 Binary files a/Session/test/Assets/test-gif.gif and /dev/null differ diff --git a/Session/test/Assets/test-jpg.JPG b/Session/test/Assets/test-jpg.JPG deleted file mode 100644 index 0b82d24e7..000000000 Binary files a/Session/test/Assets/test-jpg.JPG and /dev/null differ diff --git a/Session/test/Assets/test-mp3.mp3 b/Session/test/Assets/test-mp3.mp3 deleted file mode 100644 index 64a658310..000000000 Binary files a/Session/test/Assets/test-mp3.mp3 and /dev/null differ diff --git a/Session/test/Assets/test-mp4.mp4 b/Session/test/Assets/test-mp4.mp4 deleted file mode 100644 index 94a7f732a..000000000 Binary files a/Session/test/Assets/test-mp4.mp4 and /dev/null differ diff --git a/Session/test/Models/MantlePerfTest.swift b/Session/test/Models/MantlePerfTest.swift deleted file mode 100644 index 400f60ce7..000000000 --- a/Session/test/Models/MantlePerfTest.swift +++ /dev/null @@ -1,42 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -import XCTest -@testable import SignalUtilitiesKit -@testable import SignalUtilitiesKit - -class MantlePerfTest: SignalBaseTest { - - var primaryStorage: OWSPrimaryStorage { - return SSKEnvironment.shared.primaryStorage - } - - override func setUp() { - // Put setup code here. This method is called before the invocation of each test method in the class. - } - - override func tearDown() { - // Put teardown code here. This method is called after the invocation of each test method in the class. - } - - func testPerformanceExample() { - let migration = OWS110SortIdMigration() - - self.measureMetrics(XCTestCase.defaultPerformanceMetrics, automaticallyStartMeasuring: false) { - _ = OutgoingMessageFactory().create(count: 100) - - startMeasuring() - - let migrationCompleted = expectation(description: "migrationCompleted") - migration.runUp(completion: migrationCompleted.fulfill) - - self.wait(for: [migrationCompleted], timeout: 10) - - stopMeasuring() - - TSInteraction.removeAllObjectsInCollection() - } - } - -} diff --git a/Session/test/Models/OWSDeviceProvisioningURLParserTest.m b/Session/test/Models/OWSDeviceProvisioningURLParserTest.m deleted file mode 100644 index f315a6dff..000000000 --- a/Session/test/Models/OWSDeviceProvisioningURLParserTest.m +++ /dev/null @@ -1,49 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "OWSDeviceProvisioningURLParser.h" -#import "SignalBaseTest.h" -#import - -@interface OWSDeviceProvisioningURLParserTest : SignalBaseTest - -@end - -@implementation OWSDeviceProvisioningURLParserTest - -- (void)testValid -{ - OWSDeviceProvisioningURLParser *parser = [[OWSDeviceProvisioningURLParser alloc] initWithProvisioningURL:@""]; - XCTAssertFalse(parser.isValid); - - parser = [[OWSDeviceProvisioningURLParser alloc] initWithProvisioningURL:@"ts:/?uuid=MTIz"]; - XCTAssertFalse(parser.isValid); - - parser = [[OWSDeviceProvisioningURLParser alloc] initWithProvisioningURL:@"ts:/?pub_key=MTIz"]; - XCTAssertFalse(parser.isValid); - - parser = [[OWSDeviceProvisioningURLParser alloc] initWithProvisioningURL:@"ts:/uuid=asd&pub_key=MTIz"]; - XCTAssertFalse(parser.isValid); - - parser = [[OWSDeviceProvisioningURLParser alloc] initWithProvisioningURL:@"ts:/?uuid=asd&pub_key=MTIz"]; - XCTAssert(parser.isValid); -} - -- (void)testPublicKey -{ - OWSDeviceProvisioningURLParser *parser = - [[OWSDeviceProvisioningURLParser alloc] initWithProvisioningURL:@"ts:/?uuid=asd&pub_key=MTIz"]; - - XCTAssertEqualObjects(@"MTIz", [parser.publicKey base64EncodedString]); -} - -- (void)testEphemeralDeviceId -{ - OWSDeviceProvisioningURLParser *parser = - [[OWSDeviceProvisioningURLParser alloc] initWithProvisioningURL:@"ts:/?uuid=asd&pub_key=MTIz"]; - - XCTAssertEqualObjects(@"asd", parser.ephemeralDeviceId); -} - -@end diff --git a/Session/test/SSKTests/ParamParserTest.swift b/Session/test/SSKTests/ParamParserTest.swift deleted file mode 100644 index 49c92769f..000000000 --- a/Session/test/SSKTests/ParamParserTest.swift +++ /dev/null @@ -1,118 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -import XCTest - -class ParamParserTest: SignalBaseTest { - - override func setUp() { - super.setUp() - // Put setup code here. This method is called before the invocation of each test method in the class. - } - - override func tearDown() { - // Put teardown code here. This method is called after the invocation of each test method in the class. - super.tearDown() - } - - let dict: [String: Any] = ["some_int": 11, "some_string": "asdf", "large_int": Int64.max, "negative_int": -10] - var parser: ParamParser { - return ParamParser(dictionary: dict) - } - - func testExample() { - XCTAssertEqual(11, try parser.required(key: "some_int")) - XCTAssertEqual(11, try parser.optional(key: "some_int")) - - let expectedString: String = "asdf" - XCTAssertEqual(expectedString, try parser.required(key: "some_string")) - XCTAssertEqual(expectedString, try parser.optional(key: "some_string")) - - XCTAssertEqual(nil, try parser.optional(key: "does_not_exist") as String?) - XCTAssertThrowsError(try parser.required(key: "does_not_exist") as String) - } - - func testNumeric() { - let expectedInt32: Int32 = 11 - XCTAssertEqual(expectedInt32, try parser.required(key: "some_int")) - XCTAssertEqual(expectedInt32, try parser.optional(key: "some_int")) - - let expectedInt64: Int64 = 11 - XCTAssertEqual(expectedInt64, try parser.required(key: "some_int")) - XCTAssertEqual(expectedInt64, try parser.optional(key: "some_int")) - } - - func testNumericSizeFailures() { - XCTAssertThrowsError(try { - let _: Int32 = try parser.required(key: "large_int") - }()) - - XCTAssertThrowsError(try { - let _: Int32? = try parser.optional(key: "large_int") - }()) - - XCTAssertNoThrow(try { - let _: Int64 = try parser.required(key: "large_int") - }()) - } - - func testNumericSignFailures() { - XCTAssertNoThrow(try { - let _: Int = try parser.required(key: "negative_int") - }()) - - XCTAssertNoThrow(try { - let _: Int64 = try parser.required(key: "negative_int") - }()) - - XCTAssertThrowsError(try { - let _: UInt64 = try parser.required(key: "negative_int") - }()) - } - - // MARK: Base64EncodedData - - func testBase64Data_Valid() { - let originalString = "asdf" - let utf8Data: Data = originalString.data(using: .utf8)! - let base64EncodedString = utf8Data.base64EncodedString() - - let dict: [String: Any] = ["some_data": base64EncodedString] - let parser = ParamParser(dictionary: dict) - - XCTAssertEqual(utf8Data, try parser.requiredBase64EncodedData(key: "some_data")) - XCTAssertEqual(utf8Data, try parser.optionalBase64EncodedData(key: "some_data")) - - let data: Data = try! parser.requiredBase64EncodedData(key: "some_data") - let roundTripString = String(data: data, encoding: .utf8) - XCTAssertEqual(originalString, roundTripString) - } - - func testBase64Data_EmptyString() { - let dict: [String: Any] = ["some_data": ""] - let parser = ParamParser(dictionary: dict) - - XCTAssertThrowsError(try parser.requiredBase64EncodedData(key: "some_data")) - XCTAssertEqual(nil, try parser.optionalBase64EncodedData(key: "some_data")) - } - - func testBase64Data_NSNull() { - let dict: [String: Any] = ["some_data": NSNull()] - let parser = ParamParser(dictionary: dict) - - XCTAssertThrowsError(try parser.requiredBase64EncodedData(key: "some_data")) - XCTAssertEqual(nil, try parser.optionalBase64EncodedData(key: "some_data")) - } - - func testBase64Data_Invalid() { - // invalid base64 data - let base64EncodedString = "YXNkZg" - - let dict: [String: Any] = ["some_data": base64EncodedString] - let parser = ParamParser(dictionary: dict) - - XCTAssertThrowsError(try parser.requiredBase64EncodedData(key: "some_data")) - XCTAssertThrowsError(try parser.optionalBase64EncodedData(key: "some_data")) - } -} diff --git a/Session/test/SSKTests/SSKProtoEnvelopeTest.swift b/Session/test/SSKTests/SSKProtoEnvelopeTest.swift deleted file mode 100644 index 4f5b9424b..000000000 --- a/Session/test/SSKTests/SSKProtoEnvelopeTest.swift +++ /dev/null @@ -1,103 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -import XCTest - -import SignalUtilitiesKit -import SwiftProtobuf - -class SSKProtoEnvelopeTest: SignalBaseTest { - - override func setUp() { - super.setUp() - // Put setup code here. This method is called before the invocation of each test method in the class. - } - - override func tearDown() { - // Put teardown code here. This method is called after the invocation of each test method in the class. - super.tearDown() - } - - func testParse_EmptyData() { - let data = Data() - XCTAssertThrowsError(try SSKProtoEnvelope.parseData(data)) - } - - func testParse_UnparseableData() { - let data = "asdf".data(using: .utf8)! - XCTAssertThrowsError(try SSKProtoEnvelope.parseData(data)) { error in - XCTAssert(error is SwiftProtobuf.BinaryDecodingError) - } - } - - func testParse_ValidData() { - // `encodedData` was derived thus: - // let builder = SSKProtoEnvelopeBuilder() - // builder.setTimestamp(NSDate.ows_millisecondTimeStamp()) - // builder.setSource("+15551231234") - // builder.setSourceDevice(1) - // builder.setType(SSKProtoEnvelopeType.ciphertext) - // let encodedData = builder.build().data()!.base64EncodedString() - let encodedData = "CAESDCsxNTU1MTIzMTIzNCjKm4WazSw4AQ==" - let data = Data(base64Encoded: encodedData)! - - XCTAssertNoThrow(try SSKProtoEnvelope.parseData(data)) - } - - func testParse_invalidData() { - // `encodedData` was derived thus: - // let builder = SSKProtoEnvelopeBuilder() - // builder.setTimestamp(NSDate.ows_millisecondTimeStamp()) - // builder.setSource("+15551231234") - // builder.setSourceDevice(1) - // // MISSING TYPE! - // let encodedData = builder.build().data()!.base64EncodedString() - let encodedData = "EgwrMTU1NTEyMzEyMzQojdmOms0sOAE=" - let data = Data(base64Encoded: encodedData)! - - XCTAssertThrowsError(try SSKProtoEnvelope.parseData(data)) { (error) -> Void in - switch error { - case SSKProtoError.invalidProtobuf: - break - default: - XCTFail("unexpected error: \(error)") - } - } - } - - func testParse_roundtrip() { - let builder = SSKProtoEnvelope.builder(type: SSKProtoEnvelope.SSKProtoEnvelopeType.prekeyBundle, - timestamp: 123) - builder.setSource("+13213214321") - builder.setSourceDevice(1) - - let phonyContent = "phony data".data(using: .utf8)! - - builder.setContent(phonyContent) - - var envelopeData: Data - do { - envelopeData = try builder.buildSerializedData() - } catch { - XCTFail("Couldn't serialize data.") - return - } - - var envelope: SSKProtoEnvelope - do { - envelope = try SSKProtoEnvelope.parseData(envelopeData) - } catch { - XCTFail("Couldn't serialize data.") - return - } - - XCTAssertEqual(envelope.type, SSKProtoEnvelope.SSKProtoEnvelopeType.prekeyBundle) - XCTAssertEqual(envelope.timestamp, 123) - XCTAssertEqual(envelope.source, "+13213214321") - XCTAssertEqual(envelope.sourceDevice, 1) - XCTAssertTrue(envelope.hasContent) - XCTAssertEqual(envelope.content, phonyContent) - XCTAssertFalse(envelope.hasLegacyMessage) - } -} diff --git a/Session/test/SignalBaseTest.h b/Session/test/SignalBaseTest.h deleted file mode 100644 index fc585eaaa..000000000 --- a/Session/test/SignalBaseTest.h +++ /dev/null @@ -1,20 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "MockEnvironment.h" -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface SignalBaseTest : XCTestCase - -- (void)readWithBlock:(void (^)(YapDatabaseReadTransaction *transaction))block; - -- (void)readWriteWithBlock:(void (^)(YapDatabaseReadWriteTransaction *transaction))block; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/test/SignalBaseTest.m b/Session/test/SignalBaseTest.m deleted file mode 100644 index e6dc17962..000000000 --- a/Session/test/SignalBaseTest.m +++ /dev/null @@ -1,54 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "SignalBaseTest.h" -#import "Environment.h" -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@implementation SignalBaseTest - -- (void)setUp -{ - OWSLogInfo(@""); - - [super setUp]; - - ClearCurrentAppContextForTests(); - [Environment clearSharedForTests]; - [SSKEnvironment clearSharedForTests]; - - SetCurrentAppContext([TestAppContext new]); - - [MockSSKEnvironment activate]; - [MockEnvironment activate]; -} - -- (void)tearDown -{ - OWSLogInfo(@""); - - [super tearDown]; -} - -- (void)readWithBlock:(void (^)(YapDatabaseReadTransaction *transaction))block -{ - OWSAssert(block); - - [[SSKEnvironment.shared.primaryStorage newDatabaseConnection] readWithBlock:block]; -} - - -- (void)readWriteWithBlock:(void (^)(YapDatabaseReadWriteTransaction *transaction))block -{ - OWSAssert(block); - - [[SSKEnvironment.shared.primaryStorage newDatabaseConnection] readWriteWithBlock:block]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/test/SignalTests-Bridging-Header.h b/Session/test/SignalTests-Bridging-Header.h deleted file mode 100644 index daa6f7e83..000000000 --- a/Session/test/SignalTests-Bridging-Header.h +++ /dev/null @@ -1,6 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "Signal-Bridging-Header.h" -#import "SignalBaseTest.h" diff --git a/Session/test/Supporting Files/SignalTests-Info.plist b/Session/test/Supporting Files/SignalTests-Info.plist deleted file mode 100644 index 169b6f710..000000000 --- a/Session/test/Supporting Files/SignalTests-Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - ${EXECUTABLE_NAME} - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundlePackageType - BNDL - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1 - - diff --git a/Session/test/Supporting Files/whisperFake.cer b/Session/test/Supporting Files/whisperFake.cer deleted file mode 100644 index fe8ad1d3d..000000000 Binary files a/Session/test/Supporting Files/whisperFake.cer and /dev/null differ diff --git a/Session/test/TestUtil.h b/Session/test/TestUtil.h deleted file mode 100644 index dbc0f4c08..000000000 --- a/Session/test/TestUtil.h +++ /dev/null @@ -1,12 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#define testPhoneNumber1 [PhoneNumber phoneNumberFromE164:@"+19027777777"] -#define testPhoneNumber2 [PhoneNumber phoneNumberFromE164:@"+19028888888"] - -#define test(expressionExpectedToBeTrue) XCTAssert(expressionExpectedToBeTrue, @"") -#define testThrows(expressionExpectedToThrow) XCTAssertThrows(expressionExpectedToThrow, @"") -#define testDoesNotThrow(expressionExpectedToNotThrow) expressionExpectedToNotThrow -#define testChurnUntil(condition, timeout) test(_testChurnHelper(^int{ return condition; }, timeout)) -#define testChurnAndConditionMustStayTrue(condition, timeout) test(!_testChurnHelper(^int{ return !(condition); }, timeout)) diff --git a/Session/test/ViewControllers/ConversationViewItemTest.m b/Session/test/ViewControllers/ConversationViewItemTest.m deleted file mode 100644 index 9b618ed4c..000000000 --- a/Session/test/ViewControllers/ConversationViewItemTest.m +++ /dev/null @@ -1,275 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "ConversationViewItem.h" -#import "SignalBaseTest.h" -#import -#import -#import -#import -#import -#import -#import -#import - -/* -@interface ConversationViewItemTest : SignalBaseTest - -@property TSThread *thread; -@property ConversationStyle *conversationStyle; - -@end - -@implementation ConversationViewItemTest - -- (void)setUp -{ - [super setUp]; - self.thread = [TSContactThread getOrCreateThreadWithContactId:@"+15555555"]; - self.conversationStyle = [[ConversationStyle alloc] initWithThread:self.thread]; -} - -- (void)tearDown -{ - // Put teardown code here. This method is called after the invocation of each test method in the class. - [super tearDown]; -} - -- (NSString *)fakeTextMessageText -{ - return @"abc"; -} - -- (ConversationInteractionViewItem *)textViewItem -{ - TSOutgoingMessage *message = - [TSOutgoingMessage outgoingMessageInThread:self.thread messageBody:self.fakeTextMessageText attachmentId:nil]; - [message save]; - __block ConversationInteractionViewItem *viewItem = nil; - [self readWithBlock:^(YapDatabaseReadTransaction *transaction) { - viewItem = [[ConversationInteractionViewItem alloc] initWithInteraction:message - isGroupThread:NO - transaction:transaction - conversationStyle:self.conversationStyle]; - }]; - return viewItem; -} - -- (ConversationInteractionViewItem *)viewItemWithAttachmentMimetype:(NSString *)mimeType filename:(NSString *)filename -{ - OWSAssertDebug(filename.length > 0); - - NSString *resourcePath = [[NSBundle bundleForClass:[self class]] resourcePath]; - NSString *filePath = [resourcePath stringByAppendingPathComponent:filename]; - - OWSAssertDebug([[NSFileManager defaultManager] fileExistsAtPath:filePath]); - - DataSource *dataSource = [DataSourcePath dataSourceWithFilePath:filePath shouldDeleteOnDeallocation:NO]; - dataSource.sourceFilename = filename; - TSAttachmentStream *attachment = [AttachmentStreamFactory createWithContentType:mimeType dataSource:dataSource]; - - TSOutgoingMessage *message = - [TSOutgoingMessage outgoingMessageInThread:self.thread messageBody:nil attachmentId:attachment.uniqueId]; - [message save]; - - __block ConversationInteractionViewItem *viewItem = nil; - [self readWithBlock:^(YapDatabaseReadTransaction *transaction) { - viewItem = [[ConversationInteractionViewItem alloc] initWithInteraction:message - isGroupThread:NO - transaction:transaction - conversationStyle:self.conversationStyle]; - }]; - - return viewItem; -} - -- (ConversationInteractionViewItem *)stillImageViewItem -{ - return [self viewItemWithAttachmentMimetype:OWSMimeTypeImageJpeg filename:@"test-jpg.jpg"]; -} - -- (ConversationInteractionViewItem *)animatedImageViewItem -{ - return [self viewItemWithAttachmentMimetype:OWSMimeTypeImageGif filename:@"test-gif.gif"]; -} - -- (ConversationInteractionViewItem *)videoViewItem -{ - return [self viewItemWithAttachmentMimetype:@"video/mp4" filename:@"test-mp4.mp4"]; -} - -- (ConversationInteractionViewItem *)audioViewItem -{ - return [self viewItemWithAttachmentMimetype:@"audio/mp3" filename:@"test-mp3.mp3"]; -} - -// Test Delete - -- (void)testPerformDeleteEditingActionWithNonMediaMessage -{ - ConversationInteractionViewItem *viewItem = self.textViewItem; - - XCTAssertNotNil([TSMessage fetchObjectWithUniqueID:viewItem.interaction.uniqueId]); - [viewItem deleteAction]; - XCTAssertNil([TSMessage fetchObjectWithUniqueID:viewItem.interaction.uniqueId]); -} - -- (void)testPerformDeleteActionWithPhotoMessage -{ - ConversationInteractionViewItem *viewItem = self.stillImageViewItem; - - XCTAssertEqual((NSUInteger)1, ((TSMessage *)viewItem.interaction).attachmentIds.count); - NSString *_Nullable attachmentId = ((TSMessage *)viewItem.interaction).attachmentIds.firstObject; - XCTAssertNotNil(attachmentId); - TSAttachment *_Nullable attachment = [TSAttachment fetchObjectWithUniqueID:attachmentId]; - XCTAssertTrue([attachment isKindOfClass:[TSAttachmentStream class]]); - TSAttachmentStream *_Nullable attachmentStream = (TSAttachmentStream *)attachment; - NSString *_Nullable filePath = attachmentStream.originalFilePath; - XCTAssertNotNil(filePath); - - XCTAssertNotNil([TSMessage fetchObjectWithUniqueID:viewItem.interaction.uniqueId]); - XCTAssertNotNil([TSAttachment fetchObjectWithUniqueID:attachmentId]); - XCTAssertTrue([[NSFileManager defaultManager] fileExistsAtPath:filePath]); - [viewItem deleteAction]; - XCTAssertNil([TSMessage fetchObjectWithUniqueID:viewItem.interaction.uniqueId]); - XCTAssertNil([TSAttachment fetchObjectWithUniqueID:attachmentId]); - XCTAssertFalse([[NSFileManager defaultManager] fileExistsAtPath:filePath]); -} - -- (void)testPerformDeleteEditingActionWithAnimatedMessage -{ - ConversationInteractionViewItem *viewItem = self.animatedImageViewItem; - - XCTAssertEqual((NSUInteger)1, ((TSMessage *)viewItem.interaction).attachmentIds.count); - NSString *_Nullable attachmentId = ((TSMessage *)viewItem.interaction).attachmentIds.firstObject; - XCTAssertNotNil(attachmentId); - TSAttachment *_Nullable attachment = [TSAttachment fetchObjectWithUniqueID:attachmentId]; - XCTAssertTrue([attachment isKindOfClass:[TSAttachmentStream class]]); - TSAttachmentStream *_Nullable attachmentStream = (TSAttachmentStream *)attachment; - NSString *_Nullable filePath = attachmentStream.originalFilePath; - XCTAssertNotNil(filePath); - - XCTAssertNotNil([TSMessage fetchObjectWithUniqueID:viewItem.interaction.uniqueId]); - XCTAssertNotNil([TSAttachment fetchObjectWithUniqueID:attachmentId]); - XCTAssertTrue([[NSFileManager defaultManager] fileExistsAtPath:filePath]); - [viewItem deleteAction]; - XCTAssertNil([TSMessage fetchObjectWithUniqueID:viewItem.interaction.uniqueId]); - XCTAssertNil([TSAttachment fetchObjectWithUniqueID:attachmentId]); - XCTAssertFalse([[NSFileManager defaultManager] fileExistsAtPath:filePath]); -} - -- (void)testPerformDeleteEditingActionWithVideoMessage -{ - ConversationInteractionViewItem *viewItem = self.videoViewItem; - - XCTAssertEqual((NSUInteger)1, ((TSMessage *)viewItem.interaction).attachmentIds.count); - NSString *_Nullable attachmentId = ((TSMessage *)viewItem.interaction).attachmentIds.firstObject; - XCTAssertNotNil(attachmentId); - TSAttachment *_Nullable attachment = [TSAttachment fetchObjectWithUniqueID:attachmentId]; - XCTAssertTrue([attachment isKindOfClass:[TSAttachmentStream class]]); - TSAttachmentStream *_Nullable attachmentStream = (TSAttachmentStream *)attachment; - NSString *_Nullable filePath = attachmentStream.originalFilePath; - XCTAssertNotNil(filePath); - - XCTAssertNotNil([TSMessage fetchObjectWithUniqueID:viewItem.interaction.uniqueId]); - XCTAssertNotNil([TSAttachment fetchObjectWithUniqueID:attachmentId]); - XCTAssertTrue([[NSFileManager defaultManager] fileExistsAtPath:filePath]); - [viewItem deleteAction]; - XCTAssertNil([TSMessage fetchObjectWithUniqueID:viewItem.interaction.uniqueId]); - XCTAssertNil([TSAttachment fetchObjectWithUniqueID:attachmentId]); - XCTAssertFalse([[NSFileManager defaultManager] fileExistsAtPath:filePath]); -} - -- (void)testPerformDeleteEditingActionWithAudioMessage -{ - ConversationInteractionViewItem *viewItem = self.audioViewItem; - - XCTAssertEqual((NSUInteger)1, ((TSMessage *)viewItem.interaction).attachmentIds.count); - NSString *_Nullable attachmentId = ((TSMessage *)viewItem.interaction).attachmentIds.firstObject; - XCTAssertNotNil(attachmentId); - TSAttachment *_Nullable attachment = [TSAttachment fetchObjectWithUniqueID:attachmentId]; - XCTAssertTrue([attachment isKindOfClass:[TSAttachmentStream class]]); - TSAttachmentStream *_Nullable attachmentStream = (TSAttachmentStream *)attachment; - NSString *_Nullable filePath = attachmentStream.originalFilePath; - XCTAssertNotNil(filePath); - - XCTAssertNotNil([TSMessage fetchObjectWithUniqueID:viewItem.interaction.uniqueId]); - XCTAssertNotNil([TSAttachment fetchObjectWithUniqueID:attachmentId]); - XCTAssertTrue([[NSFileManager defaultManager] fileExistsAtPath:filePath]); - [viewItem deleteAction]; - XCTAssertNil([TSMessage fetchObjectWithUniqueID:viewItem.interaction.uniqueId]); - XCTAssertNil([TSAttachment fetchObjectWithUniqueID:attachmentId]); - XCTAssertFalse([[NSFileManager defaultManager] fileExistsAtPath:filePath]); -} - -// Test Copy - -- (void)testPerformCopyEditingActionWithNonMediaMessage -{ - // Reset the pasteboard. - UIPasteboard.generalPasteboard.items = @[]; - XCTAssertNil(UIPasteboard.generalPasteboard.string); - - ConversationInteractionViewItem *viewItem = self.textViewItem; - [viewItem copyTextAction]; - XCTAssertEqualObjects(self.fakeTextMessageText, UIPasteboard.generalPasteboard.string); -} - -- (void)testPerformCopyEditingActionWithStillImageMessage -{ - // Reset the pasteboard. - UIPasteboard.generalPasteboard.items = @[]; - XCTAssertNil(UIPasteboard.generalPasteboard.image); - XCTAssertNil([UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeJPEG]); - - ConversationInteractionViewItem *viewItem = self.stillImageViewItem; - [viewItem copyMediaAction]; - NSData *_Nullable copiedData = [UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeJPEG]; - XCTAssertTrue(copiedData.length > 0); -} - -- (void)testPerformCopyEditingActionWithAnimatedImageMessage -{ - // Reset the pasteboard. - UIPasteboard.generalPasteboard.items = @[]; - XCTAssertNil(UIPasteboard.generalPasteboard.image); - XCTAssertNil([UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeGIF]); - - ConversationInteractionViewItem *viewItem = self.animatedImageViewItem; - [viewItem copyMediaAction]; - NSData *_Nullable copiedData = [UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeGIF]; - XCTAssertTrue(copiedData.length > 0); -} - -- (void)testPerformCopyEditingActionWithVideoMessage -{ - // Reset the pasteboard. - UIPasteboard.generalPasteboard.items = @[]; - XCTAssertNil([UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeMPEG4]); - - ConversationInteractionViewItem *viewItem = self.videoViewItem; - [viewItem copyMediaAction]; - NSData *_Nullable copiedData = [UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeMPEG4]; - XCTAssertTrue(copiedData.length > 0); -} - -- (void)testPerformCopyEditingActionWithMp3AudioMessage -{ - // Reset the pasteboard. - UIPasteboard.generalPasteboard.items = @[]; - XCTAssertNil([UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeMP3]); - - ConversationInteractionViewItem *viewItem = self.audioViewItem; - [viewItem copyMediaAction]; - NSData *_Nullable copiedData = [UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeMP3]; - XCTAssertTrue(copiedData.length > 0); -} - -- (void)unknownAction:(id)sender -{ - // It's easier to create this stub method than to suppress the "unknown selector" build warnings. -} - -@end - */ diff --git a/Session/test/call/PeerConnectionClientTest.swift b/Session/test/call/PeerConnectionClientTest.swift deleted file mode 100644 index e064e43a2..000000000 --- a/Session/test/call/PeerConnectionClientTest.swift +++ /dev/null @@ -1,139 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -import XCTest -import WebRTC -@testable import Session - -/* -/** - * Playing the role of the call service. - */ -class FakePeerConnectionClientDelegate: PeerConnectionClientDelegate { - - enum ConnectionState { - case connected, disconnected, failed - } - - var connectionState: ConnectionState? - var localIceCandidates = [RTCIceCandidate]() - var dataChannelMessages = [WebRTCProtoData]() - - func peerConnectionClientIceConnected(_ peerconnectionClient: PeerConnectionClient) { - connectionState = .connected - } - - func peerConnectionClientIceDisconnected(_ peerconnectionClient: PeerConnectionClient) { - connectionState = .disconnected - } - - func peerConnectionClientIceFailed(_ peerconnectionClient: PeerConnectionClient) { - connectionState = .failed - } - - func peerConnectionClient(_ peerconnectionClient: PeerConnectionClient, addedLocalIceCandidate iceCandidate: RTCIceCandidate) { - localIceCandidates.append(iceCandidate) - } - - func peerConnectionClient(_ peerconnectionClient: PeerConnectionClient, received dataChannelMessage: WebRTCProtoData) { - dataChannelMessages.append(dataChannelMessage) - } - - func peerConnectionClient(_ peerconnectionClient: PeerConnectionClient, didUpdateLocalVideoCaptureSession captureSession: AVCaptureSession?) { - } - - func peerConnectionClient(_ peerconnectionClient: PeerConnectionClient, didUpdateRemoteVideoTrack videoTrack: RTCVideoTrack?) { - } -} - -class PeerConnectionClientTest: SignalBaseTest { - - var client: PeerConnectionClient! - var clientDelegate: FakePeerConnectionClientDelegate! - var peerConnection: RTCPeerConnection! - var dataChannel: RTCDataChannel! - - override func setUp() { - super.setUp() - - let iceServers = [RTCIceServer]() - clientDelegate = FakePeerConnectionClientDelegate() - client = PeerConnectionClient(iceServers: iceServers, delegate: clientDelegate, callDirection: .outgoing, useTurnOnly: false) - peerConnection = client.peerConnectionForTests() - dataChannel = client.dataChannelForTests() - } - - override func tearDown() { - client.terminate() - - super.tearDown() - } - - func testIceConnectionStateChange() { - XCTAssertNil(clientDelegate.connectionState) - - client.peerConnection(peerConnection, didChange: RTCIceConnectionState.connected) - waitForPeerConnectionClient() - XCTAssertEqual(FakePeerConnectionClientDelegate.ConnectionState.connected, clientDelegate.connectionState) - - client.peerConnection(peerConnection, didChange: RTCIceConnectionState.completed) - waitForPeerConnectionClient() - XCTAssertEqual(FakePeerConnectionClientDelegate.ConnectionState.connected, clientDelegate.connectionState) - - client.peerConnection(peerConnection, didChange: RTCIceConnectionState.failed) - waitForPeerConnectionClient() - XCTAssertEqual(FakePeerConnectionClientDelegate.ConnectionState.failed, clientDelegate.connectionState) - } - - func testIceCandidateAdded() { - XCTAssertEqual(0, clientDelegate.localIceCandidates.count) - - let candidate1 = RTCIceCandidate(sdp: "sdp-1", sdpMLineIndex: 0, sdpMid: "sdpMid-1") - let candidate2 = RTCIceCandidate(sdp: "sdp-2", sdpMLineIndex: 0, sdpMid: "sdpMid-2") - let candidate3 = RTCIceCandidate(sdp: "sdp-3", sdpMLineIndex: 0, sdpMid: "sdpMid-3") - - client.peerConnection(peerConnection, didGenerate: candidate1) - client.peerConnection(peerConnection, didGenerate: candidate2) - client.peerConnection(peerConnection, didGenerate: candidate3) - - waitForPeerConnectionClient() - - XCTAssertEqual(3, clientDelegate.localIceCandidates.count) - } - - func waitForPeerConnectionClient() { - // PeerConnectionClient processes RTCPeerConnectionDelegate invocations first on the signaling queue... - client.flushSignalingQueueForTests() - // ...then on the main queue. - let expectation = self.expectation(description: "Wait for PeerConnectionClient to call delegate method on main queue") - DispatchQueue.main.async { - expectation.fulfill() - } - self.waitForExpectations(timeout: 1.0, handler: nil) - } - - func testDataChannelMessage() { - XCTAssertEqual(0, clientDelegate.dataChannelMessages.count) - - let hangupBuilder = WebRTCProtoHangup.builder(id: 123) - let hangup = try! hangupBuilder.build() - - let dataBuilder = WebRTCProtoData.builder() - dataBuilder.setHangup(hangup) - let hangupData = try! dataBuilder.buildSerializedData() - let hangupBuffer = RTCDataBuffer(data: hangupData, isBinary: false) - client.dataChannel(dataChannel, didReceiveMessageWith: hangupBuffer) - - waitForPeerConnectionClient() - - XCTAssertEqual(1, clientDelegate.dataChannelMessages.count) - - let dataChannelMessageProto = clientDelegate.dataChannelMessages[0] - XCTAssertNotNil(dataChannelMessageProto.hangup) - - let hangupProto = dataChannelMessageProto.hangup! - XCTAssertEqual(123, hangupProto.id) - } -} - */ diff --git a/Session/test/mocks/MockEnvironment.h b/Session/test/mocks/MockEnvironment.h deleted file mode 100644 index 5406613f7..000000000 --- a/Session/test/mocks/MockEnvironment.h +++ /dev/null @@ -1,22 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "Environment.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface MockEnvironment : Environment - -+ (MockEnvironment *)activate; - -- (instancetype)init; - -@property (nonatomic) OWSContactsManager *contactsManager; -@property (nonatomic) OWSPreferences *preferences; -@property (nonatomic) OWSSounds *sounds; -@property (nonatomic) OWSWindowManager *windowManager; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/test/mocks/MockEnvironment.m b/Session/test/mocks/MockEnvironment.m deleted file mode 100644 index 9c71076d5..000000000 --- a/Session/test/mocks/MockEnvironment.m +++ /dev/null @@ -1,47 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "MockEnvironment.h" -#import "OWSBackup.h" -#import "OWSWindowManager.h" -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@implementation MockEnvironment - -+ (MockEnvironment *)activate -{ - MockEnvironment *instance = [MockEnvironment new]; - [self setShared:instance]; - return instance; -} - -- (instancetype)init -{ - OWSPrimaryStorage *primaryStorage = SSKEnvironment.shared.primaryStorage; - OWSAssertDebug(primaryStorage); - - // TODO: We should probably mock this out. - OWSAudioSession *audioSession = [OWSAudioSession new]; - OWSPreferences *preferences = [OWSPreferences new]; - OWSSounds *sounds = [[OWSSounds alloc] initWithPrimaryStorage:primaryStorage]; - id proximityMonitoringManager = [OWSProximityMonitoringManagerImpl new]; - OWSWindowManager *windowManager = [[OWSWindowManager alloc] initDefault]; - - self = [super initWithAudioSession:audioSession - preferences:preferences - proximityMonitoringManager:proximityMonitoringManager - sounds:sounds - windowManager:windowManager]; - - OWSAssertDebug(self); - return self; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/test/util/ByteParserTest.swift b/Session/test/util/ByteParserTest.swift deleted file mode 100644 index b505947e5..000000000 --- a/Session/test/util/ByteParserTest.swift +++ /dev/null @@ -1,221 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -import XCTest -@testable import Session - -class ByteParserTest: SignalBaseTest { - - override func setUp() { - super.setUp() - } - - override func tearDown() { - // Put teardown code here. This method is called after the invocation of each test method in the class. - super.tearDown() - } - - func testGetShort_Empty() { - let parser = ByteParser(data: Data(), littleEndian: true) - XCTAssertNotNil(parser) - XCTAssertFalse(parser.hasError) - - XCTAssertEqual(0, parser.nextShort()) - XCTAssertTrue(parser.hasError) - } - - func testGetShort_littleEndian() { - let data = Data(bytes: [0x01, 0x00, 0x00, 0x01, 0x01, 0x01 ]) - let parser = ByteParser(data: data, littleEndian: true) - XCTAssertNotNil(parser) - XCTAssertFalse(parser.hasError) - - XCTAssertEqual(1, parser.nextShort()) - XCTAssertFalse(parser.hasError) - - XCTAssertEqual(256, parser.nextShort()) - XCTAssertFalse(parser.hasError) - - XCTAssertEqual(257, parser.nextShort()) - XCTAssertFalse(parser.hasError) - - XCTAssertEqual(0, parser.nextShort()) - XCTAssertTrue(parser.hasError) - } - - func testGetShort_bigEndian() { - let data = Data(bytes: [0x01, 0x00, 0x00, 0x01, 0x01, 0x01 ]) - let parser = ByteParser(data: data, littleEndian: false) - XCTAssertNotNil(parser) - XCTAssertFalse(parser.hasError) - - XCTAssertEqual(256, parser.nextShort()) - XCTAssertFalse(parser.hasError) - - XCTAssertEqual(1, parser.nextShort()) - XCTAssertFalse(parser.hasError) - - XCTAssertEqual(257, parser.nextShort()) - XCTAssertFalse(parser.hasError) - - XCTAssertEqual(0, parser.nextShort()) - XCTAssertTrue(parser.hasError) - } - - func testGetInt_Empty() { - let parser = ByteParser(data: Data(), littleEndian: true) - XCTAssertNotNil(parser) - XCTAssertFalse(parser.hasError) - - XCTAssertEqual(0, parser.nextInt()) - XCTAssertTrue(parser.hasError) - } - - func testGetInt_littleEndian() { - let data = Data(bytes: [0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00 ]) - let parser = ByteParser(data: data, littleEndian: true) - XCTAssertNotNil(parser) - XCTAssertFalse(parser.hasError) - - XCTAssertEqual(1, parser.nextInt()) - XCTAssertFalse(parser.hasError) - - XCTAssertEqual(256, parser.nextInt()) - XCTAssertFalse(parser.hasError) - - XCTAssertEqual(257, parser.nextInt()) - XCTAssertFalse(parser.hasError) - - XCTAssertEqual(0, parser.nextInt()) - XCTAssertTrue(parser.hasError) - } - - func testGetInt_bigEndian() { - let data = Data(bytes: [0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01 ]) - let parser = ByteParser(data: data, littleEndian: false) - XCTAssertNotNil(parser) - XCTAssertFalse(parser.hasError) - - XCTAssertEqual(1, parser.nextInt()) - XCTAssertFalse(parser.hasError) - - XCTAssertEqual(256, parser.nextInt()) - XCTAssertFalse(parser.hasError) - - XCTAssertEqual(257, parser.nextInt()) - XCTAssertFalse(parser.hasError) - - XCTAssertEqual(0, parser.nextInt()) - XCTAssertTrue(parser.hasError) - } - - func testGetLong_Empty() { - let parser = ByteParser(data: Data(), littleEndian: true) - XCTAssertNotNil(parser) - XCTAssertFalse(parser.hasError) - - XCTAssertEqual(0, parser.nextLong()) - XCTAssertTrue(parser.hasError) - } - - func testGetLong_littleEndian() { - let data = Data(bytes: [0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]) - let parser = ByteParser(data: data, littleEndian: true) - XCTAssertNotNil(parser) - XCTAssertFalse(parser.hasError) - - XCTAssertEqual(1, parser.nextLong()) - XCTAssertFalse(parser.hasError) - - XCTAssertEqual(256, parser.nextLong()) - XCTAssertFalse(parser.hasError) - - XCTAssertEqual(257, parser.nextLong()) - XCTAssertFalse(parser.hasError) - - XCTAssertEqual(0, parser.nextLong()) - XCTAssertTrue(parser.hasError) - } - - func testGetLong_bigEndian() { - let data = Data(bytes: [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01 ]) - let parser = ByteParser(data: data, littleEndian: false) - XCTAssertNotNil(parser) - XCTAssertFalse(parser.hasError) - - XCTAssertEqual(1, parser.nextLong()) - XCTAssertFalse(parser.hasError) - - XCTAssertEqual(256, parser.nextLong()) - XCTAssertFalse(parser.hasError) - - XCTAssertEqual(257, parser.nextLong()) - XCTAssertFalse(parser.hasError) - - XCTAssertEqual(0, parser.nextLong()) - XCTAssertTrue(parser.hasError) - } - - func testReadZero_Empty() { - let parser = ByteParser(data: Data(), littleEndian: true) - XCTAssertNotNil(parser) - XCTAssertFalse(parser.hasError) - - XCTAssertFalse(parser.readZero(1)) - XCTAssertTrue(parser.hasError) - } - - func testReadZero() { - let data = Data(bytes: [0x00, 0x01, 0x00, 0x00, 0x01, 0x00]) - let parser = ByteParser(data: data, littleEndian: true) - XCTAssertNotNil(parser) - XCTAssertFalse(parser.hasError) - - XCTAssertTrue(parser.readZero(1)) - XCTAssertFalse(parser.hasError) - - XCTAssertFalse(parser.readZero(1)) - XCTAssertFalse(parser.hasError) - - XCTAssertTrue(parser.readZero(2)) - XCTAssertFalse(parser.hasError) - - XCTAssertFalse(parser.readZero(2)) - XCTAssertFalse(parser.hasError) - - XCTAssertFalse(parser.readZero(1)) - XCTAssertTrue(parser.hasError) - } - - func testReadBytes_Empty() { - let parser = ByteParser(data: Data(), littleEndian: true) - XCTAssertNotNil(parser) - XCTAssertFalse(parser.hasError) - - XCTAssertNil(parser.readBytes(1)) - XCTAssertTrue(parser.hasError) - } - - func testReadBytes() { - let data = Data(bytes: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05]) - let parser = ByteParser(data: data, littleEndian: true) - XCTAssertNotNil(parser) - XCTAssertFalse(parser.hasError) - - XCTAssertEqual(Data(bytes: [0x00 ]), parser.readBytes(1)) - XCTAssertFalse(parser.hasError) - - XCTAssertEqual(Data(bytes: [0x01 ]), parser.readBytes(1)) - XCTAssertFalse(parser.hasError) - - XCTAssertEqual(Data(bytes: [0x02, 0x03]), parser.readBytes(2)) - XCTAssertFalse(parser.hasError) - - XCTAssertEqual(Data(bytes: [0x04, 0x05]), parser.readBytes(2)) - XCTAssertFalse(parser.hasError) - - XCTAssertNil(parser.readBytes(1)) - XCTAssertTrue(parser.hasError) - } -} diff --git a/Session/test/util/CDSSigningCertificateTest.m b/Session/test/util/CDSSigningCertificateTest.m deleted file mode 100644 index 0e3ee7557..000000000 --- a/Session/test/util/CDSSigningCertificateTest.m +++ /dev/null @@ -1,197 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "SignalBaseTest.h" -#import -#import - -@interface CDSSigningCertificateTest : SignalBaseTest - -@end - -#pragma mark - - -@implementation CDSSigningCertificateTest - -- (void)testParsing_good -{ - NSString *pem = [self certificatesPem_good]; - NSError *error; - CDSSigningCertificate *_Nullable certificate = [CDSSigningCertificate parseCertificateFromPem:pem error:&error]; - XCTAssertNotNil(certificate); - XCTAssertNil(error); -} - -- (void)testParsing_bad -{ - NSString *pem = [self certificatesPem_bad]; - NSError *error; - CDSSigningCertificate *_Nullable certificate = [CDSSigningCertificate parseCertificateFromPem:pem error:&error]; - XCTAssertNil(certificate); - XCTAssertNotNil(error); - XCTAssertEqual(error.code, CDSSigningCertificateError_InvalidDistinguishedName); -} - -- (void)testVerification_good -{ - NSString *pem = [self certificatesPem_good]; - NSData *signature = [self signature_good]; - NSString *bodyString = [self bodyString_good]; - - NSError *error; - CDSSigningCertificate *_Nullable certificate = [CDSSigningCertificate parseCertificateFromPem:pem error:&error]; - XCTAssertNotNil(certificate); - XCTAssertNil(error); - - BOOL result = [certificate verifySignatureOfBody:bodyString signature:signature]; - XCTAssertTrue(result); -} - -- (void)testVerification_badData -{ - NSString *pem = [self certificatesPem_good]; - NSData *signature = [self signature_good]; - NSString *bodyString = [self bodyString_bad]; - - NSError *error; - CDSSigningCertificate *_Nullable certificate = [CDSSigningCertificate parseCertificateFromPem:pem error:&error]; - XCTAssertNotNil(certificate); - XCTAssertNil(error); - - XCTAssertFalse([certificate verifySignatureOfBody:bodyString signature:signature]); -} - -- (void)testVerification_badSignature -{ - NSString *pem = [self certificatesPem_good]; - NSData *signature = [self signature_bad]; - NSString *bodyString = [self bodyString_good]; - - NSError *error; - CDSSigningCertificate *_Nullable certificate = [CDSSigningCertificate parseCertificateFromPem:pem error:&error]; - XCTAssertNotNil(certificate); - XCTAssertNil(error); - - XCTAssertFalse([certificate verifySignatureOfBody:bodyString signature:signature]); -} - -#pragma mark - test values - -- (NSString *)certificatesPem_good { - return @"-----BEGIN CERTIFICATE----- \ - MIIEoTCCAwmgAwIBAgIJANEHdl0yo7CWMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNV \ - BAYTAlVTMQswCQYDVQQIDAJDQTEUMBIGA1UEBwwLU2FudGEgQ2xhcmExGjAYBgNV \ - BAoMEUludGVsIENvcnBvcmF0aW9uMTAwLgYDVQQDDCdJbnRlbCBTR1ggQXR0ZXN0 \ - YXRpb24gUmVwb3J0IFNpZ25pbmcgQ0EwHhcNMTYxMTIyMDkzNjU4WhcNMjYxMTIw \ - MDkzNjU4WjB7MQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ0ExFDASBgNVBAcMC1Nh \ - bnRhIENsYXJhMRowGAYDVQQKDBFJbnRlbCBDb3Jwb3JhdGlvbjEtMCsGA1UEAwwk \ - SW50ZWwgU0dYIEF0dGVzdGF0aW9uIFJlcG9ydCBTaWduaW5nMIIBIjANBgkqhkiG \ - 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqXot4OZuphR8nudFrAFiaGxxkgma/Es/BA+t \ - beCTUR106AL1ENcWA4FX3K+E9BBL0/7X5rj5nIgX/R/1ubhkKWw9gfqPG3KeAtId \ - cv/uTO1yXv50vqaPvE1CRChvzdS/ZEBqQ5oVvLTPZ3VEicQjlytKgN9cLnxbwtuv \ - LUK7eyRPfJW/ksddOzP8VBBniolYnRCD2jrMRZ8nBM2ZWYwnXnwYeOAHV+W9tOhA \ - ImwRwKF/95yAsVwd21ryHMJBcGH70qLagZ7Ttyt++qO/6+KAXJuKwZqjRlEtSEz8 \ - gZQeFfVYgcwSfo96oSMAzVr7V0L6HSDLRnpb6xxmbPdqNol4tQIDAQABo4GkMIGh \ - MB8GA1UdIwQYMBaAFHhDe3amfrzQr35CN+s1fDuHAVE8MA4GA1UdDwEB/wQEAwIG \ - wDAMBgNVHRMBAf8EAjAAMGAGA1UdHwRZMFcwVaBToFGGT2h0dHA6Ly90cnVzdGVk \ - c2VydmljZXMuaW50ZWwuY29tL2NvbnRlbnQvQ1JML1NHWC9BdHRlc3RhdGlvblJl \ - cG9ydFNpZ25pbmdDQS5jcmwwDQYJKoZIhvcNAQELBQADggGBAGcIthtcK9IVRz4r \ - Rq+ZKE+7k50/OxUsmW8aavOzKb0iCx07YQ9rzi5nU73tME2yGRLzhSViFs/LpFa9 \ - lpQL6JL1aQwmDR74TxYGBAIi5f4I5TJoCCEqRHz91kpG6Uvyn2tLmnIdJbPE4vYv \ - WLrtXXfFBSSPD4Afn7+3/XUggAlc7oCTizOfbbtOFlYA4g5KcYgS1J2ZAeMQqbUd \ - ZseZCcaZZZn65tdqee8UXZlDvx0+NdO0LR+5pFy+juM0wWbu59MvzcmTXbjsi7HY \ - 6zd53Yq5K244fwFHRQ8eOB0IWB+4PfM7FeAApZvlfqlKOlLcZL2uyVmzRkyR5yW7 \ - 2uo9mehX44CiPJ2fse9Y6eQtcfEhMPkmHXI01sN+KwPbpA39+xOsStjhP9N1Y1a2 \ - tQAVo+yVgLgV2Hws73Fc0o3wC78qPEA+v2aRs/Be3ZFDgDyghc/1fgU+7C+P6kbq \ - d4poyb6IW8KCJbxfMJvkordNOgOUUxndPHEi/tb/U7uLjLOgPA== \ - -----END CERTIFICATE----- \ - -----BEGIN CERTIFICATE----- \ - MIIFSzCCA7OgAwIBAgIJANEHdl0yo7CUMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNV \ - BAYTAlVTMQswCQYDVQQIDAJDQTEUMBIGA1UEBwwLU2FudGEgQ2xhcmExGjAYBgNV \ - BAoMEUludGVsIENvcnBvcmF0aW9uMTAwLgYDVQQDDCdJbnRlbCBTR1ggQXR0ZXN0 \ - YXRpb24gUmVwb3J0IFNpZ25pbmcgQ0EwIBcNMTYxMTE0MTUzNzMxWhgPMjA0OTEy \ - MzEyMzU5NTlaMH4xCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEUMBIGA1UEBwwL \ - U2FudGEgQ2xhcmExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0aW9uMTAwLgYDVQQD \ - DCdJbnRlbCBTR1ggQXR0ZXN0YXRpb24gUmVwb3J0IFNpZ25pbmcgQ0EwggGiMA0G \ - CSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQCfPGR+tXc8u1EtJzLA10Feu1Wg+p7e \ - LmSRmeaCHbkQ1TF3Nwl3RmpqXkeGzNLd69QUnWovYyVSndEMyYc3sHecGgfinEeh \ - rgBJSEdsSJ9FpaFdesjsxqzGRa20PYdnnfWcCTvFoulpbFR4VBuXnnVLVzkUvlXT \ - L/TAnd8nIZk0zZkFJ7P5LtePvykkar7LcSQO85wtcQe0R1Raf/sQ6wYKaKmFgCGe \ - NpEJUmg4ktal4qgIAxk+QHUxQE42sxViN5mqglB0QJdUot/o9a/V/mMeH8KvOAiQ \ - byinkNndn+Bgk5sSV5DFgF0DffVqmVMblt5p3jPtImzBIH0QQrXJq39AT8cRwP5H \ - afuVeLHcDsRp6hol4P+ZFIhu8mmbI1u0hH3W/0C2BuYXB5PC+5izFFh/nP0lc2Lf \ - 6rELO9LZdnOhpL1ExFOq9H/B8tPQ84T3Sgb4nAifDabNt/zu6MmCGo5U8lwEFtGM \ - RoOaX4AS+909x00lYnmtwsDVWv9vBiJCXRsCAwEAAaOByTCBxjBgBgNVHR8EWTBX \ - MFWgU6BRhk9odHRwOi8vdHJ1c3RlZHNlcnZpY2VzLmludGVsLmNvbS9jb250ZW50 \ - L0NSTC9TR1gvQXR0ZXN0YXRpb25SZXBvcnRTaWduaW5nQ0EuY3JsMB0GA1UdDgQW \ - BBR4Q3t2pn680K9+QjfrNXw7hwFRPDAfBgNVHSMEGDAWgBR4Q3t2pn680K9+Qjfr \ - NXw7hwFRPDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADANBgkq \ - hkiG9w0BAQsFAAOCAYEAeF8tYMXICvQqeXYQITkV2oLJsp6J4JAqJabHWxYJHGir \ - IEqucRiJSSx+HjIJEUVaj8E0QjEud6Y5lNmXlcjqRXaCPOqK0eGRz6hi+ripMtPZ \ - sFNaBwLQVV905SDjAzDzNIDnrcnXyB4gcDFCvwDFKKgLRjOB/WAqgscDUoGq5ZVi \ - zLUzTqiQPmULAQaB9c6Oti6snEFJiCQ67JLyW/E83/frzCmO5Ru6WjU4tmsmy8Ra \ - Ud4APK0wZTGtfPXU7w+IBdG5Ez0kE1qzxGQaL4gINJ1zMyleDnbuS8UicjJijvqA \ - 152Sq049ESDz+1rRGc2NVEqh1KaGXmtXvqxXcTB+Ljy5Bw2ke0v8iGngFBPqCTVB \ - 3op5KBG3RjbF6RRSzwzuWfL7QErNC8WEy5yDVARzTA5+xmBc388v9Dm21HGfcC8O \ - DD+gT9sSpssq0ascmvH49MOgjt1yoysLtdCtJW/9FZpoOypaHx0R+mJTLwPXVMrv \ - DaVzWh5aiEx+idkSGMnX \ - -----END CERTIFICATE-----"; -} - -- (NSString *)certificatesPem_bad -{ - NSString *pem_good = [self certificatesPem_good]; - NSUInteger middleIndex = 100; - NSString *pem_bad = [[[pem_good substringToIndex:middleIndex] - stringByAppendingString:@"0"] - stringByAppendingString:[pem_good substringFromIndex:middleIndex]]; - return pem_bad; -} - -- (NSData *)signature_good { - return [NSData dataFromBase64String:@"Hj4zz2gLX+g1T4avpcpXxmBqI5bpKKLOy4HLCTO0PwKcV+Q3fhDJVuVy0+SEgzC1TlmARKyH/DVynWu3pA9FA+4BvZxb7nLbaMG4PXdYu56sHDCzFVPsm9TPgqsVu5PbVXatZQ0oVxMkzKtPae3fy/ootXkG+4ahOU6Hwqa0Uy6+HYzL2CJZRJjHV6/iZjgTLjYsQqS0mZiaUuFoqn8RRb8/f7/9SujDSLa8dmKBqaZCtZpeHh4posLWjOhTJx07FhBRh5EV01gXFfys56h2NTc7MpmYbzt2onfH/3lDM8DfdNUJl0TfikzJyVdLWXi0MyAS2nrRhHFwVp365FYEJg=="]; -} - -- (NSData *)signature_bad { - NSData *signature_good = [self signature_good]; - uint8_t badByte = 0; - NSData *badByteData = [NSData dataWithBytes:&badByte length:1]; - NSData *signature_bad = [[signature_good subdataWithRange:NSMakeRange(0, signature_good.length - 1)] dataByAppendingData:badByteData]; - return signature_bad; -} - -- (NSData *)bodyData_good -{ - return [NSData dataFromBase64String:@"eyJpZCI6IjUyODQwOTg3NDQxNjA3OTk4Njg4MDQxMDE2MDQ3NDE2ODYwMDMiLCJ0aW1lc3RhbXAiOiIy \ - MDE4LTA3LTE5VDE5OjU4OjI3LjUwNDEwMSIsImlzdkVuY2xhdmVRdW90ZVN0YXR1cyI6IkdST1VQX09V \ - VF9PRl9EQVRFIiwicGxhdGZvcm1JbmZvQmxvYiI6IjE1MDIwMDY1MDQwMDAxMDAwMDA1MDUwMjA0MDEw \ - MTAwMDAwMDAwMDAwMDAwMDAwMDAwMDcwMDAwMDYwMDAwMDAwMjAwMDAwMDAwMDAwMDBBREZFQjYxNDI0 \ - RDY5QTc3N0U3RkFCRjNBMDMzQUJFMzYyMjcwQzZDMjAxQzUzQzk1REY1NzU4NUU0MjIyQkJEOEE3NDg3 \ - NjkyNTlBNTM3QzA0NEVGQjQwREY3NzMzQkQ5QTQzRjk1NDU5MkY2MkRCMEJFNzgyNEUwNjMzQkJFQkQ4 \ - MyIsImlzdkVuY2xhdmVRdW90ZUJvZHkiOiJBZ0FBQU44S0FBQUhBQVlBQUFBQUFHTnpvZktCVTdQMGtm \ - QUY4bnAwbW9BdmN6NjU3bjM2Vm9WV2FkeDdySkNuQkFUL0JQLy9BQUFBQUFBQUFBQUFBQUFBQUFBQUFB \ - QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUJ3QUFBQUFBQUFBSEFBQUFBQUFBQU0xcy9E \ - UXBON0k3RzkwN3Y1Y2hxbFlWckovMUNuWEZVbjFFSE5NbmFDYkpBQUFBQUFBQUFBQUFBQUFBQUFBQUFB \ - QUFBQUFBQUFBQUFBQUFBQUFBQUFCYmZ4VHRkbEFxU0FtS29ZbmFsV0IyODN3RDZQa2tPdWFYUXA1d296 \ - VURUUUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB \ - QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB \ - QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB \ - QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBRDVkZXM4c2ZmbmU2WVo4QkpIY1BSTGpQ \ - Y0VVczU4VmdDelpXVVBPVXF0YXdBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB \ - QUEifQ=="]; -} - -- (NSString *)bodyString_good -{ - NSData *bodyData = [self bodyData_good]; - NSString *bodyString = [[NSString alloc] initWithData:bodyData encoding:NSUTF8StringEncoding]; - return bodyString; -} - -- (NSString *)bodyString_bad -{ - return [[self bodyString_good] stringByAppendingString:@" "]; -} - -@end diff --git a/Session/test/util/DisplayableTextFilterTest.swift b/Session/test/util/DisplayableTextFilterTest.swift deleted file mode 100644 index 2a1fa1dcb..000000000 --- a/Session/test/util/DisplayableTextFilterTest.swift +++ /dev/null @@ -1,165 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -import XCTest -@testable import Session -@testable import SignalUtilitiesKit - -class DisplayableTextTest: SignalBaseTest { - - override func setUp() { - super.setUp() - // Put setup code here. This method is called before the invocation of each test method in the class. - } - - override func tearDown() { - // Put teardown code here. This method is called after the invocation of each test method in the class. - super.tearDown() - } - - func testDisplayableText() { - // show plain text - let boringText = "boring text" - XCTAssertEqual(boringText, boringText.filterStringForDisplay()) - - // show high byte emojis - let emojiText = "🇹🇹🌼🇹🇹🌼🇹🇹" - XCTAssertEqual(emojiText, emojiText.filterStringForDisplay()) - - // show normal diacritic usage - let diacriticalText = "Příliš žluťoučký kůň úpěl ďábelské ódy." - XCTAssertEqual(diacriticalText, diacriticalText.filterStringForDisplay()) - - // filter excessive diacritics - XCTAssertEqual("HAVING TROUBLE READING TEXT?", "H҉̸̧͘͠A͢͞V̛̛I̴̸N͏̕͏G҉̵͜͏͢ ̧̧́T̶̛͘͡R̸̵̨̢̀O̷̡U͡҉B̶̛͢͞L̸̸͘͢͟É̸ ̸̛͘͏R͟È͠͞A̸͝Ḑ̕͘͜I̵͘҉͜͞N̷̡̢͠G̴͘͠ ͟͞T͏̢́͡È̀X̕҉̢̀T̢͠?̕͏̢͘͢".filterStringForDisplay() ) - - XCTAssertEqual("LGO!", "L̷̳͔̲͝Ģ̵̮̯̤̩̙͍̬̟͉̹̘̹͍͈̮̦̰̣͟͝O̶̴̮̻̮̗͘͡!̴̷̟͓͓".filterStringForDisplay()) - } - - func testGlyphCount() { - // Plain text - XCTAssertEqual("boring text".glyphCount, 11) - - // Emojis - XCTAssertEqual("🇹🇹🌼🇹🇹🌼🇹🇹".glyphCount, 5) - XCTAssertEqual("🇹🇹".glyphCount, 1) - XCTAssertEqual("🇹🇹 ".glyphCount, 2) - XCTAssertEqual("👌🏽👌🏾👌🏿".glyphCount, 3) - XCTAssertEqual("😍".glyphCount, 1) - XCTAssertEqual("👩🏽".glyphCount, 1) - XCTAssertEqual("👾🙇💁🙅🙆🙋🙎🙍".glyphCount, 8) - XCTAssertEqual("🐵🙈🙉🙊".glyphCount, 4) - XCTAssertEqual("❤️💔💌💕💞💓💗💖💘💝💟💜💛💚💙".glyphCount, 15) - XCTAssertEqual("✋🏿💪🏿👐🏿🙌🏿👏🏿🙏🏿".glyphCount, 6) - XCTAssertEqual("🚾🆒🆓🆕🆖🆗🆙🏧".glyphCount, 8) - XCTAssertEqual("0️⃣1️⃣2️⃣3️⃣4️⃣5️⃣6️⃣7️⃣8️⃣9️⃣🔟".glyphCount, 11) - XCTAssertEqual("🇺🇸🇷🇺🇦🇫🇦🇲".glyphCount, 4) - XCTAssertEqual("🇺🇸🇷🇺🇸 🇦🇫🇦🇲🇸".glyphCount, 7) - XCTAssertEqual("🇺🇸🇷🇺🇸🇦🇫🇦🇲".glyphCount, 5) - XCTAssertEqual("🇺🇸🇷🇺🇸🇦".glyphCount, 3) - XCTAssertEqual("123".glyphCount, 3) - - // Normal diacritic usage - XCTAssertEqual("Příliš žluťoučký kůň úpěl ďábelské ódy.".glyphCount, 39) - - // Excessive diacritics - - // some insignificant discrepencies across iOS versions - if #available(iOS 11, *) { - XCTAssertEqual("H҉̸̧͘͠A͢͞V̛̛I̴̸N͏̕͏G҉̵͜͏͢ ̧̧́T̶̛͘͡R̸̵̨̢̀O̷̡U͡҉B̶̛͢͞L̸̸͘͢͟É̸ ̸̛͘͏R͟È͠͞A̸͝Ḑ̕͘͜I̵͘҉͜͞N̷̡̢͠G̴͘͠ ͟͞T͏̢́͡È̀X̕҉̢̀T̢͠?̕͏̢͘͢".glyphCount, 115) - } else { - XCTAssertEqual("H҉̸̧͘͠A͢͞V̛̛I̴̸N͏̕͏G҉̵͜͏͢ ̧̧́T̶̛͘͡R̸̵̨̢̀O̷̡U͡҉B̶̛͢͞L̸̸͘͢͟É̸ ̸̛͘͏R͟È͠͞A̸͝Ḑ̕͘͜I̵͘҉͜͞N̷̡̢͠G̴͘͠ ͟͞T͏̢́͡È̀X̕҉̢̀T̢͠?̕͏̢͘͢".glyphCount, 109) - } - - XCTAssertEqual("L̷̳͔̲͝Ģ̵̮̯̤̩̙͍̬̟͉̹̘̹͍͈̮̦̰̣͟͝O̶̴̮̻̮̗͘͡!̴̷̟͓͓".glyphCount, 43) - } - - func testContainsOnlyEmoji() { - // Plain text - XCTAssertFalse("boring text".containsOnlyEmoji) - - // Emojis - XCTAssertTrue("🇹🇹🌼🇹🇹🌼🇹🇹".containsOnlyEmoji) - XCTAssertTrue("🇹🇹".containsOnlyEmoji) - XCTAssertFalse("🇹🇹 ".containsOnlyEmoji) - XCTAssertTrue("👌🏽👌🏾👌🏿".containsOnlyEmoji) - XCTAssertTrue("😍".containsOnlyEmoji) - XCTAssertTrue("👩🏽".containsOnlyEmoji) - XCTAssertTrue("👾🙇💁🙅🙆🙋🙎🙍".containsOnlyEmoji) - XCTAssertTrue("🐵🙈🙉🙊".containsOnlyEmoji) - XCTAssertTrue("❤️💔💌💕💞💓💗💖💘💝💟💜💛💚💙".containsOnlyEmoji) - XCTAssertTrue("✋🏿💪🏿👐🏿🙌🏿👏🏿🙏🏿".containsOnlyEmoji) - XCTAssertTrue("🚾🆒🆓🆕🆖🆗🆙🏧".containsOnlyEmoji) - XCTAssertFalse("0️⃣1️⃣2️⃣3️⃣4️⃣5️⃣6️⃣7️⃣8️⃣9️⃣🔟".containsOnlyEmoji) - XCTAssertTrue("🇺🇸🇷🇺🇦🇫🇦🇲".containsOnlyEmoji) - XCTAssertFalse("🇺🇸🇷🇺🇸 🇦🇫🇦🇲🇸".containsOnlyEmoji) - XCTAssertTrue("🇺🇸🇷🇺🇸🇦🇫🇦🇲".containsOnlyEmoji) - XCTAssertTrue("🇺🇸🇷🇺🇸🇦".containsOnlyEmoji) - // Unicode standard doesn't consider these to be Emoji. - XCTAssertFalse("123".containsOnlyEmoji) - - // Normal diacritic usage - XCTAssertFalse("Příliš žluťoučký kůň úpěl ďábelské ódy.".containsOnlyEmoji) - - // Excessive diacritics - XCTAssertFalse("H҉̸̧͘͠A͢͞V̛̛I̴̸N͏̕͏G҉̵͜͏͢ ̧̧́T̶̛͘͡R̸̵̨̢̀O̷̡U͡҉B̶̛͢͞L̸̸͘͢͟É̸ ̸̛͘͏R͟È͠͞A̸͝Ḑ̕͘͜I̵͘҉͜͞N̷̡̢͠G̴͘͠ ͟͞T͏̢́͡È̀X̕҉̢̀T̢͠?̕͏̢͘͢".containsOnlyEmoji) - XCTAssertFalse("L̷̳͔̲͝Ģ̵̮̯̤̩̙͍̬̟͉̹̘̹͍͈̮̦̰̣͟͝O̶̴̮̻̮̗͘͡!̴̷̟͓͓".containsOnlyEmoji) - } - - func test_shouldAllowLinkification() { - func assertLinkifies(_ text: String, file: StaticString = #file, line: UInt = #line) { - let displayableText = DisplayableText.displayableText(text) - XCTAssert(displayableText.shouldAllowLinkification, "was not linkifiable text: \(text)", file: file, line: line) - } - - func assertNotLinkifies(_ text: String, file: StaticString = #file, line: UInt = #line) { - let displayableText = DisplayableText.displayableText(text) - XCTAssertFalse(displayableText.shouldAllowLinkification, "was linkifiable text: \(text)", file: file, line: line) - } - - // some basic happy paths - assertLinkifies("foo google.com") - assertLinkifies("google.com/foo") - assertLinkifies("blah google.com/foo") - assertLinkifies("foo http://google.com") - assertLinkifies("foo https://google.com") - - // cyrillic host with ascii tld - assertNotLinkifies("foo http://asĸ.com") - assertNotLinkifies("http://asĸ.com") - assertNotLinkifies("asĸ.com") - - // Mixed latin and cyrillic text, but it's not a link - // (nothing to linkify, but there's nothing illegal here) - assertLinkifies("asĸ") - - // Cyrillic host with cyrillic TLD - assertLinkifies("http://кц.рф") - assertLinkifies("https://кц.рф") - assertLinkifies("кц.рф") - assertLinkifies("https://кц.рф/foo") - assertLinkifies("https://кц.рф/кц") - assertLinkifies("https://кц.рф/кцfoo") - - // ascii text outside of the link, with cyrillic host + cyrillic domain - assertLinkifies("some text: кц.рф") - - // Mixed ascii/cyrillic text outside of the link, with cyrillic host + cyrillic domain - assertLinkifies("asĸ кц.рф") - - assertLinkifies("google.com") - assertLinkifies("foo.google.com") - assertLinkifies("https://foo.google.com") - assertLinkifies("https://foo.google.com/some/path.html") - - assertNotLinkifies("asĸ.com") - assertNotLinkifies("https://кц.cфm") - assertNotLinkifies("https://google.cфm") - - assertLinkifies("кц.рф") - assertLinkifies("кц.рф/some/path") - assertLinkifies("https://кц.рф/some/path") - assertNotLinkifies("http://foo.кц.рф") - } -} diff --git a/Session/test/util/ExceptionsTest.h b/Session/test/util/ExceptionsTest.h deleted file mode 100644 index 1ee996e49..000000000 --- a/Session/test/util/ExceptionsTest.h +++ /dev/null @@ -1,9 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "SignalBaseTest.h" - -@interface ExceptionsTest : SignalBaseTest - -@end diff --git a/Session/test/util/FunctionalUtilTest.m b/Session/test/util/FunctionalUtilTest.m deleted file mode 100644 index df286cbc5..000000000 --- a/Session/test/util/FunctionalUtilTest.m +++ /dev/null @@ -1,49 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "FunctionalUtil.h" -#import "SignalBaseTest.h" -#import "TestUtil.h" - -@interface FunctionalUtilTest : SignalBaseTest - -@end - -#pragma mark - - -@implementation FunctionalUtilTest - --(void) testAny { - test(![@[] any:^(id x) { return false; }]); - test(![@[] any:^(id x) { return true; }]); - test(![@[@1] any:^(id x) { return false; }]); - test([@[@1] any:^(id x) { return true; }]); - - test([(@[@2, @3, @5]) any:^(NSNumber* x) { return x.intValue == 3; }]); - test(![(@[@2, @4, @5]) any:^(NSNumber* x) { return x.intValue == 3; }]); -} - --(void) testMap { - test([[@[] map:^(id x) { return x; }] isEqualToArray:@[]]); - test([[(@[@1,@2]) map:^(id x) { return x; }] isEqualToArray:(@[@1,@2])]); - test([[(@[@1,@2]) map:^(NSNumber* x) { return @(x.intValue + 1); }] isEqualToArray:(@[@2,@3])]); -} - --(void) testFilter { - test([[@[] filter:^(id x) { return true; }] isEqualToArray:@[]]); - test([[(@[@1,@2]) filter:^(NSNumber* x) { return true; }] isEqualToArray:(@[@1,@2])]); - test([[(@[@1,@2]) filter:^(NSNumber* x) { return false; }] isEqualToArray:(@[])]); - test([[(@[@1,@2]) filter:^(NSNumber* x) { return x.intValue == 1; }] isEqualToArray:(@[@1])]); - test([[(@[@1,@2]) filter:^(NSNumber* x) { return x.intValue == 2; }] isEqualToArray:(@[@2])]); -} - --(void) testGroupBy { - test([[@[] groupBy:^id(id value) { return @true; }] isEqual:@{}]); - test([[@[@1] groupBy:^id(id value) { return @true; }] isEqual:@{@true : @[@1]}]); - test([[(@[@1, @2]) groupBy:^id(id value) { return @true; }] isEqual:@{@true : (@[@1, @2])}]); - test([[(@[@1, @2]) groupBy:^id(id value) { return value; }] isEqual:(@{@1 : @[@1], @2 : @[@2]})]); - test([[(@[@1, @1, @2, @3, @5]) groupBy:^id(NSNumber* value) { return @(value.intValue/2); }] isEqual:(@{@0 : @[@1, @1], @1 : @[@2, @3], @2 : @[@5]})]); -} - -@end diff --git a/Session/test/util/ImageCacheTest.swift b/Session/test/util/ImageCacheTest.swift deleted file mode 100644 index 8257b05db..000000000 --- a/Session/test/util/ImageCacheTest.swift +++ /dev/null @@ -1,61 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -import XCTest -@testable import Session - -class ImageCacheTest: SignalBaseTest { - - var imageCache: ImageCache! - - let firstVariation = UIImage() - let secondVariation = UIImage() - let otherImage = UIImage() - - let cacheKey1 = "cache-key-1" as NSString - let cacheKey2 = "cache-key-2" as NSString - - override func setUp() { - super.setUp() - self.imageCache = ImageCache() - imageCache.setImage(firstVariation, forKey: cacheKey1, diameter: 100) - imageCache.setImage(secondVariation, forKey: cacheKey1, diameter: 200) - imageCache.setImage(otherImage, forKey: cacheKey2, diameter: 100) - } - - override func tearDown() { - // Put teardown code here. This method is called after the invocation of each test method in the class. - super.tearDown() - } - - func testSetGet() { - XCTAssertEqual(firstVariation, imageCache.image(forKey: cacheKey1, diameter: 100)) - XCTAssertEqual(secondVariation, imageCache.image(forKey: cacheKey1, diameter: 200)) - XCTAssertNotEqual(secondVariation, imageCache.image(forKey: cacheKey1, diameter: 100)) - XCTAssertEqual(otherImage, imageCache.image(forKey: cacheKey2, diameter: 100)) - XCTAssertNil(imageCache.image(forKey: cacheKey2, diameter: 200)) - } - - func testRemoveAllForKey() { - // sanity check - XCTAssertEqual(firstVariation, imageCache.image(forKey: cacheKey1, diameter: 100)) - XCTAssertEqual(otherImage, imageCache.image(forKey: cacheKey2, diameter: 100)) - - imageCache.removeAllImages(forKey: cacheKey1) - - XCTAssertNil(imageCache.image(forKey: cacheKey1, diameter: 100)) - XCTAssertNil(imageCache.image(forKey: cacheKey1, diameter: 200)) - XCTAssertEqual(otherImage, imageCache.image(forKey: cacheKey2, diameter: 100)) - } - - func testRemoveAll() { - XCTAssertEqual(firstVariation, imageCache.image(forKey: cacheKey1, diameter: 100)) - - imageCache.removeAllImages() - - XCTAssertNil(imageCache.image(forKey: cacheKey1, diameter: 100)) - XCTAssertNil(imageCache.image(forKey: cacheKey1, diameter: 200)) - XCTAssertNil(imageCache.image(forKey: cacheKey2, diameter: 100)) - } -} diff --git a/Session/test/util/OWSDatabaseConverterTest.m b/Session/test/util/OWSDatabaseConverterTest.m deleted file mode 100644 index 7d7dd15ca..000000000 --- a/Session/test/util/OWSDatabaseConverterTest.m +++ /dev/null @@ -1,1165 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "SignalBaseTest.h" -#import -#import -#import -#import -#import -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface YapDatabase (OWSDatabaseConverterTest) - -- (void)flushInternalQueue; -- (void)flushCheckpointQueue; - -@end - -@interface OWSStorage (OWSDatabaseConverterTest) - -+ (YapDatabaseDeserializer)logOnFailureDeserializer; -+ (void)storeKeyChainValue:(NSData *)data keychainKey:(NSString *)keychainKey; -+ (nullable NSData *)tryToLoadKeyChainValue:(NSString *)keychainKey errorHandle:(NSError **)errorHandle; - -@end - -#pragma mark - - -@interface YapDatabaseCryptoUtils (OWSDatabaseConverterTest) - -+ (NSData *)readFirstNBytesOfDatabaseFile:(NSString *)filePath byteCount:(NSUInteger)byteCount; - -@end - -#pragma mark - - -@interface OWSDatabaseConverterTest : SignalBaseTest - -@end - -#pragma mark - - -@implementation OWSDatabaseConverterTest - -- (NSData *)randomDatabasePassword -{ - return [Randomness generateRandomBytes:30]; -} - -- (NSData *)randomDatabaseSalt -{ - return [Randomness generateRandomBytes:(int)kSQLCipherSaltLength]; -} - -- (NSData *)randomDatabaseKeySpec -{ - return [Randomness generateRandomBytes:(int)kSQLCipherKeySpecLength]; -} - -// * Open a YapDatabase. -// * Do some work with a block. -// * Close the database. -// * Verify that the database is closed. -- (void)openYapDatabase:(NSString *)databaseFilePath - databasePassword:(NSData *_Nullable)databasePassword - databaseSalt:(NSData *_Nullable)databaseSalt - databaseKeySpec:(NSData *_Nullable)databaseKeySpec - databaseBlock:(void (^_Nonnull)(YapDatabase *))databaseBlock -{ - OWSAssertDebug(databaseFilePath.length > 0); - OWSAssertDebug(databasePassword.length > 0 || databaseKeySpec.length > 0); - OWSAssertDebug(databaseBlock); - - OWSLogVerbose(@"openYapDatabase: %@", databaseFilePath); - [DDLog flushLog]; - - __weak YapDatabase *_Nullable weakDatabase = nil; - dispatch_queue_t snapshotQueue; - dispatch_queue_t writeQueue; - - @autoreleasepool { - YapDatabaseOptions *options = [[YapDatabaseOptions alloc] init]; - options.corruptAction = YapDatabaseCorruptAction_Fail; - if (databasePassword) { - OWSLogInfo(@"Using password."); - options.cipherKeyBlock = ^{ - return databasePassword; - }; - } - options.enableMultiProcessSupport = YES; - - if (databaseSalt) { - OWSLogInfo(@"Using salt & unencrypted header."); - options.cipherSaltBlock = ^{ - return databaseSalt; - }; - options.cipherUnencryptedHeaderLength = kSqliteHeaderLength; - } else if (databaseKeySpec) { - OWSLogInfo(@"Using key spec & unencrypted header."); - options.cipherKeySpecBlock = ^{ - return databaseKeySpec; - }; - options.cipherUnencryptedHeaderLength = kSqliteHeaderLength; - } - options.legacyCipherCompatibilityVersion = 3; - - OWSAssertDebug(options.cipherDefaultkdfIterNumber == 0); - OWSAssertDebug(options.kdfIterNumber == 0); - OWSAssertDebug(options.cipherPageSize == 0); - OWSAssertDebug(options.pragmaPageSize == 0); - OWSAssertDebug(options.pragmaJournalSizeLimit == 0); - - YapDatabase *database = [[YapDatabase alloc] initWithPath:databaseFilePath - serializer:nil - deserializer:[OWSStorage logOnFailureDeserializer] - options:options]; - OWSAssertDebug(database); - - weakDatabase = database; - snapshotQueue = database->snapshotQueue; - writeQueue = database->writeQueue; - - databaseBlock(database); - - [database flushInternalQueue]; - [database flushCheckpointQueue]; - - // Close the database. - database = nil; - } - - // Flush the database's queues, which may contain lingering - // references to the database. - dispatch_sync(snapshotQueue, - ^{ - }); - dispatch_sync(writeQueue, - ^{ - }); - - // Wait for notifications from writes to be fired. - { - XCTestExpectation *expectation = [self expectationWithDescription:@"Database modified notifications"]; - - dispatch_async(dispatch_get_main_queue(), ^{ - // Database modified notifications are fired on the main queue. - // Once this block executes, the main queue has been flushed - // and we know that all database modified notifications are - // complete. - [expectation fulfill]; - }); - - // YapDatabase can retain cached references to the registration - // connections for up to 5 seconds. This can block deallocation - // of the YapDatabase instance. Since we're trying to block on - // closing of the database (so that we can examine its contents - // on disk), we wait for the worst case duration. - [self waitForExpectationsWithTimeout:5.0 - handler:^(NSError *error) { - if (error) { - OWSLogInfo(@"Timeout Error: %@", error); - } - }]; - } - - // Verify that the database is indeed closed. - YapDatabase *_Nullable strongDatabase = weakDatabase; - OWSAssertDebug(!strongDatabase); -} - -- (void)createTestDatabase:(NSString *)databaseFilePath - databasePassword:(NSData *_Nullable)databasePassword - databaseSalt:(NSData *_Nullable)databaseSalt - databaseKeySpec:(NSData *_Nullable)databaseKeySpec -{ - OWSAssertDebug(databaseFilePath.length > 0); - OWSAssertDebug(databasePassword.length > 0 || databaseKeySpec.length > 0); - - OWSAssertDebug(![[NSFileManager defaultManager] fileExistsAtPath:databaseFilePath]); - - [self openYapDatabase:databaseFilePath - databasePassword:databasePassword - databaseSalt:databaseSalt - databaseKeySpec:databaseKeySpec - databaseBlock:^(YapDatabase *database) { - [self logHeaderOfDatabaseFile:databaseFilePath - label:@"mid-creation"]; - - YapDatabaseConnection *dbConnection = database.newConnection; - [dbConnection setObject:@(YES) forKey:@"test_key_name" inCollection:@"test_collection_name"]; - [dbConnection flushTransactionsWithCompletionQueue:dispatch_get_main_queue() completionBlock:nil]; - }]; - - OWSAssertDebug([[NSFileManager defaultManager] fileExistsAtPath:databaseFilePath]); - - NSError *_Nullable error = nil; - NSDictionary *fileAttributes = - [[NSFileManager defaultManager] attributesOfItemAtPath:databaseFilePath error:&error]; - OWSAssertDebug(fileAttributes && !error); - OWSLogVerbose(@"test database file size: %@", fileAttributes[NSFileSize]); -} - -- (BOOL)verifyTestDatabase:(NSString *)databaseFilePath - databasePassword:(NSData *_Nullable)databasePassword - databaseSalt:(NSData *_Nullable)databaseSalt - databaseKeySpec:(NSData *_Nullable)databaseKeySpec -{ - OWSAssertDebug(databaseFilePath.length > 0); - OWSAssertDebug(databasePassword.length > 0 || databaseKeySpec.length > 0); - - OWSAssertDebug([[NSFileManager defaultManager] fileExistsAtPath:databaseFilePath]); - - __block BOOL isValid = NO; - [self openYapDatabase:databaseFilePath - databasePassword:databasePassword - databaseSalt:databaseSalt - databaseKeySpec:databaseKeySpec - databaseBlock:^(YapDatabase *database) { - YapDatabaseConnection *dbConnection = database.newConnection; - id _Nullable value = [dbConnection objectForKey:@"test_key_name" inCollection:@"test_collection_name"]; - isValid = [@(YES) isEqual:value]; - }]; - - OWSAssertDebug([[NSFileManager defaultManager] fileExistsAtPath:databaseFilePath]); - - return isValid; -} - -- (nullable NSString *)createUnconvertedDatabase:(NSData *)databasePassword -{ - return [self createDatabase:databasePassword databaseSalt:nil databaseKeySpec:nil]; -} - -- (NSString *)createTempDatabaseFilePath -{ - NSString *databaseFilePath = [OWSFileSystem temporaryFilePathWithFileExtension:@"sqlite"]; - - OWSLogInfo(@"databaseFilePath: %@", databaseFilePath); - [DDLog flushLog]; - - return databaseFilePath; -} - -// If databaseSalt and databaseKeySpec are both nil, creates a non-converted database. -// Otherwise creates a pre-converted database. -- (nullable NSString *)createDatabase:(NSData *_Nullable)databasePassword - databaseSalt:(NSData *_Nullable)databaseSalt - databaseKeySpec:(NSData *_Nullable)databaseKeySpec -{ - OWSAssertDebug(databasePassword.length > 0 || databaseKeySpec.length > 0); - - NSString *databaseFilePath = [self createTempDatabaseFilePath]; - - [self createTestDatabase:databaseFilePath - databasePassword:databasePassword - databaseSalt:databaseSalt - databaseKeySpec:databaseKeySpec]; - - [self logHeaderOfDatabaseFile:databaseFilePath - label:@"created"]; - - BOOL isValid = [self verifyTestDatabase:databaseFilePath - databasePassword:databasePassword - databaseSalt:databaseSalt - databaseKeySpec:databaseKeySpec]; - OWSAssertDebug(isValid); - - return databaseFilePath; -} - -#pragma mark - Tests - -- (void)testDoesDatabaseNeedToBeConverted_Unconverted -{ - NSData *databasePassword = [self randomDatabasePassword]; - NSString *_Nullable databaseFilePath = [self createUnconvertedDatabase:databasePassword]; - XCTAssertTrue([YapDatabaseCryptoUtils doesDatabaseNeedToBeConverted:databaseFilePath]); -} - -- (void)testDoesDatabaseNeedToBeConverted_ConvertedWithoutKeyspec -{ - NSData *databasePassword = [self randomDatabasePassword]; - NSData *databaseSalt = [self randomDatabaseSalt]; - NSData *_Nullable databaseKeySpec = nil; - NSString *_Nullable databaseFilePath = - [self createDatabase:databasePassword databaseSalt:databaseSalt databaseKeySpec:databaseKeySpec]; - XCTAssertFalse([YapDatabaseCryptoUtils doesDatabaseNeedToBeConverted:databaseFilePath]); -} - -- (void)testDoesDatabaseNeedToBeConverted_ConvertedWithKeyspec -{ - NSData *_Nullable databasePassword = nil; - NSData *_Nullable databaseSalt = nil; - NSData *databaseKeySpec = [self randomDatabaseKeySpec]; - NSString *_Nullable databaseFilePath = - [self createDatabase:databasePassword databaseSalt:databaseSalt databaseKeySpec:databaseKeySpec]; - XCTAssertFalse([YapDatabaseCryptoUtils doesDatabaseNeedToBeConverted:databaseFilePath]); -} - -// Verifies that legacy users with non-converted databases can convert. -- (void)testDatabaseConversion_WithoutKeyspec -{ - NSData *databasePassword = [self randomDatabasePassword]; - NSString *_Nullable databaseFilePath = [self createUnconvertedDatabase:databasePassword]; - XCTAssertTrue([YapDatabaseCryptoUtils doesDatabaseNeedToBeConverted:databaseFilePath]); - - __block NSData *_Nullable databaseSalt = nil; - __block NSData *_Nullable databaseKeySpec = nil; - YapRecordDatabaseSaltBlock recordSaltBlock = ^(NSData *saltData) { - OWSAssertDebug(!databaseSalt); - OWSAssertDebug(saltData); - - databaseSalt = saltData; - databaseKeySpec = [YapDatabaseCryptoUtils deriveDatabaseKeySpecForPassword:databasePassword saltData:saltData]; - XCTAssert(databaseKeySpec.length == kSQLCipherKeySpecLength); - - return YES; - }; - - NSError *_Nullable error = [YapDatabaseCryptoUtils convertDatabaseIfNecessary:databaseFilePath - databasePassword:databasePassword - options:OWSStorage.defaultDatabaseOptions - recordSaltBlock:recordSaltBlock]; - if (error) { - OWSLogError(@"error: %@", error); - } - XCTAssertNil(error); - XCTAssertFalse([YapDatabaseCryptoUtils doesDatabaseNeedToBeConverted:databaseFilePath]); - XCTAssertNotNil(databaseSalt); - XCTAssertEqual(databaseSalt.length, kSQLCipherSaltLength); - XCTAssertNotNil(databaseKeySpec); - XCTAssertEqual(databaseKeySpec.length, kSQLCipherKeySpecLength); - - BOOL isValid = [self verifyTestDatabase:databaseFilePath - databasePassword:databasePassword - databaseSalt:databaseSalt - databaseKeySpec:nil]; - XCTAssertTrue(isValid); -} - -// Verifies that legacy users with non-converted databases can convert. -- (void)testDatabaseConversion_WithKeyspec -{ - NSData *databasePassword = [self randomDatabasePassword]; - NSString *_Nullable databaseFilePath = [self createUnconvertedDatabase:databasePassword]; - XCTAssertTrue([YapDatabaseCryptoUtils doesDatabaseNeedToBeConverted:databaseFilePath]); - - __block NSData *_Nullable databaseSalt = nil; - - __block NSData *_Nullable databaseKeySpec = nil; - YapRecordDatabaseSaltBlock recordSaltBlock = ^(NSData *saltData) { - OWSAssertDebug(!databaseSalt); - OWSAssertDebug(saltData); - - databaseSalt = saltData; - databaseKeySpec = [YapDatabaseCryptoUtils deriveDatabaseKeySpecForPassword:databasePassword saltData:saltData]; - XCTAssert(databaseKeySpec.length == kSQLCipherKeySpecLength); - - return YES; - }; - - NSError *_Nullable error = [YapDatabaseCryptoUtils convertDatabaseIfNecessary:databaseFilePath - databasePassword:databasePassword - options:OWSStorage.defaultDatabaseOptions - recordSaltBlock:recordSaltBlock]; - if (error) { - OWSLogError(@"error: %@", error); - } - XCTAssertNil(error); - XCTAssertFalse([YapDatabaseCryptoUtils doesDatabaseNeedToBeConverted:databaseFilePath]); - XCTAssertNotNil(databaseSalt); - XCTAssertEqual(databaseSalt.length, kSQLCipherSaltLength); - XCTAssertNotNil(databaseKeySpec); - XCTAssertEqual(databaseKeySpec.length, kSQLCipherKeySpecLength); - - BOOL isValid = [self verifyTestDatabase:databaseFilePath - databasePassword:nil - databaseSalt:nil - databaseKeySpec:databaseKeySpec]; - XCTAssertTrue(isValid); -} - -// If we fail to record the salt for some reason, we'll be unable to re-open the database -// halt the conversion in hopes that either the failure is intermittent or we can push out -// a patch to fix the problem without having lost the user's DB. -- (void)testDatabaseConversionDoesNotProceedWhenRecordingSaltFails -{ - NSData *databasePassword = [self randomDatabasePassword]; - NSString *_Nullable databaseFilePath = [self createUnconvertedDatabase:databasePassword]; - XCTAssertTrue([YapDatabaseCryptoUtils doesDatabaseNeedToBeConverted:databaseFilePath]); - - __block NSData *_Nullable databaseSalt = nil; - - __block NSData *_Nullable databaseKeySpec = nil; - YapRecordDatabaseSaltBlock recordSaltBlock = ^(NSData *saltData) { - OWSAssertDebug(!databaseSalt); - OWSAssertDebug(saltData); - - // Simulate a failure to record the new salt, e.g. if KDF returns nil - return NO; - }; - - NSError *_Nullable error = [YapDatabaseCryptoUtils convertDatabaseIfNecessary:databaseFilePath - databasePassword:databasePassword - options:OWSStorage.defaultDatabaseOptions - recordSaltBlock:recordSaltBlock]; - - XCTAssertNotNil(error); - XCTAssertTrue([YapDatabaseCryptoUtils doesDatabaseNeedToBeConverted:databaseFilePath]); - - BOOL isValid = [self verifyTestDatabase:databaseFilePath - databasePassword:databasePassword - databaseSalt:nil - databaseKeySpec:databaseKeySpec]; - XCTAssertTrue(isValid); -} - -// Verifies that legacy users with non-converted databases can convert. -- (void)testDatabaseConversionPerformance_WithKeyspec -{ - NSData *databasePassword = [self randomDatabasePassword]; - NSString *databaseFilePath = [self createTempDatabaseFilePath]; - - const int kItemCount = 50 * 1000; - - // Create and populate an unconverted database. - [self openYapDatabase:databaseFilePath - databasePassword:databasePassword - databaseSalt:nil - databaseKeySpec:nil - databaseBlock:^(YapDatabase *database) { - YapDatabaseConnection *dbConnection = database.newConnection; - [dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { - for (int i = 0; i < kItemCount; i++) { - NSString *key = [NSString stringWithFormat:@"key-%d", i]; - [transaction setObject:@"test-object" forKey:key inCollection:@"test_collection_name"]; - } - }]; - }]; - - XCTAssertTrue([YapDatabaseCryptoUtils doesDatabaseNeedToBeConverted:databaseFilePath]); - - __block NSData *_Nullable databaseSalt = nil; - __block NSData *_Nullable databaseKeySpec = nil; - YapRecordDatabaseSaltBlock recordSaltBlock = ^(NSData *saltData) { - OWSAssertDebug(!databaseSalt); - OWSAssertDebug(saltData); - - databaseSalt = saltData; - databaseKeySpec = [YapDatabaseCryptoUtils deriveDatabaseKeySpecForPassword:databasePassword saltData:saltData]; - XCTAssert(databaseKeySpec.length == kSQLCipherKeySpecLength); - - return YES; - }; - - NSError *_Nullable error = [YapDatabaseCryptoUtils convertDatabaseIfNecessary:databaseFilePath - databasePassword:databasePassword - options:OWSStorage.defaultDatabaseOptions - recordSaltBlock:recordSaltBlock]; - if (error) { - OWSLogError(@"error: %@", error); - } - XCTAssertNil(error); - XCTAssertFalse([YapDatabaseCryptoUtils doesDatabaseNeedToBeConverted:databaseFilePath]); - XCTAssertNotNil(databaseSalt); - XCTAssertEqual(databaseSalt.length, kSQLCipherSaltLength); - XCTAssertNotNil(databaseKeySpec); - XCTAssertEqual(databaseKeySpec.length, kSQLCipherKeySpecLength); - - // Verify the contents of the unconverted database. - __block BOOL isValid = NO; - [self openYapDatabase:databaseFilePath - databasePassword:nil - databaseSalt:nil - databaseKeySpec:databaseKeySpec - databaseBlock:^(YapDatabase *database) { - YapDatabaseConnection *dbConnection = database.newConnection; - isValid = [dbConnection numberOfKeysInCollection:@"test_collection_name"] == kItemCount; - }]; - XCTAssertTrue(isValid); -} - -// Verifies new users who create new pre-converted databases. -- (void)testDatabaseCreation_WithoutKeySpec -{ - NSData *databasePassword = [self randomDatabasePassword]; - NSData *databaseSalt = [self randomDatabaseSalt]; - NSData *_Nullable databaseKeySpec = nil; - NSString *_Nullable databaseFilePath = - [self createDatabase:databasePassword databaseSalt:databaseSalt databaseKeySpec:databaseKeySpec]; - XCTAssertFalse([YapDatabaseCryptoUtils doesDatabaseNeedToBeConverted:databaseFilePath]); - - YapRecordDatabaseSaltBlock recordSaltBlock = ^(NSData *saltData) { - OWSAssertDebug(saltData); - - XCTFail(@"No conversion should be necessary"); - return NO; - }; - - NSError *_Nullable error = [YapDatabaseCryptoUtils convertDatabaseIfNecessary:databaseFilePath - databasePassword:databasePassword - options:OWSStorage.defaultDatabaseOptions - recordSaltBlock:recordSaltBlock]; - if (error) { - OWSLogError(@"error: %@", error); - } - XCTAssertNil(error); - XCTAssertFalse([YapDatabaseCryptoUtils doesDatabaseNeedToBeConverted:databaseFilePath]); - - BOOL isValid = [self verifyTestDatabase:databaseFilePath - databasePassword:databasePassword - databaseSalt:databaseSalt - databaseKeySpec:databaseKeySpec]; - XCTAssertTrue(isValid); -} - -// Verifies new users who create new pre-converted databases. -- (void)testDatabaseCreation_WithKeySpec -{ - NSData *_Nullable databasePassword = nil; - NSData *_Nullable databaseSalt = nil; - NSData *databaseKeySpec = [self randomDatabaseKeySpec]; - NSString *_Nullable databaseFilePath = - [self createDatabase:databasePassword databaseSalt:databaseSalt databaseKeySpec:databaseKeySpec]; - XCTAssertFalse([YapDatabaseCryptoUtils doesDatabaseNeedToBeConverted:databaseFilePath]); - - YapRecordDatabaseSaltBlock recordSaltBlock = ^(NSData *saltData) { - OWSAssertDebug(saltData); - - XCTFail(@"No conversion should be necessary"); - return NO; - }; - - NSError *_Nullable error = [YapDatabaseCryptoUtils convertDatabaseIfNecessary:databaseFilePath - databasePassword:databasePassword - options:OWSStorage.defaultDatabaseOptions - recordSaltBlock:recordSaltBlock]; - if (error) { - OWSLogError(@"error: %@", error); - } - XCTAssertNil(error); - XCTAssertFalse([YapDatabaseCryptoUtils doesDatabaseNeedToBeConverted:databaseFilePath]); - - BOOL isValid = [self verifyTestDatabase:databaseFilePath - databasePassword:databasePassword - databaseSalt:databaseSalt - databaseKeySpec:databaseKeySpec]; - XCTAssertTrue(isValid); -} - -// Simulates a legacy user who needs to convert their database. -- (void)testConversionWithoutYapDatabase -{ - sqlite3 *db; - sqlite3_stmt *stmt; - const int ROWSTOINSERT = 3; - - NSString *databaseFilePath = [self createTempDatabaseFilePath]; - - OWSAssertDebug(![[NSFileManager defaultManager] fileExistsAtPath:databaseFilePath]); - - NSData *keyData = [self randomDatabasePassword]; - - /* Step 1. Create a new encrypted database. */ - - int openFlags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_PRIVATECACHE; - - int rc = sqlite3_open_v2([databaseFilePath UTF8String], &db, openFlags, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_key(db, [keyData bytes], (int)[keyData length]); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_exec(db, "PRAGMA journal_mode = WAL;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_exec(db, "CREATE TABLE IF NOT EXISTS t1 (a INTEGER PRIMARY KEY AUTOINCREMENT, b TEXT);", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_exec(db, "BEGIN;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_prepare_v2(db, "INSERT INTO t1(b) VALUES (?);", -1, &stmt, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - for(int row = 0; row < ROWSTOINSERT; row++) { - rc = sqlite3_bind_text(stmt, 1, [[NSString stringWithFormat:@"%d", (int) arc4random()] UTF8String], -1, SQLITE_TRANSIENT); - XCTAssertTrue(rc == SQLITE_OK); - rc = sqlite3_step(stmt); - XCTAssertTrue(rc == SQLITE_DONE); - rc = sqlite3_reset(stmt); - XCTAssertTrue(rc == SQLITE_OK); - } - rc = sqlite3_finalize(stmt); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_exec(db, "COMMIT;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - NSString *salt = [self executeSingleStringQuery:@"PRAGMA cipher_salt;" - db:db]; - - rc = sqlite3_close(db); - XCTAssertTrue(rc == SQLITE_OK); - - [self logHeaderOfDatabaseFile:databaseFilePath - label:@"Unconverted header"]; - - /* Step 2. Rewrite header */ - - rc = sqlite3_open_v2([databaseFilePath UTF8String], &db, openFlags, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_key(db, [keyData bytes], (int)[keyData length]); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_exec(db, "PRAGMA journal_mode = WAL;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - rc = sqlite3_exec(db, "PRAGMA synchronous = NORMAL;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - rc = sqlite3_exec(db, "PRAGMA journal_size_limit = 1048576;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_exec(db, "PRAGMA cipher_plaintext_header_size = 32;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_exec(db, "PRAGMA user_version = 2;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - int log, ckpt; - rc = sqlite3_wal_checkpoint_v2(db, NULL, SQLITE_CHECKPOINT_FULL, &log, &ckpt); - XCTAssertTrue(rc == SQLITE_OK); - OWSLogInfo(@"log = %d, ckpt = %d", log, ckpt); - - rc = sqlite3_close(db); - XCTAssertTrue(rc == SQLITE_OK); - - [self logHeaderOfDatabaseFile:databaseFilePath - label:@"Converted header"]; - - /* Step 3. Open the database and query it */ - - rc = sqlite3_open_v2([databaseFilePath UTF8String], &db, openFlags, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_key(db, [keyData bytes], (int)[keyData length]); - XCTAssertTrue(rc == SQLITE_OK); - - NSString *saltPragma = [NSString stringWithFormat:@"PRAGMA cipher_salt = \"x'%@'\";", salt]; - OWSLogInfo(@"salt pragma = %@", saltPragma); - rc = sqlite3_exec(db, [saltPragma UTF8String], NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_exec(db, "PRAGMA cipher_plaintext_header_size = 32;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_exec(db, "PRAGMA journal_mode = WAL;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - rc = sqlite3_exec(db, "PRAGMA synchronous = NORMAL;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - rc = sqlite3_exec(db, "PRAGMA journal_size_limit = 1048576;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - XCTAssertEqual(2, [self executeSingleIntQuery:@"SELECT count(*) FROM sqlite_master;" db:db]); - - XCTAssertEqual(ROWSTOINSERT, [self executeSingleIntQuery:@"SELECT count(*) FROM t1;" db:db]); - - rc = sqlite3_close(db); - XCTAssertTrue(rc == SQLITE_OK); -} - -- (int)executeSingleIntQuery:(NSString *)sql - db:(sqlite3 *)db -{ - sqlite3_stmt *stmt; - - int rc = sqlite3_prepare_v2(db, sql.UTF8String, -1, &stmt, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_step(stmt); - XCTAssertTrue(rc = SQLITE_ROW); - - int result = sqlite3_column_int(stmt, 0); - - rc = sqlite3_finalize(stmt); - XCTAssertTrue(rc == SQLITE_OK); - - return result; -} - -- (NSString *)executeSingleStringQuery:(NSString *)sql - db:(sqlite3 *)db -{ - sqlite3_stmt *stmt; - - int rc = sqlite3_prepare_v2(db, sql.UTF8String, -1, &stmt, NULL); - XCTAssertTrue(rc == SQLITE_OK); - rc = sqlite3_step(stmt); - XCTAssertTrue(rc = SQLITE_ROW); - NSString *result = [NSString stringWithFormat:@"%s", sqlite3_column_text(stmt, 0)]; - - rc = sqlite3_finalize(stmt); - XCTAssertTrue(rc == SQLITE_OK); - - return result; -} - -// Simulates a new user who makes a new, pre-converted database. -- (void)testNewUserWithoutYapDatabase -{ - sqlite3 *db; - sqlite3_stmt *stmt; - const int ROWSTOINSERT = 3; - - NSString *databaseFilePath = [self createTempDatabaseFilePath]; - - OWSAssertDebug(![[NSFileManager defaultManager] fileExistsAtPath:databaseFilePath]); - - NSData *keyData = [self randomDatabasePassword]; - NSData *databaseSalt = [self randomDatabaseSalt]; - NSString *salt = databaseSalt.hexadecimalString; - - /* Step 1. Create a new encrypted database. */ - - int openFlags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_PRIVATECACHE; - - int rc = sqlite3_open_v2([databaseFilePath UTF8String], &db, openFlags, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_key(db, [keyData bytes], (int)[keyData length]); - XCTAssertTrue(rc == SQLITE_OK); - - NSString *saltPragma = [NSString stringWithFormat:@"PRAGMA cipher_salt = \"x'%@'\";", salt]; - OWSLogInfo(@"salt pragma = %@", saltPragma); - rc = sqlite3_exec(db, [saltPragma UTF8String], NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_exec(db, "PRAGMA cipher_plaintext_header_size = 32;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_exec(db, "PRAGMA journal_mode = WAL;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_exec(db, "CREATE TABLE IF NOT EXISTS t1 (a INTEGER PRIMARY KEY AUTOINCREMENT, b TEXT);", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_exec(db, "BEGIN;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_prepare_v2(db, "INSERT INTO t1(b) VALUES (?);", -1, &stmt, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - for(int row = 0; row < ROWSTOINSERT; row++) { - rc = sqlite3_bind_text(stmt, 1, [[NSString stringWithFormat:@"%d", (int) arc4random()] UTF8String], -1, SQLITE_TRANSIENT); - XCTAssertTrue(rc == SQLITE_OK); - rc = sqlite3_step(stmt); - XCTAssertTrue(rc == SQLITE_DONE); - rc = sqlite3_reset(stmt); - XCTAssertTrue(rc == SQLITE_OK); - } - rc = sqlite3_finalize(stmt); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_exec(db, "COMMIT;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_close(db); - XCTAssertTrue(rc == SQLITE_OK); - - /* Step 2. Open the database and query it */ - - rc = sqlite3_open_v2([databaseFilePath UTF8String], &db, openFlags, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_key(db, [keyData bytes], (int)[keyData length]); - XCTAssertTrue(rc == SQLITE_OK); - - // NSString *saltPragma = [NSString stringWithFormat:@"PRAGMA cipher_salt = \"x'%@'\";", salt]; - // OWSLogInfo(@"salt pragma = %@", saltPragma); - rc = sqlite3_exec(db, [saltPragma UTF8String], NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_exec(db, "PRAGMA cipher_plaintext_header_size = 32;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_exec(db, "PRAGMA journal_mode = WAL;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - rc = sqlite3_exec(db, "PRAGMA synchronous = NORMAL;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - rc = sqlite3_exec(db, "PRAGMA journal_size_limit = 1048576;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - XCTAssertEqual(2, [self executeSingleIntQuery:@"SELECT count(*) FROM sqlite_master;" db:db]); - - XCTAssertEqual(ROWSTOINSERT, [self executeSingleIntQuery:@"SELECT count(*) FROM t1;" db:db]); - - rc = sqlite3_close(db); - XCTAssertTrue(rc == SQLITE_OK); -} - -// Similar to testNewUserWithoutYapDatabase, but does more of the -// database configuration that YapDatabase does. -- (void)testNewUserLikeYapDatabase -{ - sqlite3 *db; - sqlite3_stmt *stmt; - const int ROWSTOINSERT = 3; - - NSString *databaseFilePath = [self createTempDatabaseFilePath]; - - OWSAssertDebug(![[NSFileManager defaultManager] fileExistsAtPath:databaseFilePath]); - - NSData *keyData = [self randomDatabasePassword]; - NSData *databaseSalt = [self randomDatabaseSalt]; - NSString *salt = databaseSalt.hexadecimalString; - - /* Step 1. Create a new encrypted database. */ - - int openFlags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_PRIVATECACHE; - - int rc = sqlite3_open_v2([databaseFilePath UTF8String], &db, openFlags, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_key(db, [keyData bytes], (int)[keyData length]); - XCTAssertTrue(rc == SQLITE_OK); - - NSString *saltPragma = [NSString stringWithFormat:@"PRAGMA cipher_salt = \"x'%@'\";", salt]; - OWSLogInfo(@"salt pragma = %@", saltPragma); - rc = sqlite3_exec(db, [saltPragma UTF8String], NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_exec(db, "PRAGMA cipher_plaintext_header_size = 32;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_exec(db, "PRAGMA journal_mode = WAL;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - { - int status = sqlite3_exec(db, "PRAGMA auto_vacuum = FULL; VACUUM;", NULL, NULL, NULL); - XCTAssertEqual(status, SQLITE_OK); - - // Set synchronous to normal for THIS sqlite instance. - // - // This does NOT affect normal connections. - // That is, this does NOT affect YapDatabaseConnection instances. - // The sqlite connections of normal YapDatabaseConnection instances will follow the set pragmaSynchronous value. - // - // The reason we hardcode normal for this sqlite instance is because - // it's only used to write the initial snapshot value. - // And this doesn't need to be durable, as it is initialized to zero everytime. - // - // (This sqlite db is also used to perform checkpoints. - // But a normal value won't affect these operations, - // as they will perform sync operations whether the connection is normal or full.) - - status = sqlite3_exec(db, "PRAGMA synchronous = NORMAL;", NULL, NULL, NULL); - XCTAssertEqual(status, SQLITE_OK); - - // Set journal_size_imit. - // - // We only need to do set this pragma for THIS connection, - // because it is the only connection that performs checkpoints. - - NSString *pragma_journal_size_limit = - [NSString stringWithFormat:@"PRAGMA journal_size_limit = %d;", 0]; - - status = sqlite3_exec(db, [pragma_journal_size_limit UTF8String], NULL, NULL, NULL); - XCTAssertEqual(status, SQLITE_OK); - - // Disable autocheckpointing. - // - // YapDatabase has its own optimized checkpointing algorithm built-in. - // It knows the state of every active connection for the database, - // so it can invoke the checkpoint methods at the precise time in which a checkpoint can be most effective. - - status = sqlite3_wal_autocheckpoint(db, 0); - XCTAssertEqual(status, SQLITE_OK); - } - - rc = sqlite3_exec(db, "CREATE TABLE IF NOT EXISTS t1 (a INTEGER PRIMARY KEY AUTOINCREMENT, b TEXT);", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_exec(db, "BEGIN;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_prepare_v2(db, "INSERT INTO t1(b) VALUES (?);", -1, &stmt, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - for(int row = 0; row < ROWSTOINSERT; row++) { - rc = sqlite3_bind_text(stmt, 1, [[NSString stringWithFormat:@"%d", (int) arc4random()] UTF8String], -1, SQLITE_TRANSIENT); - XCTAssertTrue(rc == SQLITE_OK); - rc = sqlite3_step(stmt); - XCTAssertTrue(rc == SQLITE_DONE); - rc = sqlite3_reset(stmt); - XCTAssertTrue(rc == SQLITE_OK); - } - rc = sqlite3_finalize(stmt); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_exec(db, "COMMIT;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_close(db); - XCTAssertTrue(rc == SQLITE_OK); - - /* Step 2. Open the database and query it */ - - rc = sqlite3_open_v2([databaseFilePath UTF8String], &db, openFlags, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_key(db, [keyData bytes], (int)[keyData length]); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_exec(db, [saltPragma UTF8String], NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_exec(db, "PRAGMA cipher_plaintext_header_size = 32;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - rc = sqlite3_exec(db, "PRAGMA journal_mode = WAL;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - rc = sqlite3_exec(db, "PRAGMA synchronous = NORMAL;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - rc = sqlite3_exec(db, "PRAGMA journal_size_limit = 1048576;", NULL, NULL, NULL); - XCTAssertTrue(rc == SQLITE_OK); - - XCTAssertEqual(2, [self executeSingleIntQuery:@"SELECT count(*) FROM sqlite_master;" db:db]); - - XCTAssertEqual(ROWSTOINSERT, [self executeSingleIntQuery:@"SELECT count(*) FROM t1;" db:db]); - - rc = sqlite3_close(db); - XCTAssertTrue(rc == SQLITE_OK); -} - -- (void)logHeaderOfDatabaseFile:(NSString *)databaseFilePath - label:(NSString *)label -{ - OWSAssertDebug(databaseFilePath.length > 0); - OWSAssertDebug(label.length > 0); - - NSData *headerData = - [YapDatabaseCryptoUtils readFirstNBytesOfDatabaseFile:databaseFilePath byteCount:kSqliteHeaderLength]; - OWSAssertDebug(headerData); - NSMutableString *output = [NSMutableString new]; - [output appendFormat:@"Hex: %@, ", headerData.hexadecimalString]; - [output appendString:@"Ascii: "]; - NSMutableCharacterSet *characterSet = [NSMutableCharacterSet new]; - [characterSet formUnionWithCharacterSet:[NSCharacterSet whitespaceCharacterSet]]; - [characterSet formUnionWithCharacterSet:[NSCharacterSet alphanumericCharacterSet]]; - [characterSet formUnionWithCharacterSet:[NSCharacterSet punctuationCharacterSet]]; - [characterSet formUnionWithCharacterSet:[NSCharacterSet symbolCharacterSet]]; - - const unsigned char *bytes = (const unsigned char *) headerData.bytes; - for (NSUInteger i=0; i < headerData.length; i++) { - unsigned char byte = bytes[i]; - if ([characterSet characterIsMember:(unichar)byte]) { - [output appendFormat:@"%C", (unichar)byte]; - } else { - [output appendString:@"_"]; - } - } - OWSLogInfo(@"%@: %@", label, output); -} - - -#pragma mark - keychain strategy benchmarks - - -- (void)verifyTestDatabase:(NSString *)databaseFilePath - databaseKeySpecBlock:(NSData *_Nullable (^_Nullable)(void))databaseKeySpecBlock - databasePasswordBlock:(NSData *_Nullable (^_Nullable)(void))databasePasswordBlock - databaseSaltBlock:(NSData *_Nullable (^_Nullable)(void))databaseSaltBlock -{ - NSData *_Nullable databaseKeySpec = databaseKeySpecBlock ? databaseKeySpecBlock() : nil; - NSData *_Nullable databasePassword = databasePasswordBlock ? databasePasswordBlock() : nil; - NSData *_Nullable databaseSalt = databaseSaltBlock ? databaseSaltBlock() : nil; - - [self verifyTestDatabase:databaseFilePath - databasePassword:databasePassword - databaseSalt:databaseSalt - databaseKeySpec:databaseKeySpec]; -} - -- (void)createTestDatabase:(NSString *)databaseFilePath - databaseKeySpecBlock:(NSData *_Nullable (^_Nullable)(void))databaseKeySpecBlock - databasePasswordBlock:(NSData *_Nullable (^_Nullable)(void))databasePasswordBlock - databaseSaltBlock:(NSData *_Nullable (^_Nullable)(void))databaseSaltBlock -{ - NSData *_Nullable databaseKeySpec = databaseKeySpecBlock ? databaseKeySpecBlock() : nil; - NSData *_Nullable databasePassword = databasePasswordBlock ? databasePasswordBlock() : nil; - NSData *_Nullable databaseSalt = databaseSaltBlock ? databaseSaltBlock() : nil; - - [self createTestDatabase:databaseFilePath - databasePassword:databasePassword - databaseSalt:databaseSalt - databaseKeySpec:databaseKeySpec]; -} - -- (void)storeTestPasswordInKeychain:(NSData *)password -{ - // legacy password length - OWSAssertDebug(password.length == 30); - [OWSStorage storeKeyChainValue:password keychainKey:@"_OWSTestingPassword"]; -} - -- (nullable NSData *)fetchTestPasswordFromKeychain -{ - NSError *error; - NSData *password = [OWSStorage tryToLoadKeyChainValue:@"_OWSTestingPassword" errorHandle:&error]; - OWSAssertDebug(password); - OWSAssertDebug(!error); - // legacy password length - OWSAssertDebug(password.length == 30); - - return password; -} - -- (void)storeTestSaltInKeychain:(NSData *)salt -{ - OWSAssertDebug(salt.length == kSQLCipherSaltLength); - [OWSStorage storeKeyChainValue:salt keychainKey:@"_OWSTestingSalt"]; -} - -- (nullable NSData *)fetchTestSaltFromKeychain -{ - NSError *error; - NSData *salt = [OWSStorage tryToLoadKeyChainValue:@"_OWSTestingSalt" errorHandle:&error]; - OWSAssertDebug(salt); - OWSAssertDebug(!error); - OWSAssertDebug(salt.length == kSQLCipherSaltLength); - return salt; -} - -- (void)storeTestKeySpecInKeychain:(NSData *)keySpec -{ - OWSAssertDebug(keySpec.length == kSQLCipherKeySpecLength); - [OWSStorage storeKeyChainValue:keySpec keychainKey:@"_OWSTestingKeySpec"]; -} - -- (nullable NSData *)fetchTestKeySpecFromKeychain -{ - NSError *error; - NSData *keySpec = [OWSStorage tryToLoadKeyChainValue:@"_OWSTestingKeySpec" errorHandle:&error]; - OWSAssertDebug(keySpec); - OWSAssertDebug(!error); - OWSAssertDebug(keySpec.length == kSQLCipherKeySpecLength); - - return keySpec; -} - -- (void)testWidePassphraseFetchingStrategy -{ - NSData *password = [self randomDatabasePassword]; - NSData *salt = [self randomDatabaseSalt]; - - [self measureBlock:^{ - NSString *databaseFilePath = [self createTempDatabaseFilePath]; - - [self createTestDatabase:databaseFilePath - databaseKeySpecBlock:nil - databasePasswordBlock:^() { - return password; - } - databaseSaltBlock:^() { - return salt; - }]; - - [self verifyTestDatabase:databaseFilePath - databaseKeySpecBlock:nil - databasePasswordBlock:^() { - return password; - } - databaseSaltBlock:^() { - return salt; - }]; - }]; -} - -- (void)testGranularPassphraseFetchingStrategy -{ - NSData *password = [self randomDatabasePassword]; - NSData *salt = [self randomDatabaseSalt]; - [self storeTestPasswordInKeychain:password]; - [self storeTestSaltInKeychain:salt]; - - [self measureBlock:^{ - - NSString *databaseFilePath = [self createTempDatabaseFilePath]; - - - [self createTestDatabase:databaseFilePath - databaseKeySpecBlock:nil - databasePasswordBlock:^() { - return [self fetchTestPasswordFromKeychain]; - } - databaseSaltBlock:^() { - return [self fetchTestSaltFromKeychain]; - }]; - - [self verifyTestDatabase:databaseFilePath - databaseKeySpecBlock:nil - databasePasswordBlock:^() { - return [self fetchTestPasswordFromKeychain]; - } - databaseSaltBlock:^() { - return [self fetchTestSaltFromKeychain]; - }]; - }]; -} - -- (void)testGranularKeySpecFetchingStrategy -{ - NSData *keySpec = [self randomDatabaseKeySpec]; - [self storeTestKeySpecInKeychain:keySpec]; - - [self measureBlock:^{ - NSString *databaseFilePath = [self createTempDatabaseFilePath]; - - [self createTestDatabase:databaseFilePath - databaseKeySpecBlock:^() { - return [self fetchTestKeySpecFromKeychain]; - } - databasePasswordBlock:nil - databaseSaltBlock:nil]; - - [self verifyTestDatabase:databaseFilePath - databaseKeySpecBlock:^() { - return [self fetchTestKeySpecFromKeychain]; - } - databasePasswordBlock:nil - databaseSaltBlock:nil]; - }]; -} - -- (void)testWideKeyFetchingStrategy -{ - NSData *keySpec = [self randomDatabaseKeySpec]; - - [self measureBlock:^{ - NSString *databaseFilePath = [self createTempDatabaseFilePath]; - - [self createTestDatabase:databaseFilePath - databaseKeySpecBlock:^() { - return keySpec; - } - databasePasswordBlock:nil - databaseSaltBlock:nil]; - - [self verifyTestDatabase:databaseFilePath - databaseKeySpecBlock:^() { - return keySpec; - } - databasePasswordBlock:nil - databaseSaltBlock:nil]; - }]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/test/util/OWSOrphanDataCleanerTest.m b/Session/test/util/OWSOrphanDataCleanerTest.m deleted file mode 100644 index 9bea7053c..000000000 --- a/Session/test/util/OWSOrphanDataCleanerTest.m +++ /dev/null @@ -1,252 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "OWSOrphanDataCleaner.h" -#import "SignalBaseTest.h" -#import -#import -#import -#import -#import - -@interface OWSOrphanDataCleaner (Test) - -+ (nullable NSSet *)filePathsInDirectorySafe:(NSString *)dirPath; - -@end - -#pragma mark - - - -@interface OWSOrphanDataCleanerTest : SignalBaseTest - -@end - -#pragma mark - - -@implementation OWSOrphanDataCleanerTest - -#ifdef BROKEN_TESTS - -- (void)setUp -{ - [super setUp]; - // Register views, etc. - [OWSPrimaryStorage registerExtensionsWithMigrationBlock:^{ - }]; - - // Set up initial conditions & Sanity check - XCTAssertEqual(0, [self numberOfItemsInAttachmentsFolder]); - XCTAssertEqual(0, [TSAttachmentStream numberOfKeysInCollection]); - XCTAssertEqual(0, [TSIncomingMessage numberOfKeysInCollection]); - XCTAssertEqual(0, [TSThread numberOfKeysInCollection]); -} - -- (void)tearDown -{ - [super tearDown]; -} - -- (int)numberOfItemsInAttachmentsFolder -{ - NSString *legacyAttachmentsDirPath = TSAttachmentStream.legacyAttachmentsDirPath; - NSSet *_Nullable legacyAttachmentFilePaths = - [OWSOrphanDataCleaner filePathsInDirectorySafe:legacyAttachmentsDirPath]; - - NSString *sharedDataAttachmentsDirPath = TSAttachmentStream.sharedDataAttachmentsDirPath; - NSSet *_Nullable sharedDataAttachmentFilePaths = - [OWSOrphanDataCleaner filePathsInDirectorySafe:sharedDataAttachmentsDirPath]; - - NSMutableSet *attachmentFilePaths = [NSMutableSet new]; - if (legacyAttachmentFilePaths) { - [attachmentFilePaths unionSet:legacyAttachmentFilePaths]; - } - if (sharedDataAttachmentFilePaths) { - [attachmentFilePaths unionSet:sharedDataAttachmentFilePaths]; - } - - return (int)attachmentFilePaths.count; -} - -- (TSIncomingMessage *)createIncomingMessageWithThread:(TSThread *)thread - attachmentIds:(NSArray *)attachmentIds -{ - TSIncomingMessage *incomingMessage = - [[TSIncomingMessage alloc] initIncomingMessageWithTimestamp:1 - inThread:thread - authorId:@"fake-author-id" - sourceDeviceId:OWSDevicePrimaryDeviceId - messageBody:@"footch" - attachmentIds:attachmentIds - expiresInSeconds:0 - quotedMessage:nil - contactShare:nil - linkPreview:nil]; - [incomingMessage save]; - - return incomingMessage; -} - -- (TSAttachmentStream *)createAttachmentStream -{ - NSError *error; - TSAttachmentStream *attachmentStream = - [[TSAttachmentStream alloc] initWithContentType:@"image/jpeg" byteCount:12 sourceFilename:nil]; - [attachmentStream writeData:[NSData new] error:&error]; - - XCTAssertNil(error); - - [attachmentStream save]; - - return attachmentStream; -} - -- (void)testInteractionsWithoutThreadAreDeleted -{ - // This thread is intentionally not saved. It's meant to recreate a situation we've seen where interactions exist - // that reference the id of a thread that no longer exists. Presumably this is the result of a deleted thread not - // properly deleting it's interactions. - TSContactThread *unsavedThread = [[TSContactThread alloc] initWithUniqueId:@"this-thread-does-not-exist"]; - - __unused TSIncomingMessage *incomingMessage = - [self createIncomingMessageWithThread:unsavedThread attachmentIds:@[]]; - - XCTAssertEqual(1, [TSIncomingMessage numberOfKeysInCollection]); - - XCTestExpectation *expectation = [self expectationWithDescription:@"Cleanup"]; - [OWSOrphanDataCleaner auditAndCleanup:YES - completion:^{ - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:5.0 - handler:^(NSError *error) { - if (error) { - XCTFail(@"Expectation Failed with error: %@", error); - } - }]; - - XCTAssertEqual(0, [TSIncomingMessage numberOfKeysInCollection]); -} - -- (void)testInteractionsWithThreadAreNotDeleted -{ - TSContactThread *savedThread = [[TSContactThread alloc] initWithUniqueId:@"this-thread-exists"]; - [savedThread save]; - - __unused TSIncomingMessage *incomingMessage = [self createIncomingMessageWithThread:savedThread attachmentIds:@[]]; - - XCTAssertEqual(1, [TSIncomingMessage numberOfKeysInCollection]); - - XCTestExpectation *expectation = [self expectationWithDescription:@"Cleanup"]; - [OWSOrphanDataCleaner auditAndCleanup:YES - completion:^{ - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:5.0 - handler:^(NSError *error) { - if (error) { - XCTFail(@"Expectation Failed with error: %@", error); - } - }]; - - XCTAssertEqual(1, [TSIncomingMessage numberOfKeysInCollection]); -} - -- (void)testFilesWithoutInteractionsAreDeleted -{ - // sanity check - XCTAssertEqual(0, [self numberOfItemsInAttachmentsFolder]); - - TSAttachmentStream *attachmentStream = [self createAttachmentStream]; - - NSString *orphanFilePath = [attachmentStream originalFilePath]; - BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:orphanFilePath]; - XCTAssert(fileExists); - XCTAssertEqual(1, [self numberOfItemsInAttachmentsFolder]); - - // Do multiple cleanup passes. - for (int i = 0; i < 2; i++) { - XCTestExpectation *expectation = [self expectationWithDescription:@"Cleanup"]; - [OWSOrphanDataCleaner auditAndCleanup:YES - completion:^{ - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:5.0 - handler:^(NSError *error) { - if (error) { - XCTFail(@"Expectation Failed with error: %@", error); - } - }]; - } - - fileExists = [[NSFileManager defaultManager] fileExistsAtPath:orphanFilePath]; - XCTAssertFalse(fileExists); - XCTAssertEqual(0, [self numberOfItemsInAttachmentsFolder]); -} - -- (void)testFilesWithInteractionsAreNotDeleted -{ - TSContactThread *savedThread = [[TSContactThread alloc] initWithUniqueId:@"this-thread-exists"]; - [savedThread save]; - - TSAttachmentStream *attachmentStream = [self createAttachmentStream]; - - __unused TSIncomingMessage *incomingMessage = - [self createIncomingMessageWithThread:savedThread attachmentIds:@[ attachmentStream.uniqueId ]]; - - NSString *attachmentFilePath = [attachmentStream originalFilePath]; - BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:attachmentFilePath]; - XCTAssert(fileExists); - XCTAssertEqual(1, [self numberOfItemsInAttachmentsFolder]); - - XCTestExpectation *expectation = [self expectationWithDescription:@"Cleanup"]; - [OWSOrphanDataCleaner auditAndCleanup:YES - completion:^{ - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:5.0 - handler:^(NSError *error) { - if (error) { - XCTFail(@"Expectation Failed with error: %@", error); - } - }]; - - fileExists = [[NSFileManager defaultManager] fileExistsAtPath:attachmentFilePath]; - XCTAssert(fileExists); - XCTAssertEqual(1, [self numberOfItemsInAttachmentsFolder]); -} - -- (void)testFilesWithoutAttachmentStreamsAreDeleted -{ - NSError *error; - TSAttachmentStream *attachmentStream = - [[TSAttachmentStream alloc] initWithContentType:@"image/jpeg" byteCount:0 sourceFilename:nil]; - [attachmentStream writeData:[NSData new] error:&error]; - // Intentionally not saved, because we want a lingering file. - - NSString *orphanFilePath = [attachmentStream originalFilePath]; - BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:orphanFilePath]; - XCTAssert(fileExists); - XCTAssertEqual(1, [self numberOfItemsInAttachmentsFolder]); - - XCTestExpectation *expectation = [self expectationWithDescription:@"Cleanup"]; - [OWSOrphanDataCleaner auditAndCleanup:YES - completion:^{ - [expectation fulfill]; - }]; - [self waitForExpectationsWithTimeout:5.0 - handler:^(NSError *error) { - if (error) { - XCTFail(@"Expectation Failed with error: %@", error); - } - }]; - - fileExists = [[NSFileManager defaultManager] fileExistsAtPath:orphanFilePath]; - XCTAssertFalse(fileExists); - XCTAssertEqual(0, [self numberOfItemsInAttachmentsFolder]); -} - -#endif - -@end diff --git a/Session/test/util/OWSScrubbingLogFormatterTest.m b/Session/test/util/OWSScrubbingLogFormatterTest.m deleted file mode 100644 index 16ac6eb1a..000000000 --- a/Session/test/util/OWSScrubbingLogFormatterTest.m +++ /dev/null @@ -1,148 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "OWSScrubbingLogFormatter.h" -#import "SignalBaseTest.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface OWSScrubbingLogFormatterTest : SignalBaseTest - -@property (nonatomic) NSDate *testDate; - -@end - -@implementation OWSScrubbingLogFormatterTest - -- (void)setUp -{ - [super setUp]; - - self.testDate = [NSDate new]; -} - -- (void)tearDown -{ - [super tearDown]; -} - -- (DDLogMessage *)messageWithString:(NSString *)string -{ - return [[DDLogMessage alloc] initWithMessage:string - level:DDLogLevelInfo - flag:0 - context:0 - file:@"mock file name" - function:@"mock function name" - line:0 - tag:nil - options:0 - timestamp:self.testDate]; -} - -- (void)testDataScrubbed -{ - NSDictionary *expectedOutputs = @{ - @"<01234567 89a23def 23234567 89ab1234>" : @"[ REDACTED_DATA:01... ]", - @"My data is: <01234567 89a23def 23234567 89ab1223>" : @"My data is: [ REDACTED_DATA:01... ]", - @"My data is <12345670 89a23def 23234567 89ab1223> their data is <87654321 89ab1234>" : - @"My data is [ REDACTED_DATA:12... ] their data is [ REDACTED_DATA:87... ]" - }; - - OWSScrubbingLogFormatter *formatter = [OWSScrubbingLogFormatter new]; - - // Other formatters add a dynamic date prefix to log lines. We truncate that when comparing our expected output. - NSUInteger datePrefixLength = [formatter formatLogMessage:[self messageWithString:@""]].length; - - for (NSString *input in expectedOutputs) { - - NSString *rawActual = [formatter formatLogMessage:[self messageWithString:input]]; - - // strip out dynamic date portion of log line - NSString *actual = - [rawActual substringWithRange:NSMakeRange(datePrefixLength, rawActual.length - datePrefixLength)]; - - NSString *expected = expectedOutputs[input]; - - XCTAssertEqualObjects(expected, actual); - } -} - -- (void)testPhoneNumbersScrubbed -{ - NSArray *phoneStrings = @[ - @"+13331231234 ", - @"+4113331231234", - @"+13331231234 something something +13331231234", - ]; - - for (NSString *phoneString in phoneStrings) { - OWSScrubbingLogFormatter *formatter = [OWSScrubbingLogFormatter new]; - NSString *messageText = [NSString stringWithFormat:@"My phone number is %@", phoneString]; - NSString *actual = [formatter formatLogMessage:[self messageWithString:messageText]]; - NSRange redactedRange = [actual rangeOfString:@"My phone number is [ REDACTED_PHONE_NUMBER:xxx234 ]"]; - XCTAssertNotEqual(NSNotFound, redactedRange.location, "Failed to redact phone string: %@", phoneString); - - NSRange phoneNumberRange = [actual rangeOfString:phoneString]; - XCTAssertEqual(NSNotFound, phoneNumberRange.location, "Failed to redact phone string: %@", phoneString); - } -} - -- (void)testNonPhoneNumberNotScrubbed -{ - OWSScrubbingLogFormatter *formatter = [OWSScrubbingLogFormatter new]; - NSString *actual = - [formatter formatLogMessage:[self messageWithString:[NSString stringWithFormat:@"Some unfiltered string"]]]; - - NSRange redactedRange = [actual rangeOfString:@"Some unfiltered string"]; - XCTAssertNotEqual(NSNotFound, redactedRange.location, "Shouldn't touch non phone string."); -} - -- (void)testIPAddressesScrubbed -{ - id scrubbingFormatter = [OWSScrubbingLogFormatter new]; - id defaultFormatter = [DDLogFileFormatterDefault new]; - - NSDictionary *valueMap = @{ - @"0.0.0.0" : @"[ REDACTED_IPV4_ADDRESS:...0 ]", - @"127.0.0.1" : @"[ REDACTED_IPV4_ADDRESS:...1 ]", - @"255.255.255.255" : @"[ REDACTED_IPV4_ADDRESS:...255 ]", - @"1.2.3.4" : @"[ REDACTED_IPV4_ADDRESS:...4 ]", - }; - NSArray *messageFormats = @[ - @"a%@b", - @"http://%@", - @"http://%@/", - @"%@ and %@ and %@", - @"%@", - @"%@ %@", - @"no ip address!", - @"", - ]; - - for (NSString *ipAddress in valueMap) { - NSString *redactedIPAddress = valueMap[ipAddress]; - - for (NSString *messageFormat in messageFormats) { - NSString *message = [messageFormat stringByReplacingOccurrencesOfString:@"%@" withString:ipAddress]; - - NSString *unredactedMessage = [defaultFormatter formatLogMessage:[self messageWithString:messageFormat]]; - NSString *expectedRedactedMessage = [defaultFormatter - formatLogMessage:[self messageWithString:[messageFormat - stringByReplacingOccurrencesOfString:@"%@" - withString:redactedIPAddress]]]; - NSString *redactedMessage = [scrubbingFormatter formatLogMessage:[self messageWithString:message]]; - - XCTAssertEqualObjects( - expectedRedactedMessage, redactedMessage, @"Scrubbing failed for message: %@", unredactedMessage); - - NSRange ipAddressRange = [redactedMessage rangeOfString:ipAddress]; - XCTAssertEqual(NSNotFound, ipAddressRange.location, "Failed to redact IP address: %@", unredactedMessage); - } - } -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/test/util/ProtoParsingTest.m b/Session/test/util/ProtoParsingTest.m deleted file mode 100644 index cfe2b788f..000000000 --- a/Session/test/util/ProtoParsingTest.m +++ /dev/null @@ -1,179 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "SignalBaseTest.h" -#import -#import -#import -#import -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@class CNContact; - -@interface TestContactsManager : NSObject - -@end - -#pragma mark - - -@implementation TestContactsManager - -- (NSString *)displayNameForPhoneIdentifier:(NSString *_Nullable)phoneNumber -{ - return phoneNumber; -} - -- (NSArray *)signalAccounts -{ - return @[]; -} - -- (BOOL)isSystemContact:(NSString *)recipientId -{ - return YES; -} - -- (BOOL)isSystemContactWithSignalAccount:(NSString *)recipientId -{ - return YES; -} - -- (NSComparisonResult)compareSignalAccount:(SignalAccount *)left withSignalAccount:(SignalAccount *)right -{ - return NSOrderedSame; -} - -- (nullable CNContact *)cnContactWithId:(nullable NSString *)contactId -{ - return nil; -} - -- (nullable NSData *)avatarDataForCNContactId:(nullable NSString *)contactId -{ - return nil; -} - -- (nullable UIImage *)avatarImageForCNContactId:(nullable NSString *)contactId -{ - return nil; -} - -- (nonnull NSString *)displayNameForPhoneIdentifier:(NSString * _Nullable)recipientId transaction:(nonnull YapDatabaseReadTransaction *)transaction { - return nil; -} - -@end - -#pragma mark - - -@interface FakeContact : NSObject - -@property (nullable, nonatomic) NSString *firstName; -@property (nullable, nonatomic) NSString *lastName; -@property (nonatomic) NSString *fullName; -@property (nonatomic) NSString *comparableNameFirstLast; -@property (nonatomic) NSString *comparableNameLastFirst; -@property (nonatomic) NSArray *parsedPhoneNumbers; -@property (nonatomic) NSArray *userTextPhoneNumbers; -@property (nonatomic) NSArray *emails; -@property (nonatomic) NSString *uniqueId; -@property (nonatomic) BOOL isSignalContact; -@property (nonatomic) NSString *cnContactId; - -@end - -#pragma mark - - -@implementation FakeContact - -@end - -#pragma mark - - -@interface ProtoParsingTest : SignalBaseTest - -@end - -#pragma mark - - -@implementation ProtoParsingTest - -- (void)testProtoParsing_empty -{ - NSData *data = [NSData new]; - NSError *error; - SSKProtoEnvelope *_Nullable envelope = [SSKProtoEnvelope parseData:data error:&error]; - XCTAssertNil(envelope); - XCTAssertNotNil(error); -} - -- (void)testProtoParsing_wrong1 -{ - NSData *data = [@"test" dataUsingEncoding:NSUTF8StringEncoding]; - NSError *error; - SSKProtoEnvelope *_Nullable envelope = [SSKProtoEnvelope parseData:data error:&error]; - XCTAssertNil(envelope); - XCTAssertNotNil(error); -} - -- (void)testProtoStreams -{ - NSArray *signalAccounts = @[ - [[SignalAccount alloc] initWithRecipientId:@"+13213214321"], - [[SignalAccount alloc] initWithRecipientId:@"+13213214322"], - [[SignalAccount alloc] initWithRecipientId:@"+13213214323"], - ]; - NSData *_Nullable streamData = [self dataForSyncingContacts:signalAccounts]; - XCTAssertNotNil(streamData); - - XCTAssertEqualObjects(streamData.hexadecimalString, - @"2c0a0c2b31333231333231343332311209416c69636520426f62220f66616b6520636f6c6f72206e616d6540002c0a0c2b31333231333" - @"231343332321209416c69636520426f62220f66616b6520636f6c6f72206e616d6540002c0a0c2b31333231333231343332331209416c" - @"69636520426f62220f66616b6520636f6c6f72206e616d654000"); -} - -- (nullable NSData *)dataForSyncingContacts:(NSArray *)signalAccounts -{ - TestContactsManager *contactsManager = [TestContactsManager new]; - NSOutputStream *dataOutputStream = [NSOutputStream outputStreamToMemory]; - [dataOutputStream open]; - OWSContactsOutputStream *contactsOutputStream = - [[OWSContactsOutputStream alloc] initWithOutputStream:dataOutputStream]; - - for (SignalAccount *signalAccount in signalAccounts) { - OWSRecipientIdentity *_Nullable recipientIdentity = nil; - // NSData *_Nullable profileKeyData = [Randomness generateRandomBytes:32]; - NSData *_Nullable profileKeyData = nil; - OWSDisappearingMessagesConfiguration *_Nullable disappearingMessagesConfiguration = nil; - NSString *_Nullable conversationColorName = @"fake color name"; - - FakeContact *fakeContact = [FakeContact new]; - fakeContact.cnContactId = @"123"; - fakeContact.fullName = @"Alice Bob"; - signalAccount.contact = (Contact *)fakeContact; - - [contactsOutputStream writeSignalAccount:signalAccount - recipientIdentity:recipientIdentity - profileKeyData:profileKeyData - contactsManager:contactsManager - conversationColorName:conversationColorName - disappearingMessagesConfiguration:disappearingMessagesConfiguration]; - } - - [dataOutputStream close]; - - if (contactsOutputStream.hasError) { - return nil; - } - - return [dataOutputStream propertyForKey:NSStreamDataWrittenToMemoryStreamKey]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/test/util/SearcherTest.swift b/Session/test/util/SearcherTest.swift deleted file mode 100644 index 5e8b7d488..000000000 --- a/Session/test/util/SearcherTest.swift +++ /dev/null @@ -1,434 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -import XCTest -import Contacts -@testable import Session -@testable import SignalUtilitiesKit - -// TODO: We might be able to merge this with OWSFakeContactsManager. -@objc -class FullTextSearcherContactsManager: NSObject, ContactsManagerProtocol { - func displayName(forPhoneIdentifier recipientId: String?, transaction: YapDatabaseReadTransaction) -> String { - return self.displayName(forPhoneIdentifier: recipientId) - } - - func displayName(forPhoneIdentifier phoneNumber: String?) -> String { - if phoneNumber == aliceRecipientId { - return "Alice" - } else if phoneNumber == bobRecipientId { - return "Bob Barker" - } else { - return "" - } - } - - func signalAccounts() -> [SignalAccount] { - return [] - } - - func isSystemContact(_ recipientId: String) -> Bool { - return true - } - - func isSystemContact(withSignalAccount recipientId: String) -> Bool { - return true - } - - func compare(signalAccount left: SignalAccount, with right: SignalAccount) -> ComparisonResult { - owsFailDebug("if this method ends up being used by the tests, we should provide a better implementation.") - - return .orderedAscending - } - - func cnContact(withId contactId: String?) -> CNContact? { - return nil - } - - func avatarData(forCNContactId contactId: String?) -> Data? { - return nil - } - - func avatarImage(forCNContactId contactId: String?) -> UIImage? { - return nil - } -} - -private let bobRecipientId = "+49030183000" -private let aliceRecipientId = "+12345678900" - -class FullTextSearcherTest: SignalBaseTest { - - // MARK: - Dependencies - var searcher: FullTextSearcher { - return FullTextSearcher.shared - } - - var dbConnection: YapDatabaseConnection { - return OWSPrimaryStorage.shared().dbReadWriteConnection - } - - // MARK: - Test Life Cycle - - override func tearDown() { - super.tearDown() - } - - /* - override func setUp() { - super.setUp() - - FullTextSearchFinder.ensureDatabaseExtensionRegistered(storage: OWSPrimaryStorage.shared()) - - // Replace this singleton. - SSKEnvironment.shared.contactsManager = FullTextSearcherContactsManager() - - self.dbConnection.readWrite { transaction in - let bookModel = TSGroupModel(title: "Book Club", memberIds: [aliceRecipientId, bobRecipientId], image: nil, groupId: Randomness.generateRandomBytes(kGroupIdLength)) - let bookClubGroupThread = TSGroupThread.getOrCreateThread(with: bookModel, transaction: transaction) - self.bookClubThread = ThreadViewModel(thread: bookClubGroupThread, transaction: transaction) - - let snackModel = TSGroupModel(title: "Snack Club", memberIds: [aliceRecipientId], image: nil, groupId: Randomness.generateRandomBytes(kGroupIdLength)) - let snackClubGroupThread = TSGroupThread.getOrCreateThread(with: snackModel, transaction: transaction) - self.snackClubThread = ThreadViewModel(thread: snackClubGroupThread, transaction: transaction) - - let aliceContactThread = TSContactThread.getOrCreateThread(withContactId: aliceRecipientId, transaction: transaction) - self.aliceThread = ThreadViewModel(thread: aliceContactThread, transaction: transaction) - - let bobContactThread = TSContactThread.getOrCreateThread(withContactId: bobRecipientId, transaction: transaction) - self.bobEmptyThread = ThreadViewModel(thread: bobContactThread, transaction: transaction) - - let helloAlice = TSOutgoingMessage(in: aliceContactThread, messageBody: "Hello Alice", attachmentId: nil) - helloAlice.save(with: transaction) - - let goodbyeAlice = TSOutgoingMessage(in: aliceContactThread, messageBody: "Goodbye Alice", attachmentId: nil) - goodbyeAlice.save(with: transaction) - - let helloBookClub = TSOutgoingMessage(in: bookClubGroupThread, messageBody: "Hello Book Club", attachmentId: nil) - helloBookClub.save(with: transaction) - - let goodbyeBookClub = TSOutgoingMessage(in: bookClubGroupThread, messageBody: "Goodbye Book Club", attachmentId: nil) - goodbyeBookClub.save(with: transaction) - - let bobsPhoneNumber = TSOutgoingMessage(in: bookClubGroupThread, messageBody: "My phone number is: 321-321-4321", attachmentId: nil) - bobsPhoneNumber.save(with: transaction) - - let bobsFaxNumber = TSOutgoingMessage(in: bookClubGroupThread, messageBody: "My fax is: 222-333-4444", attachmentId: nil) - bobsFaxNumber.save(with: transaction) - } - } - - // MARK: - Fixtures - - var bookClubThread: ThreadViewModel! - var snackClubThread: ThreadViewModel! - - var aliceThread: ThreadViewModel! - var bobEmptyThread: ThreadViewModel! - - // MARK: Tests - - func testSearchByGroupName() { - var threads: [ThreadViewModel] = [] - - // No Match - threads = searchConversations(searchText: "asdasdasd") - XCTAssert(threads.isEmpty) - - // Partial Match - threads = searchConversations(searchText: "Book") - XCTAssertEqual(1, threads.count) - XCTAssertEqual([bookClubThread], threads) - - threads = searchConversations(searchText: "Snack") - XCTAssertEqual(1, threads.count) - XCTAssertEqual([snackClubThread], threads) - - // Multiple Partial Matches - threads = searchConversations(searchText: "Club") - XCTAssertEqual(2, threads.count) - XCTAssertEqual([bookClubThread, snackClubThread], threads) - - // Match Name Exactly - threads = searchConversations(searchText: "Book Club") - XCTAssertEqual(1, threads.count) - XCTAssertEqual([bookClubThread], threads) - } - - func testSearchContactByNumber() { - var threads: [ThreadViewModel] = [] - - // No match - threads = searchConversations(searchText: "+5551239999") - XCTAssertEqual(0, threads.count) - - // Exact match - threads = searchConversations(searchText: aliceRecipientId) - XCTAssertEqual(3, threads.count) - XCTAssertEqual([bookClubThread, aliceThread, snackClubThread], threads) - - // Partial match - threads = searchConversations(searchText: "+123456") - XCTAssertEqual(3, threads.count) - XCTAssertEqual([bookClubThread, aliceThread, snackClubThread], threads) - - // Prefixes - threads = searchConversations(searchText: "12345678900") - XCTAssertEqual(3, threads.count) - XCTAssertEqual([bookClubThread, aliceThread, snackClubThread], threads) - - threads = searchConversations(searchText: "49") - XCTAssertEqual(1, threads.count) - XCTAssertEqual([bookClubThread], threads) - - threads = searchConversations(searchText: "1-234-56") - XCTAssertEqual(3, threads.count) - XCTAssertEqual([bookClubThread, aliceThread, snackClubThread], threads) - - threads = searchConversations(searchText: "123456") - XCTAssertEqual(3, threads.count) - XCTAssertEqual([bookClubThread, aliceThread, snackClubThread], threads) - - threads = searchConversations(searchText: "1.234.56") - XCTAssertEqual(3, threads.count) - XCTAssertEqual([bookClubThread, aliceThread, snackClubThread], threads) - - threads = searchConversations(searchText: "1 234 56") - XCTAssertEqual(3, threads.count) - XCTAssertEqual([bookClubThread, aliceThread, snackClubThread], threads) - } - - func testSearchContactByNumberWithoutCountryCode() { - var threads: [ThreadViewModel] = [] - // Phone Number formatting should be forgiving - threads = searchConversations(searchText: "234.56") - XCTAssertEqual(3, threads.count) - XCTAssertEqual([bookClubThread, aliceThread, snackClubThread], threads) - - threads = searchConversations(searchText: "234 56") - XCTAssertEqual(3, threads.count) - XCTAssertEqual([bookClubThread, aliceThread, snackClubThread], threads) - } - - func testSearchConversationByContactByName() { - var threads: [ThreadViewModel] = [] - - threads = searchConversations(searchText: "Alice") - XCTAssertEqual(3, threads.count) - XCTAssertEqual([bookClubThread, aliceThread, snackClubThread], threads) - - threads = searchConversations(searchText: "Bob") - XCTAssertEqual(1, threads.count) - XCTAssertEqual([bookClubThread], threads) - - threads = searchConversations(searchText: "Barker") - XCTAssertEqual(1, threads.count) - XCTAssertEqual([bookClubThread], threads) - - threads = searchConversations(searchText: "Bob B") - XCTAssertEqual(1, threads.count) - XCTAssertEqual([bookClubThread], threads) - } - - func testSearchMessageByBodyContent() { - var resultSet: HomeScreenSearchResultSet = .empty - - resultSet = getResultSet(searchText: "Hello Alice") - XCTAssertEqual(1, resultSet.messages.count) - XCTAssertEqual(aliceThread, resultSet.messages.first?.thread) - - resultSet = getResultSet(searchText: "Hello") - XCTAssertEqual(2, resultSet.messages.count) - XCTAssert(resultSet.messages.map { $0.thread }.contains(aliceThread)) - XCTAssert(resultSet.messages.map { $0.thread }.contains(bookClubThread)) - } - - func testSearchEdgeCases() { - var resultSet: HomeScreenSearchResultSet = .empty - - resultSet = getResultSet(searchText: "Hello Alice") - XCTAssertEqual(1, resultSet.messages.count) - XCTAssertEqual(["Hello Alice"], bodies(forMessageResults: resultSet.messages)) - - resultSet = getResultSet(searchText: "hello alice") - XCTAssertEqual(1, resultSet.messages.count) - XCTAssertEqual(["Hello Alice"], bodies(forMessageResults: resultSet.messages)) - - resultSet = getResultSet(searchText: "Hel") - XCTAssertEqual(2, resultSet.messages.count) - XCTAssertEqual(["Hello Alice", "Hello Book Club"], bodies(forMessageResults: resultSet.messages)) - - resultSet = getResultSet(searchText: "Hel Ali") - XCTAssertEqual(1, resultSet.messages.count) - XCTAssertEqual(["Hello Alice"], bodies(forMessageResults: resultSet.messages)) - - resultSet = getResultSet(searchText: "Hel Ali Alic") - XCTAssertEqual(1, resultSet.messages.count) - XCTAssertEqual(["Hello Alice"], bodies(forMessageResults: resultSet.messages)) - - resultSet = getResultSet(searchText: "Ali Hel") - XCTAssertEqual(1, resultSet.messages.count) - XCTAssertEqual(["Hello Alice"], bodies(forMessageResults: resultSet.messages)) - - resultSet = getResultSet(searchText: "CLU") - XCTAssertEqual(2, resultSet.messages.count) - XCTAssertEqual(["Goodbye Book Club", "Hello Book Club"], bodies(forMessageResults: resultSet.messages)) - - resultSet = getResultSet(searchText: "hello !@##!@#!$^@!@#! alice") - XCTAssertEqual(1, resultSet.messages.count) - XCTAssertEqual(["Hello Alice"], bodies(forMessageResults: resultSet.messages)) - - resultSet = getResultSet(searchText: "3213 phone") - XCTAssertEqual(1, resultSet.messages.count) - XCTAssertEqual(["My phone number is: 321-321-4321"], bodies(forMessageResults: resultSet.messages)) - - resultSet = getResultSet(searchText: "PHO 3213") - XCTAssertEqual(1, resultSet.messages.count) - XCTAssertEqual(["My phone number is: 321-321-4321"], bodies(forMessageResults: resultSet.messages)) - - resultSet = getResultSet(searchText: "fax") - XCTAssertEqual(1, resultSet.messages.count) - XCTAssertEqual(["My fax is: 222-333-4444"], bodies(forMessageResults: resultSet.messages)) - - resultSet = getResultSet(searchText: "fax 2223") - XCTAssertEqual(1, resultSet.messages.count) - XCTAssertEqual(["My fax is: 222-333-4444"], bodies(forMessageResults: resultSet.messages)) - } - - // MARK: Helpers - - func bodies(forMessageResults messageResults: [ConversationSearchResult]) -> [String] { - var result = [String]() - - self.dbConnection.read { transaction in - for messageResult in messageResults { - guard let messageId = messageResult.messageId else { - owsFailDebug("message result missing message id") - continue - } - guard let interaction = TSInteraction.fetch(uniqueId: messageId, transaction: transaction) else { - owsFailDebug("couldn't load interaction for message result") - continue - } - guard let message = interaction as? TSMessage else { - owsFailDebug("invalid message for message result") - continue - } - guard let messageBody = message.body else { - owsFailDebug("message result missing message body") - continue - } - result.append(messageBody) - } - } - - return result.sorted() - } - - private func searchConversations(searchText: String) -> [ThreadViewModel] { - let results = getResultSet(searchText: searchText) - return results.conversations.map { $0.thread } - } - - private func getResultSet(searchText: String) -> HomeScreenSearchResultSet { - var results: HomeScreenSearchResultSet! - self.dbConnection.read { transaction in - results = self.searcher.searchForHomeScreen(searchText: searchText, transaction: transaction, contactsManager: SSKEnvironment.shared.contactsManager) - } - return results - } -} - -class SearcherTest: SignalBaseTest { - - struct TestCharacter { - let name: String - let description: String - let phoneNumber: String? - } - - let smerdyakov = TestCharacter(name: "Pavel Fyodorovich Smerdyakov", description: "A rusty hue in the sky", phoneNumber: nil) - let stinkingLizaveta = TestCharacter(name: "Stinking Lizaveta", description: "object of pity", phoneNumber: "+13235555555") - let regularLizaveta = TestCharacter(name: "Lizaveta", description: "", phoneNumber: "1 (415) 555-5555") - - let indexer = { (character: TestCharacter) in - return "\(character.name) \(character.description) \(character.phoneNumber ?? "")" - } - - var searcher: Searcher { - return Searcher(indexer: indexer) - } - - override func setUp() { - super.setUp() - // Put setup code here. This method is called before the invocation of each test method in the class. - } - - override func tearDown() { - // Put teardown code here. This method is called after the invocation of each test method in the class. - super.tearDown() - } - - func testSimple() { - XCTAssert(searcher.matches(item: smerdyakov, query: "Pavel")) - XCTAssert(searcher.matches(item: smerdyakov, query: "pavel")) - XCTAssertFalse(searcher.matches(item: smerdyakov, query: "asdf")) - XCTAssertFalse(searcher.matches(item: smerdyakov, query: "")) - XCTAssert(searcher.matches(item: stinkingLizaveta, query: "Pity")) - } - - func testRepeats() { - XCTAssert(searcher.matches(item: smerdyakov, query: "pavel pavel")) - XCTAssertFalse(searcher.matches(item: smerdyakov, query: "pavelpavel")) - } - - func testSplitWords() { - XCTAssert(searcher.matches(item: stinkingLizaveta, query: "Lizaveta")) - XCTAssert(searcher.matches(item: regularLizaveta, query: "Lizaveta")) - - XCTAssert(searcher.matches(item: stinkingLizaveta, query: "Stinking Lizaveta")) - XCTAssertFalse(searcher.matches(item: regularLizaveta, query: "Stinking Lizaveta")) - - XCTAssert(searcher.matches(item: stinkingLizaveta, query: "Lizaveta Stinking")) - XCTAssert(searcher.matches(item: stinkingLizaveta, query: "Lizaveta St")) - XCTAssert(searcher.matches(item: stinkingLizaveta, query: " Lizaveta St ")) - } - - func testFormattingChars() { - XCTAssert(searcher.matches(item: stinkingLizaveta, query: "323")) - XCTAssert(searcher.matches(item: stinkingLizaveta, query: "1-323-555-5555")) - XCTAssert(searcher.matches(item: stinkingLizaveta, query: "13235555555")) - XCTAssert(searcher.matches(item: stinkingLizaveta, query: "+1-323")) - XCTAssert(searcher.matches(item: stinkingLizaveta, query: "Liza +1-323")) - - // Sanity check, match both by names - XCTAssert(searcher.matches(item: stinkingLizaveta, query: "Liza")) - XCTAssert(searcher.matches(item: regularLizaveta, query: "Liza")) - - // Disambiguate the two Liza's by area code - XCTAssert(searcher.matches(item: stinkingLizaveta, query: "Liza 323")) - XCTAssertFalse(searcher.matches(item: regularLizaveta, query: "Liza 323")) - } - - func testSearchQuery() { - XCTAssertEqual(FullTextSearchFinder.query(searchText: "Liza"), "\"Liza\"*") - XCTAssertEqual(FullTextSearchFinder.query(searchText: "Liza +1-323"), "\"1323\"* \"Liza\"*") - XCTAssertEqual(FullTextSearchFinder.query(searchText: "\"\\ `~!@#$%^&*()_+-={}|[]:;'<>?,./Liza +1-323"), "\"1323\"* \"Liza\"*") - XCTAssertEqual(FullTextSearchFinder.query(searchText: "renaldo RENALDO reñaldo REÑALDO"), "\"RENALDO\"* \"REÑALDO\"* \"renaldo\"* \"reñaldo\"*") - XCTAssertEqual(FullTextSearchFinder.query(searchText: "😏"), "\"😏\"*") - XCTAssertEqual(FullTextSearchFinder.query(searchText: "alice 123 bob 456"), "\"123456\"* \"alice\"* \"bob\"*") - XCTAssertEqual(FullTextSearchFinder.query(searchText: "Li!za"), "\"Liza\"*") - XCTAssertEqual(FullTextSearchFinder.query(searchText: "Liza Liza"), "\"Liza\"*") - XCTAssertEqual(FullTextSearchFinder.query(searchText: "Liza liza"), "\"Liza\"* \"liza\"*") - } - - func testTextNormalization() { - XCTAssertEqual(FullTextSearchFinder.normalize(text: "Liza"), "Liza") - XCTAssertEqual(FullTextSearchFinder.normalize(text: "Liza +1-323"), "Liza 1323") - XCTAssertEqual(FullTextSearchFinder.normalize(text: "\"\\ `~!@#$%^&*()_+-={}|[]:;'<>?,./Liza +1-323"), "Liza 1323") - XCTAssertEqual(FullTextSearchFinder.normalize(text: "renaldo RENALDO reñaldo REÑALDO"), "renaldo RENALDO reñaldo REÑALDO") - XCTAssertEqual(FullTextSearchFinder.normalize(text: "😏"), "😏") - } - */ -} diff --git a/Session/test/util/StringAdditionsTest.swift b/Session/test/util/StringAdditionsTest.swift deleted file mode 100644 index 3118ee600..000000000 --- a/Session/test/util/StringAdditionsTest.swift +++ /dev/null @@ -1,126 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -import XCTest - -class StringAdditionsTest: SignalBaseTest { - - override func setUp() { - super.setUp() - // Put setup code here. This method is called before the invocation of each test method in the class. - } - - override func tearDown() { - // Put teardown code here. This method is called after the invocation of each test method in the class. - super.tearDown() - } - - func test_truncated_ASCII() { - let originalString = "Hello World" - - var truncatedString = originalString.truncated(toByteCount: 8) - XCTAssertEqual("Hello Wo", truncatedString) - - truncatedString = originalString.truncated(toByteCount: 0) - XCTAssertEqual("", truncatedString) - - truncatedString = originalString.truncated(toByteCount: 11) - XCTAssertEqual("Hello World", truncatedString) - - truncatedString = originalString.truncated(toByteCount: 12) - XCTAssertEqual("Hello World", truncatedString) - - truncatedString = originalString.truncated(toByteCount: 100) - XCTAssertEqual("Hello World", truncatedString) - } - - func test_truncated_MultiByte() { - let originalString = "🇨🇦🇨🇦🇨🇦🇨🇦" - - var truncatedString = originalString.truncated(toByteCount: 0) - XCTAssertEqual("", truncatedString) - - truncatedString = originalString.truncated(toByteCount: 1) - XCTAssertEqual("", truncatedString) - - truncatedString = originalString.truncated(toByteCount: 7) - XCTAssertEqual("", truncatedString) - - truncatedString = originalString.truncated(toByteCount: 8) - XCTAssertEqual("🇨🇦", truncatedString) - - truncatedString = originalString.truncated(toByteCount: 9) - XCTAssertEqual("🇨🇦", truncatedString) - - truncatedString = originalString.truncated(toByteCount: 15) - XCTAssertEqual("🇨🇦", truncatedString) - - truncatedString = originalString.truncated(toByteCount: 16) - XCTAssertEqual("🇨🇦🇨🇦", truncatedString) - - truncatedString = originalString.truncated(toByteCount: 17) - XCTAssertEqual("🇨🇦🇨🇦", truncatedString) - } - - func test_truncated_Mixed() { - let originalString = "Oh🇨🇦Canada🇨🇦" - - var truncatedString = originalString.truncated(toByteCount: 0) - XCTAssertEqual("", truncatedString) - - truncatedString = originalString.truncated(toByteCount: 1) - XCTAssertEqual("O", truncatedString) - - truncatedString = originalString.truncated(toByteCount: 7) - XCTAssertEqual("Oh", truncatedString) - - truncatedString = originalString.truncated(toByteCount: 9) - XCTAssertEqual("Oh", truncatedString) - - truncatedString = originalString.truncated(toByteCount: 10) - XCTAssertEqual("Oh🇨🇦", truncatedString) - - truncatedString = originalString.truncated(toByteCount: 11) - XCTAssertEqual("Oh🇨🇦C", truncatedString) - - truncatedString = originalString.truncated(toByteCount: 23) - XCTAssertEqual("Oh🇨🇦Canada", truncatedString) - - truncatedString = originalString.truncated(toByteCount: 24) - XCTAssertEqual("Oh🇨🇦Canada🇨🇦", truncatedString) - - truncatedString = originalString.truncated(toByteCount: 25) - XCTAssertEqual("Oh🇨🇦Canada🇨🇦", truncatedString) - - truncatedString = originalString.truncated(toByteCount: 100) - XCTAssertEqual("Oh🇨🇦Canada🇨🇦", truncatedString) - } - - func test_caesar() { - XCTAssertEqual("abc", try! "abc".caesar(shift: 0)) - XCTAssertEqual("abc", try! "abc".caesar(shift: 127)) - - XCTAssertEqual("bcd", try! "abc".caesar(shift: 1)) - XCTAssertEqual("bcd", try! "abc".caesar(shift: 128)) - - XCTAssertEqual("z{b", try! "yza".caesar(shift: 1)) - XCTAssertEqual("|}d", try! "yza".caesar(shift: 3)) - XCTAssertEqual("ef=g", try! "bc:d".caesar(shift: 3)) - - let shifted = try! "abc".caesar(shift: 32) - let roundTrip = try! shifted.caesar(shift: 127 - 32) - XCTAssertEqual("abc", roundTrip) - } - - func test_encodedForSelector() { - XCTAssertEqual("cnN0", "abc".encodedForSelector) - XCTAssertEqual("abc", "abc".encodedForSelector!.decodedForSelector) - - XCTAssertNotEqual("abcWithFoo:bar:", "abcWithFoo:bar:".encodedForSelector) - XCTAssertEqual("abcWithFoo:bar:", "abcWithFoo:bar:".encodedForSelector!.decodedForSelector) - - XCTAssertNotEqual("abcWithFoo:bar:zaz1:", "abcWithFoo:bar:zaz1:".encodedForSelector) - XCTAssertEqual("abcWithFoo:bar:zaz1:", "abcWithFoo:bar:zaz1:".encodedForSelector!.decodedForSelector) - } -} diff --git a/Session/test/util/TSStorageIdentityKeyStoreTests.m b/Session/test/util/TSStorageIdentityKeyStoreTests.m deleted file mode 100644 index 6a182db81..000000000 --- a/Session/test/util/TSStorageIdentityKeyStoreTests.m +++ /dev/null @@ -1,95 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "OWSIdentityManager.h" -#import "OWSPrimaryStorage.h" -#import "OWSRecipientIdentity.h" -#import "OWSUnitTestEnvironment.h" -#import "SSKBaseTest.h" -#import "SSKEnvironment.h" -#import "SecurityUtils.h" -#import - -@interface TSStorageIdentityKeyStoreTests : SSKBaseTest - -@end - -@implementation TSStorageIdentityKeyStoreTests - -- (void)setUp -{ - [super setUp]; - - [[OWSPrimaryStorage sharedManager] purgeCollection:OWSPrimaryStorageTrustedKeysCollection]; - [OWSRecipientIdentity removeAllObjectsInCollection]; -} - -- (void)tearDown -{ - // Put teardown code here. This method is called after the invocation of each test method in the class. - [super tearDown]; -} - -- (void)testNewEmptyKey -{ - NSData *newKey = [SecurityUtils generateRandomBytes:32]; - NSString *recipientId = @"test@gmail.com"; - - XCTAssert([[OWSIdentityManager sharedManager] isTrustedIdentityKey:newKey - recipientId:recipientId - direction:TSMessageDirectionOutgoing]); - XCTAssert([[OWSIdentityManager sharedManager] isTrustedIdentityKey:newKey - recipientId:recipientId - direction:TSMessageDirectionIncoming]); -} - -- (void)testAlreadyRegisteredKey -{ - NSData *newKey = [SecurityUtils generateRandomBytes:32]; - NSString *recipientId = @"test@gmail.com"; - - [[OWSIdentityManager sharedManager] saveRemoteIdentity:newKey recipientId:recipientId]; - - XCTAssert([[OWSIdentityManager sharedManager] isTrustedIdentityKey:newKey - recipientId:recipientId - direction:TSMessageDirectionOutgoing]); - XCTAssert([[OWSIdentityManager sharedManager] isTrustedIdentityKey:newKey - recipientId:recipientId - direction:TSMessageDirectionIncoming]); -} - - -- (void)testChangedKey -{ - NSData *originalKey = [SecurityUtils generateRandomBytes:32]; - NSString *recipientId = @"test@protonmail.com"; - - [[OWSIdentityManager sharedManager] saveRemoteIdentity:originalKey recipientId:recipientId]; - - XCTAssert([[OWSIdentityManager sharedManager] isTrustedIdentityKey:originalKey - recipientId:recipientId - direction:TSMessageDirectionOutgoing]); - XCTAssert([[OWSIdentityManager sharedManager] isTrustedIdentityKey:originalKey - recipientId:recipientId - direction:TSMessageDirectionIncoming]); - - NSData *otherKey = [SecurityUtils generateRandomBytes:32]; - - XCTAssertFalse([[OWSIdentityManager sharedManager] isTrustedIdentityKey:otherKey - recipientId:recipientId - direction:TSMessageDirectionOutgoing]); - XCTAssert([[OWSIdentityManager sharedManager] isTrustedIdentityKey:otherKey - recipientId:recipientId - direction:TSMessageDirectionIncoming]); -} - - -- (void)testIdentityKey -{ - [[OWSIdentityManager sharedManager] generateNewIdentityKey]; - - XCTAssert([[[OWSIdentityManager sharedManager] identityKeyPair].publicKey length] == 32); -} - -@end diff --git a/Session/test/util/TSStoragePreKeyStoreTests.m b/Session/test/util/TSStoragePreKeyStoreTests.m deleted file mode 100644 index ec4243691..000000000 --- a/Session/test/util/TSStoragePreKeyStoreTests.m +++ /dev/null @@ -1,63 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "OWSPrimaryStorage+PreKeyStore.h" -#import "SSKBaseTest.h" - -@interface TSStoragePreKeyStoreTests : SSKBaseTest - -@end - -@implementation TSStoragePreKeyStoreTests - -- (void)setUp -{ - [super setUp]; - // Put setup code here. This method is called before the invocation of each test method in the class. -} - -- (void)tearDown -{ - // Put teardown code here. This method is called after the invocation of each test method in the class. - [super tearDown]; -} - -- (void)testGeneratingAndStoringPreKeys -{ - NSArray *generatedKeys = [[OWSPrimaryStorage sharedManager] generatePreKeyRecords]; - - - XCTAssert([generatedKeys count] == 100, @"Not hundred keys generated"); - - [[OWSPrimaryStorage sharedManager] storePreKeyRecords:generatedKeys]; - - PreKeyRecord *lastPreKeyRecord = [generatedKeys lastObject]; - PreKeyRecord *firstPreKeyRecord = [generatedKeys firstObject]; - - XCTAssert([[[OWSPrimaryStorage sharedManager] loadPreKey:lastPreKeyRecord.Id].keyPair.publicKey - isEqualToData:lastPreKeyRecord.keyPair.publicKey]); - - XCTAssert([[[OWSPrimaryStorage sharedManager] loadPreKey:firstPreKeyRecord.Id].keyPair.publicKey - isEqualToData:firstPreKeyRecord.keyPair.publicKey]); -} - - -- (void)testRemovingPreKeys -{ - NSArray *generatedKeys = [[OWSPrimaryStorage sharedManager] generatePreKeyRecords]; - - XCTAssert([generatedKeys count] == 100, @"Not hundred keys generated"); - - [[OWSPrimaryStorage sharedManager] storePreKeyRecords:generatedKeys]; - - PreKeyRecord *lastPreKeyRecord = [generatedKeys lastObject]; - PreKeyRecord *firstPreKeyRecord = [generatedKeys firstObject]; - - [[OWSPrimaryStorage sharedManager] removePreKey:lastPreKeyRecord.Id]; - - XCTAssertThrows([[OWSPrimaryStorage sharedManager] loadPreKey:lastPreKeyRecord.Id]); - XCTAssertNoThrow([[OWSPrimaryStorage sharedManager] loadPreKey:firstPreKeyRecord.Id]); -} - -@end diff --git a/Session/test/util/TSStorageSignedPreKeyStore.m b/Session/test/util/TSStorageSignedPreKeyStore.m deleted file mode 100644 index d436be932..000000000 --- a/Session/test/util/TSStorageSignedPreKeyStore.m +++ /dev/null @@ -1,25 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "SSKBaseTest.h" - -@interface TSStorageSignedPreKeyStore : SSKBaseTest - -@end - -@implementation TSStorageSignedPreKeyStore - -- (void)setUp -{ - [super setUp]; - // Put setup code here. This method is called before the invocation of each test method in the class. -} - -- (void)tearDown -{ - // Put teardown code here. This method is called after the invocation of each test method in the class. - [super tearDown]; -} - -@end diff --git a/Session/test/util/UtilTest.h b/Session/test/util/UtilTest.h deleted file mode 100644 index 97e23ad65..000000000 --- a/Session/test/util/UtilTest.h +++ /dev/null @@ -1,9 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "SignalBaseTest.h" - -@interface UtilTest : SignalBaseTest - -@end diff --git a/Session/test/util/UtilTest.m b/Session/test/util/UtilTest.m deleted file mode 100644 index 95ad7f520..000000000 --- a/Session/test/util/UtilTest.m +++ /dev/null @@ -1,276 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "UtilTest.h" -#import "DateUtil.h" -#import "TestUtil.h" -#import -#import -#import - -@interface DateUtil (Test) - -+ (BOOL)dateIsOlderThanToday:(NSDate *)date now:(NSDate *)now; -+ (BOOL)dateIsOlderThanOneWeek:(NSDate *)date now:(NSDate *)now; -+ (BOOL)dateIsToday:(NSDate *)date now:(NSDate *)now; -+ (BOOL)dateIsThisYear:(NSDate *)date now:(NSDate *)now; -+ (BOOL)dateIsYesterday:(NSDate *)date now:(NSDate *)now; - -@end - -#pragma mark - - -@interface NSString (OWS_Test) - -- (NSString *)removeAllCharactersIn:(NSCharacterSet *)characterSet; - -- (NSString *)filterUnsafeFilenameCharacters; - -@end - -#pragma mark - - -@implementation UtilTest - --(void) testRemoveAllCharactersIn { - - test([[@"" removeAllCharactersIn:NSCharacterSet.letterCharacterSet] isEqual:@""]); - test([[@"1" removeAllCharactersIn:NSCharacterSet.letterCharacterSet] isEqual:@"1"]); - test([[@"a" removeAllCharactersIn:NSCharacterSet.letterCharacterSet] isEqual:@""]); - test([[@"A" removeAllCharactersIn:NSCharacterSet.letterCharacterSet] isEqual:@""]); - test([[@"abc123%^&" removeAllCharactersIn:NSCharacterSet.letterCharacterSet] isEqual:@"123%^&"]); - - test([[@"" removeAllCharactersIn:NSCharacterSet.decimalDigitCharacterSet] isEqual:@""]); - test([[@"1" removeAllCharactersIn:NSCharacterSet.decimalDigitCharacterSet] isEqual:@""]); - test([[@"a" removeAllCharactersIn:NSCharacterSet.decimalDigitCharacterSet] isEqual:@"a"]); - test([[@"A" removeAllCharactersIn:NSCharacterSet.decimalDigitCharacterSet] isEqual:@"A"]); - test([[@"abc123%^&" removeAllCharactersIn:NSCharacterSet.decimalDigitCharacterSet] isEqual:@"abc%^&"]); -} - --(void) testDigitsOnly { - test([@"".digitsOnly isEqual:@""]); - test([@"1".digitsOnly isEqual:@"1"]); - test([@"a".digitsOnly isEqual:@""]); - test([@"(555) 235-7111".digitsOnly isEqual:@"5552357111"]); -} - -- (void)testfilterUnsafeFilenameCharacters -{ - XCTAssertEqualObjects(@"1".filterUnsafeFilenameCharacters, @"1"); - XCTAssertEqualObjects(@"alice\u202Dbob".filterUnsafeFilenameCharacters, @"alice\uFFFDbob"); - XCTAssertEqualObjects(@"\u202Dalicebob".filterUnsafeFilenameCharacters, @"\uFFFDalicebob"); - XCTAssertEqualObjects(@"alicebob\u202D".filterUnsafeFilenameCharacters, @"alicebob\uFFFD"); - XCTAssertEqualObjects(@"alice\u202Ebob".filterUnsafeFilenameCharacters, @"alice\uFFFDbob"); - XCTAssertEqualObjects(@"\u202Ealicebob".filterUnsafeFilenameCharacters, @"\uFFFDalicebob"); - XCTAssertEqualObjects(@"alicebob\u202E".filterUnsafeFilenameCharacters, @"alicebob\uFFFD"); - XCTAssertEqualObjects(@"alice\u202Dbobalice\u202Ebob".filterUnsafeFilenameCharacters, @"alice\uFFFDbobalice\uFFFDbob"); -} - -- (void)testDateComparison -{ - NSDate *firstDate = [NSDate new]; - - NSDate *sameDate = [NSDate dateWithTimeIntervalSinceReferenceDate:firstDate.timeIntervalSinceReferenceDate]; - NSDate *laterDate = [NSDate dateWithTimeIntervalSinceReferenceDate:firstDate.timeIntervalSinceReferenceDate + 1.f]; - - XCTAssertEqual(firstDate.timeIntervalSinceReferenceDate, sameDate.timeIntervalSinceReferenceDate); - XCTAssertNotEqual(firstDate.timeIntervalSinceReferenceDate, laterDate.timeIntervalSinceReferenceDate); - XCTAssertEqualObjects(firstDate, sameDate); - XCTAssertNotEqualObjects(firstDate, laterDate); - XCTAssertTrue(firstDate.timeIntervalSinceReferenceDate < laterDate.timeIntervalSinceReferenceDate); - XCTAssertFalse([firstDate isBeforeDate:sameDate]); - XCTAssertTrue([firstDate isBeforeDate:laterDate]); - XCTAssertFalse([laterDate isBeforeDate:firstDate]); - XCTAssertFalse([firstDate isAfterDate:sameDate]); - XCTAssertFalse([firstDate isAfterDate:laterDate]); - XCTAssertTrue([laterDate isAfterDate:firstDate]); -} - -- (void)testDateComparators -{ - // Use a specific reference date to make this test deterministic, - // and to avoid failing around midnight, new year's, etc. - NSDateComponents *nowDateComponents = [NSDateComponents new]; - nowDateComponents.year = 2015; - nowDateComponents.month = 8; - nowDateComponents.day = 31; - nowDateComponents.hour = 8; - NSDate *now = [[NSCalendar currentCalendar] dateFromComponents:nowDateComponents]; - - NSDateFormatter *formatter = [NSDateFormatter new]; - formatter.dateStyle = NSDateFormatterLongStyle; - formatter.timeStyle = NSDateFormatterLongStyle; - OWSLogInfo(@"now: %@", [formatter stringFromDate:now]); - - NSDate *oneSecondAgo = - [NSDate dateWithTimeIntervalSinceReferenceDate:[now timeIntervalSinceReferenceDate] - kSecondInterval]; - NSDate *oneMinuteAgo = - [NSDate dateWithTimeIntervalSinceReferenceDate:[now timeIntervalSinceReferenceDate] - kMinuteInterval]; - NSDate *oneDayAgo = - [NSDate dateWithTimeIntervalSinceReferenceDate:[now timeIntervalSinceReferenceDate] - kDayInterval]; - NSDate *threeDaysAgo = - [NSDate dateWithTimeIntervalSinceReferenceDate:[now timeIntervalSinceReferenceDate] - kDayInterval * 3]; - NSDate *tenDaysAgo = - [NSDate dateWithTimeIntervalSinceReferenceDate:[now timeIntervalSinceReferenceDate] - kDayInterval * 10]; - NSDate *oneYearAgo = - [NSDate dateWithTimeIntervalSinceReferenceDate:[now timeIntervalSinceReferenceDate] - kYearInterval]; - NSDate *twoYearsAgo = - [NSDate dateWithTimeIntervalSinceReferenceDate:[now timeIntervalSinceReferenceDate] - kYearInterval * 2]; - - NSDate *oneSecondAhead = - [NSDate dateWithTimeIntervalSinceReferenceDate:[now timeIntervalSinceReferenceDate] + kSecondInterval]; - NSDate *oneMinuteAhead = - [NSDate dateWithTimeIntervalSinceReferenceDate:[now timeIntervalSinceReferenceDate] + kMinuteInterval]; - NSDate *oneDayAhead = - [NSDate dateWithTimeIntervalSinceReferenceDate:[now timeIntervalSinceReferenceDate] + kDayInterval]; - NSDate *threeDaysAhead = - [NSDate dateWithTimeIntervalSinceReferenceDate:[now timeIntervalSinceReferenceDate] + kDayInterval * 3]; - NSDate *tenDaysAhead = - [NSDate dateWithTimeIntervalSinceReferenceDate:[now timeIntervalSinceReferenceDate] + kDayInterval * 10]; - NSDate *oneYearAhead = - [NSDate dateWithTimeIntervalSinceReferenceDate:[now timeIntervalSinceReferenceDate] + kYearInterval]; - NSDate *twoYearsAhead = - [NSDate dateWithTimeIntervalSinceReferenceDate:[now timeIntervalSinceReferenceDate] + kYearInterval * 2]; - - OWSLogInfo(@"oneSecondAgo: %@", [formatter stringFromDate:oneSecondAgo]); - - XCTAssertTrue([DateUtil dateIsToday:oneSecondAgo now:now]); - XCTAssertTrue([DateUtil dateIsToday:oneMinuteAgo now:now]); - XCTAssertFalse([DateUtil dateIsToday:oneDayAgo now:now]); - XCTAssertFalse([DateUtil dateIsToday:threeDaysAgo now:now]); - XCTAssertFalse([DateUtil dateIsToday:tenDaysAgo now:now]); - XCTAssertFalse([DateUtil dateIsToday:oneYearAgo now:now]); - XCTAssertFalse([DateUtil dateIsToday:twoYearsAgo now:now]); - - XCTAssertTrue([DateUtil dateIsToday:oneSecondAhead now:now]); - XCTAssertTrue([DateUtil dateIsToday:oneMinuteAhead now:now]); - XCTAssertFalse([DateUtil dateIsToday:oneDayAhead now:now]); - XCTAssertFalse([DateUtil dateIsToday:threeDaysAhead now:now]); - XCTAssertFalse([DateUtil dateIsToday:tenDaysAhead now:now]); - XCTAssertFalse([DateUtil dateIsToday:oneYearAhead now:now]); - XCTAssertFalse([DateUtil dateIsToday:twoYearsAhead now:now]); - - XCTAssertFalse([DateUtil dateIsYesterday:oneSecondAgo now:now]); - XCTAssertFalse([DateUtil dateIsYesterday:oneMinuteAgo now:now]); - XCTAssertTrue([DateUtil dateIsYesterday:oneDayAgo now:now]); - XCTAssertFalse([DateUtil dateIsYesterday:threeDaysAgo now:now]); - XCTAssertFalse([DateUtil dateIsYesterday:tenDaysAgo now:now]); - XCTAssertFalse([DateUtil dateIsYesterday:oneYearAgo now:now]); - XCTAssertFalse([DateUtil dateIsYesterday:twoYearsAgo now:now]); - - XCTAssertFalse([DateUtil dateIsYesterday:oneSecondAhead now:now]); - XCTAssertFalse([DateUtil dateIsYesterday:oneMinuteAhead now:now]); - XCTAssertFalse([DateUtil dateIsYesterday:oneDayAhead now:now]); - XCTAssertFalse([DateUtil dateIsYesterday:threeDaysAhead now:now]); - XCTAssertFalse([DateUtil dateIsYesterday:tenDaysAhead now:now]); - XCTAssertFalse([DateUtil dateIsYesterday:oneYearAhead now:now]); - XCTAssertFalse([DateUtil dateIsYesterday:twoYearsAhead now:now]); - - XCTAssertFalse([DateUtil dateIsOlderThanToday:oneSecondAgo now:now]); - XCTAssertFalse([DateUtil dateIsOlderThanToday:oneMinuteAgo now:now]); - XCTAssertTrue([DateUtil dateIsOlderThanToday:oneDayAgo now:now]); - XCTAssertTrue([DateUtil dateIsOlderThanToday:threeDaysAgo now:now]); - XCTAssertTrue([DateUtil dateIsOlderThanToday:tenDaysAgo now:now]); - XCTAssertTrue([DateUtil dateIsOlderThanToday:oneYearAgo now:now]); - XCTAssertTrue([DateUtil dateIsOlderThanToday:twoYearsAgo now:now]); - - XCTAssertFalse([DateUtil dateIsOlderThanToday:oneSecondAhead now:now]); - XCTAssertFalse([DateUtil dateIsOlderThanToday:oneMinuteAhead now:now]); - XCTAssertFalse([DateUtil dateIsOlderThanToday:oneDayAhead now:now]); - XCTAssertFalse([DateUtil dateIsOlderThanToday:threeDaysAhead now:now]); - XCTAssertFalse([DateUtil dateIsOlderThanToday:tenDaysAhead now:now]); - XCTAssertFalse([DateUtil dateIsOlderThanToday:oneYearAhead now:now]); - XCTAssertFalse([DateUtil dateIsOlderThanToday:twoYearsAhead now:now]); - - XCTAssertFalse([DateUtil dateIsOlderThanOneWeek:oneSecondAgo now:now]); - XCTAssertFalse([DateUtil dateIsOlderThanOneWeek:oneMinuteAgo now:now]); - XCTAssertFalse([DateUtil dateIsOlderThanOneWeek:oneDayAgo now:now]); - XCTAssertFalse([DateUtil dateIsOlderThanOneWeek:threeDaysAgo now:now]); - XCTAssertTrue([DateUtil dateIsOlderThanOneWeek:tenDaysAgo now:now]); - XCTAssertTrue([DateUtil dateIsOlderThanOneWeek:oneYearAgo now:now]); - XCTAssertTrue([DateUtil dateIsOlderThanOneWeek:twoYearsAgo now:now]); - - XCTAssertFalse([DateUtil dateIsOlderThanOneWeek:oneSecondAhead now:now]); - XCTAssertFalse([DateUtil dateIsOlderThanOneWeek:oneMinuteAhead now:now]); - XCTAssertFalse([DateUtil dateIsOlderThanOneWeek:oneDayAhead now:now]); - XCTAssertFalse([DateUtil dateIsOlderThanOneWeek:threeDaysAhead now:now]); - XCTAssertFalse([DateUtil dateIsOlderThanOneWeek:tenDaysAhead now:now]); - XCTAssertFalse([DateUtil dateIsOlderThanOneWeek:oneYearAhead now:now]); - XCTAssertFalse([DateUtil dateIsOlderThanOneWeek:twoYearsAhead now:now]); - - XCTAssertTrue([DateUtil dateIsThisYear:oneSecondAgo now:now]); - XCTAssertTrue([DateUtil dateIsThisYear:oneMinuteAgo now:now]); - XCTAssertTrue([DateUtil dateIsThisYear:oneDayAgo now:now]); - XCTAssertFalse([DateUtil dateIsThisYear:oneYearAgo now:now]); - XCTAssertFalse([DateUtil dateIsThisYear:twoYearsAgo now:now]); - - XCTAssertTrue([DateUtil dateIsThisYear:oneSecondAhead now:now]); - XCTAssertTrue([DateUtil dateIsThisYear:oneMinuteAhead now:now]); - XCTAssertTrue([DateUtil dateIsThisYear:oneDayAhead now:now]); - XCTAssertFalse([DateUtil dateIsThisYear:oneYearAhead now:now]); - XCTAssertFalse([DateUtil dateIsThisYear:twoYearsAhead now:now]); -} - -- (NSDate *)dateWithYear:(NSInteger)year - month:(NSInteger)month - day:(NSInteger)day - hour:(NSInteger)hour - minute:(NSInteger)minute -{ - NSDateComponents *components = [NSDateComponents new]; - components.year = year; - components.month = month; - components.day = day; - components.hour = hour; - components.minute = minute; - return [[NSCalendar currentCalendar] dateFromComponents:components]; -} - -- (void)testDateComparators_timezoneVMidnight -{ - NSDateFormatter *formatter = [NSDateFormatter new]; - formatter.dateStyle = NSDateFormatterLongStyle; - formatter.timeStyle = NSDateFormatterLongStyle; - - NSDate *yesterdayBeforeMidnight = [self dateWithYear:2015 month:8 day:10 hour:23 minute:55]; - OWSLogInfo(@"yesterdayBeforeMidnight: %@", [formatter stringFromDate:yesterdayBeforeMidnight]); - - NSDate *todayAfterMidnight = [self dateWithYear:2015 month:8 day:11 hour:0 minute:5]; - OWSLogInfo(@"todayAfterMidnight: %@", [formatter stringFromDate:todayAfterMidnight]); - - NSDate *todayNoon = [self dateWithYear:2015 month:8 day:11 hour:12 minute:0]; - OWSLogInfo(@"todayNoon: %@", [formatter stringFromDate:todayNoon]); - - // Before Midnight, after Midnight. - XCTAssertFalse([DateUtil dateIsToday:yesterdayBeforeMidnight now:todayAfterMidnight]); - XCTAssertTrue([DateUtil dateIsYesterday:yesterdayBeforeMidnight now:todayAfterMidnight]); - XCTAssertTrue([DateUtil dateIsOlderThanToday:yesterdayBeforeMidnight now:todayAfterMidnight]); - XCTAssertFalse([DateUtil dateIsOlderThanOneWeek:yesterdayBeforeMidnight now:todayAfterMidnight]); - XCTAssertTrue([DateUtil dateIsThisYear:yesterdayBeforeMidnight now:todayAfterMidnight]); - - // Before Midnight, noon. - XCTAssertFalse([DateUtil dateIsToday:yesterdayBeforeMidnight now:todayNoon]); - XCTAssertTrue([DateUtil dateIsYesterday:yesterdayBeforeMidnight now:todayNoon]); - XCTAssertTrue([DateUtil dateIsOlderThanToday:yesterdayBeforeMidnight now:todayNoon]); - XCTAssertFalse([DateUtil dateIsOlderThanOneWeek:yesterdayBeforeMidnight now:todayNoon]); - XCTAssertTrue([DateUtil dateIsThisYear:yesterdayBeforeMidnight now:todayNoon]); - - // After Midnight, noon. - XCTAssertTrue([DateUtil dateIsToday:todayAfterMidnight now:todayNoon]); - XCTAssertFalse([DateUtil dateIsYesterday:todayAfterMidnight now:todayNoon]); - XCTAssertFalse([DateUtil dateIsOlderThanToday:todayAfterMidnight now:todayNoon]); - XCTAssertFalse([DateUtil dateIsOlderThanOneWeek:todayAfterMidnight now:todayNoon]); - XCTAssertTrue([DateUtil dateIsThisYear:todayAfterMidnight now:todayNoon]); -} - -- (void)testObjectComparison -{ - XCTAssertTrue([NSObject isNullableObject:nil equalTo:nil]); - XCTAssertFalse([NSObject isNullableObject:@(YES) equalTo:nil]); - XCTAssertFalse([NSObject isNullableObject:nil equalTo:@(YES)]); - XCTAssertFalse([NSObject isNullableObject:@(YES) equalTo:@(NO)]); - XCTAssertTrue([NSObject isNullableObject:@(YES) equalTo:@(YES)]); -} - -@end diff --git a/Session/test/views/ImageEditor/ImageEditorModelTest.swift b/Session/test/views/ImageEditor/ImageEditorModelTest.swift deleted file mode 100644 index 9fbfe9ec9..000000000 --- a/Session/test/views/ImageEditor/ImageEditorModelTest.swift +++ /dev/null @@ -1,83 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -import XCTest -@testable import Session -@testable import SignalUtilitiesKit - -class ImageEditorModelTest: SignalBaseTest { - - func testImageEditorTransform0() { - let imageSizePixels = CGSize(width: 200, height: 300) - let outputSizePixels = CGSize(width: 200, height: 300) - let unitTranslation = CGPoint.zero - let rotationRadians: CGFloat = 0 - let scaling: CGFloat = 1 - let transform = ImageEditorTransform(outputSizePixels: outputSizePixels, unitTranslation: unitTranslation, rotationRadians: rotationRadians, scaling: scaling, isFlipped: false) - - let viewSize = outputSizePixels - let imageFrame = ImageEditorCanvasView.imageFrame(forViewSize: viewSize, imageSize: imageSizePixels, transform: transform) - let affineTransform = transform.affineTransform(viewSize: viewSize) - - XCTAssertEqual(0.0, imageFrame.topLeft.applying(affineTransform).x, accuracy: 0.1) - XCTAssertEqual(0.0, imageFrame.topLeft.applying(affineTransform).y, accuracy: 0.1) - XCTAssertEqual(100.0, imageFrame.center.applying(affineTransform).x, accuracy: 0.1) - XCTAssertEqual(150.0, imageFrame.center.applying(affineTransform).y, accuracy: 0.1) - XCTAssertEqual(200.0, imageFrame.bottomRight.applying(affineTransform).x, accuracy: 0.1) - XCTAssertEqual(300.0, imageFrame.bottomRight.applying(affineTransform).y, accuracy: 0.1) - } - - func testImageEditorTransform1() { - let imageSizePixels = CGSize(width: 864, height: 1536) - let outputSizePixels = CGSize(width: 432, height: 768) - let unitTranslation = CGPoint(x: +0.5, y: -0.5) - let rotationRadians: CGFloat = 0 - let scaling: CGFloat = 2 - let transform = ImageEditorTransform(outputSizePixels: outputSizePixels, unitTranslation: unitTranslation, rotationRadians: rotationRadians, scaling: scaling, isFlipped: false) - - let viewSize = CGSize(width: 335, height: 595) - let imageFrame = ImageEditorCanvasView.imageFrame(forViewSize: viewSize, imageSize: imageSizePixels, transform: transform) - let affineTransform = transform.affineTransform(viewSize: viewSize) - - XCTAssertEqual(+167.5, imageFrame.topLeft.applying(affineTransform).x, accuracy: 0.1) - XCTAssertEqual(-298.0, imageFrame.topLeft.applying(affineTransform).y, accuracy: 0.1) - XCTAssertEqual(+502.5, imageFrame.center.applying(affineTransform).x, accuracy: 0.1) - XCTAssertEqual(+297.5, imageFrame.center.applying(affineTransform).y, accuracy: 0.1) - XCTAssertEqual(+837.5, imageFrame.bottomRight.applying(affineTransform).x, accuracy: 0.1) - XCTAssertEqual(+893.0, imageFrame.bottomRight.applying(affineTransform).y, accuracy: 0.1) - } - - func testAffineTransformComposition() { - // Documents how classic SRT (scale-rotate-translate) ordering is specified - // in _reverse_ order using CGAffineTransform. - - // The transformed origin should reflect ONLY the translation, not scaling or rotation. - XCTAssertEqual(+20.0, CGPoint.zero.applying(CGAffineTransform.translate(CGPoint(x: 20, y: 30)).scale(5)).x, accuracy: 0.1) - XCTAssertEqual(+30.0, CGPoint.zero.applying(CGAffineTransform.translate(CGPoint(x: 20, y: 30)).scale(5)).y, accuracy: 0.1) - // WRONG: the translation is being scaled. - XCTAssertEqual(+100.0, CGPoint.zero.applying(CGAffineTransform.scale(5).translate(CGPoint(x: 20, y: 30))).x, accuracy: 0.1) - XCTAssertEqual(+150.0, CGPoint.zero.applying(CGAffineTransform.scale(5).translate(CGPoint(x: 20, y: 30))).y, accuracy: 0.1) - - // The transformed origin should reflect ONLY the translation, not scaling or rotation. - XCTAssertEqual(+20.0, CGPoint.zero.applying(CGAffineTransform.translate(CGPoint(x: 20, y: 30)).rotate(CGFloat.halfPi).scale(5)).x, accuracy: 0.1) - XCTAssertEqual(+30.0, CGPoint.zero.applying(CGAffineTransform.translate(CGPoint(x: 20, y: 30)).rotate(CGFloat.halfPi).scale(5)).y, accuracy: 0.1) - // WRONG: the translation is being scaled. - XCTAssertEqual(-150.0, CGPoint.zero.applying(CGAffineTransform.scale(5).rotate(CGFloat.halfPi).translate(CGPoint(x: 20, y: 30))).x, accuracy: 0.1) - XCTAssertEqual(+100.0, CGPoint.zero.applying(CGAffineTransform.scale(5).rotate(CGFloat.halfPi).translate(CGPoint(x: 20, y: 30))).y, accuracy: 0.1) - - // An arbitrary point one "unit" away from the origin should be end up scaled (unit x scaling) + translation. - XCTAssertEqual(+25.0, CGPoint.unit.applying(CGAffineTransform.translate(CGPoint(x: 20, y: 30)).scale(5)).x, accuracy: 0.1) - XCTAssertEqual(+35.0, CGPoint.unit.applying(CGAffineTransform.translate(CGPoint(x: 20, y: 30)).scale(5)).y, accuracy: 0.1) - // WRONG: the translation is being scaled. - XCTAssertEqual(+105.0, CGPoint.unit.applying(CGAffineTransform.scale(5).translate(CGPoint(x: 20, y: 30))).x, accuracy: 0.1) - XCTAssertEqual(+155.0, CGPoint.unit.applying(CGAffineTransform.scale(5).translate(CGPoint(x: 20, y: 30))).y, accuracy: 0.1) - - // An arbitrary point one "unit" away from the origin should be end up scaled (unit x scaling ... rotated about the origin) + translation. - XCTAssertEqual(+15.0, CGPoint.unit.applying(CGAffineTransform.translate(CGPoint(x: 20, y: 30)).rotate(CGFloat.halfPi).scale(5)).x, accuracy: 0.1) - XCTAssertEqual(+35.0, CGPoint.unit.applying(CGAffineTransform.translate(CGPoint(x: 20, y: 30)).rotate(CGFloat.halfPi).scale(5)).y, accuracy: 0.1) - // WRONG: the translation is being scaled. - XCTAssertEqual(-155.0, CGPoint.unit.applying(CGAffineTransform.scale(5).rotate(CGFloat.halfPi).translate(CGPoint(x: 20, y: 30))).x, accuracy: 0.1) - XCTAssertEqual(+105.0, CGPoint.unit.applying(CGAffineTransform.scale(5).rotate(CGFloat.halfPi).translate(CGPoint(x: 20, y: 30))).y, accuracy: 0.1) - } -} diff --git a/Session/test/views/ImageEditor/ImageEditorTest.swift b/Session/test/views/ImageEditor/ImageEditorTest.swift deleted file mode 100644 index 7e03a749a..000000000 --- a/Session/test/views/ImageEditor/ImageEditorTest.swift +++ /dev/null @@ -1,111 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -import XCTest -@testable import Session -@testable import SignalUtilitiesKit - -extension ImageEditorModel { - func itemIds() -> [String] { - return items().map { (item) in - item.itemId - } - } -} - -class ImageEditorTest: SignalBaseTest { - - override func setUp() { - super.setUp() - } - - override func tearDown() { - // Put teardown code here. This method is called after the invocation of each test method in the class. - super.tearDown() - } - - func testImageEditorContents() { - let contents = ImageEditorContents() - XCTAssertEqual(0, contents.itemMap.count) - - let item = ImageEditorItem(itemType: .test) - contents.append(item: item) - XCTAssertEqual(1, contents.itemMap.count) - - let contentsCopy = contents.clone() - XCTAssertEqual(1, contents.itemMap.count) - XCTAssertEqual(1, contentsCopy.itemMap.count) - - contentsCopy.remove(item: item) - XCTAssertEqual(1, contents.itemMap.count) - XCTAssertEqual(0, contentsCopy.itemMap.count) - - let modifiedItem = ImageEditorItem(itemId: item.itemId, itemType: item.itemType) - contents.replace(item: modifiedItem) - XCTAssertEqual(1, contents.itemMap.count) - XCTAssertEqual(0, contentsCopy.itemMap.count) - } - - private func writeDummyImage() -> String { - let image = UIImage.init(color: .red, size: CGSize(width: 1, height: 1)) - guard let data = image.pngData() else { - owsFail("Couldn't export dummy image.") - } - let filePath = OWSFileSystem.temporaryFilePath(withFileExtension: "png") - try! data.write(to: URL(fileURLWithPath: filePath)) - return filePath - } - - func testImageEditor() { - let imagePath = writeDummyImage() - - let imageEditor = try! ImageEditorModel(srcImagePath: imagePath) - XCTAssertFalse(imageEditor.canUndo()) - XCTAssertFalse(imageEditor.canRedo()) - XCTAssertEqual(0, imageEditor.itemCount()) - - let itemA = ImageEditorItem(itemType: .test) - imageEditor.append(item: itemA) - XCTAssertTrue(imageEditor.canUndo()) - XCTAssertFalse(imageEditor.canRedo()) - XCTAssertEqual(1, imageEditor.itemCount()) - XCTAssertEqual([itemA.itemId], imageEditor.itemIds()) - - imageEditor.undo() - XCTAssertFalse(imageEditor.canUndo()) - XCTAssertTrue(imageEditor.canRedo()) - XCTAssertEqual(0, imageEditor.itemCount()) - - imageEditor.redo() - XCTAssertTrue(imageEditor.canUndo()) - XCTAssertFalse(imageEditor.canRedo()) - XCTAssertEqual(1, imageEditor.itemCount()) - XCTAssertEqual([itemA.itemId], imageEditor.itemIds()) - - imageEditor.undo() - XCTAssertFalse(imageEditor.canUndo()) - XCTAssertTrue(imageEditor.canRedo()) - XCTAssertEqual(0, imageEditor.itemCount()) - - let itemB = ImageEditorItem(itemType: .test) - imageEditor.append(item: itemB) - XCTAssertTrue(imageEditor.canUndo()) - XCTAssertFalse(imageEditor.canRedo()) - XCTAssertEqual(1, imageEditor.itemCount()) - XCTAssertEqual([itemB.itemId], imageEditor.itemIds()) - - let itemC = ImageEditorItem(itemType: .test) - imageEditor.append(item: itemC) - XCTAssertTrue(imageEditor.canUndo()) - XCTAssertFalse(imageEditor.canRedo()) - XCTAssertEqual(2, imageEditor.itemCount()) - XCTAssertEqual([itemB.itemId, itemC.itemId], imageEditor.itemIds()) - - imageEditor.undo() - XCTAssertTrue(imageEditor.canUndo()) - XCTAssertTrue(imageEditor.canRedo()) - XCTAssertEqual(1, imageEditor.itemCount()) - XCTAssertEqual([itemB.itemId], imageEditor.itemIds()) - } -} diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 25db76c5d..40fcc8247 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -28,10 +28,8 @@ 340FC8BB204DAC8D007AEB0F /* OWSAddToContactViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 340FC8A1204DAC8D007AEB0F /* OWSAddToContactViewController.m */; }; 340FC8BC204DAC8D007AEB0F /* FingerprintViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 340FC8A2204DAC8D007AEB0F /* FingerprintViewController.m */; }; 340FC8BD204DAC8D007AEB0F /* ShowGroupMembersViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 340FC8A6204DAC8D007AEB0F /* ShowGroupMembersViewController.m */; }; - 340FC8C5204DE223007AEB0F /* DebugUIBackup.m in Sources */ = {isa = PBXBuildFile; fileRef = 340FC8C4204DE223007AEB0F /* DebugUIBackup.m */; }; 34129B8621EF877A005457A8 /* LinkPreviewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34129B8521EF8779005457A8 /* LinkPreviewView.swift */; }; 341341EF2187467A00192D59 /* ConversationViewModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 341341EE2187467900192D59 /* ConversationViewModel.m */; }; - 341F2C0F1F2B8AE700D07D6B /* DebugUIMisc.m in Sources */ = {isa = PBXBuildFile; fileRef = 341F2C0E1F2B8AE700D07D6B /* DebugUIMisc.m */; }; 34277A5E20751BDC006049F2 /* OWSQuotedMessageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 34277A5C20751BDC006049F2 /* OWSQuotedMessageView.m */; }; 3427C64320F500E000EEC730 /* OWSMessageTimerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 3427C64220F500DF00EEC730 /* OWSMessageTimerView.m */; }; 3430FE181F7751D4000EC51B /* GiphyAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3430FE171F7751D4000EC51B /* GiphyAPI.swift */; }; @@ -40,7 +38,6 @@ 34330A5E1E787BD800DF2FB9 /* ElegantIcons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 34330A5D1E787BD800DF2FB9 /* ElegantIcons.ttf */; }; 34330AA31E79686200DF2FB9 /* OWSProgressView.m in Sources */ = {isa = PBXBuildFile; fileRef = 34330AA21E79686200DF2FB9 /* OWSProgressView.m */; }; 34386A54207D271D009F5D9C /* NeverClearView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34386A53207D271C009F5D9C /* NeverClearView.swift */; }; - 343A65951FC47D5E000477A1 /* DebugUISyncMessages.m in Sources */ = {isa = PBXBuildFile; fileRef = 343A65941FC47D5E000477A1 /* DebugUISyncMessages.m */; }; 343A65981FC4CFE7000477A1 /* ConversationScrollButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 343A65961FC4CFE6000477A1 /* ConversationScrollButton.m */; }; 3441FD9F21A3604F00BB9542 /* BackupRestoreViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3441FD9E21A3604F00BB9542 /* BackupRestoreViewController.swift */; }; 34480B361FD0929200BC14EF /* ShareAppExtensionContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 34480B351FD0929200BC14EF /* ShareAppExtensionContext.m */; }; @@ -87,7 +84,6 @@ 34B6A905218B4C91007C4606 /* TypingIndicatorInteraction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34B6A904218B4C90007C4606 /* TypingIndicatorInteraction.swift */; }; 34B6A907218B5241007C4606 /* TypingIndicatorCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34B6A906218B5240007C4606 /* TypingIndicatorCell.swift */; }; 34B6A90B218BA1D1007C4606 /* typing-animation.gif in Resources */ = {isa = PBXBuildFile; fileRef = 34B6A90A218BA1D0007C4606 /* typing-animation.gif */; }; - 34BECE2B1F74C12700D7438D /* DebugUIStress.m in Sources */ = {isa = PBXBuildFile; fileRef = 34BECE2A1F74C12700D7438D /* DebugUIStress.m */; }; 34BECE2E1F7ABCE000D7438D /* GifPickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34BECE2D1F7ABCE000D7438D /* GifPickerViewController.swift */; }; 34BECE301F7ABCF800D7438D /* GifPickerLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34BECE2F1F7ABCF800D7438D /* GifPickerLayout.swift */; }; 34C3C78D20409F320000134C /* Opening.m4r in Resources */ = {isa = PBXBuildFile; fileRef = 34C3C78C20409F320000134C /* Opening.m4r */; }; @@ -114,22 +110,14 @@ 34D1F0BD1F8D108C0066283D /* AttachmentUploadView.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D1F0BC1F8D108C0066283D /* AttachmentUploadView.m */; }; 34D1F0C01F8EC1760066283D /* MessageRecipientStatusUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34D1F0BF1F8EC1760066283D /* MessageRecipientStatusUtils.swift */; }; 34D2CCDA2062E7D000CB1A14 /* OWSScreenLockUI.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D2CCD92062E7D000CB1A14 /* OWSScreenLockUI.m */; }; - 34D2CCDF206939B400CB1A14 /* DebugUIMessagesAction.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D2CCDB206939B100CB1A14 /* DebugUIMessagesAction.m */; }; - 34D2CCE0206939B400CB1A14 /* DebugUIMessagesAssetLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D2CCDC206939B200CB1A14 /* DebugUIMessagesAssetLoader.m */; }; 34D5CCA91EAE3D30005515DB /* AvatarViewHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D5CCA81EAE3D30005515DB /* AvatarViewHelper.m */; }; - 34D8C0271ED3673300188D7C /* DebugUIMessages.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D8C0241ED3673300188D7C /* DebugUIMessages.m */; }; - 34D8C0281ED3673300188D7C /* DebugUITableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D8C0261ED3673300188D7C /* DebugUITableViewController.m */; }; - 34D8C02B1ED3685800188D7C /* DebugUIContacts.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D8C02A1ED3685800188D7C /* DebugUIContacts.m */; }; 34D920E720E179C200D51158 /* OWSMessageFooterView.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D920E620E179C200D51158 /* OWSMessageFooterView.m */; }; 34D99C931F2937CC00D284D6 /* OWSAnalytics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34D99C911F2937CC00D284D6 /* OWSAnalytics.swift */; }; 34D99CE4217509C2000AFB39 /* AppEnvironment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34D99CE3217509C1000AFB39 /* AppEnvironment.swift */; }; 34DBF003206BD5A500025978 /* OWSMessageTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 34DBEFFF206BD5A400025978 /* OWSMessageTextView.m */; }; 34DBF004206BD5A500025978 /* OWSBubbleView.m in Sources */ = {isa = PBXBuildFile; fileRef = 34DBF001206BD5A500025978 /* OWSBubbleView.m */; }; 34DBF007206C3CB200025978 /* OWSBubbleShapeView.m in Sources */ = {isa = PBXBuildFile; fileRef = 34DBF006206C3CB200025978 /* OWSBubbleShapeView.m */; }; - 34DC9BD921543E0C00FDDCEC /* DebugContactsUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 34DC9BD721543E0A00FDDCEC /* DebugContactsUtils.m */; }; 34E3E5681EC4B19400495BAC /* AudioProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34E3E5671EC4B19400495BAC /* AudioProgressView.swift */; }; - 34E3EF0D1EFC235B007F6822 /* DebugUIDiskUsage.m in Sources */ = {isa = PBXBuildFile; fileRef = 34E3EF0C1EFC235B007F6822 /* DebugUIDiskUsage.m */; }; - 34E3EF101EFC2684007F6822 /* DebugUIPage.m in Sources */ = {isa = PBXBuildFile; fileRef = 34E3EF0F1EFC2684007F6822 /* DebugUIPage.m */; }; 34E88D262098C5AE00A608F4 /* ContactViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34E88D252098C5AE00A608F4 /* ContactViewController.swift */; }; 34EA69402194933900702471 /* MediaDownloadView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34EA693F2194933900702471 /* MediaDownloadView.swift */; }; 34EA69422194DE8000702471 /* MediaUploadView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34EA69412194DE7F00702471 /* MediaUploadView.swift */; }; @@ -145,7 +133,6 @@ 451166C01FD86B98000739BA /* AccountManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 451166BF1FD86B98000739BA /* AccountManager.swift */; }; 4517642B1DE939FD00EDB8B9 /* ContactCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 451764291DE939FD00EDB8B9 /* ContactCell.swift */; }; 451A13B11E13DED2000A50FD /* AppNotifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = 451A13B01E13DED2000A50FD /* AppNotifications.swift */; }; - 452037D11EE84975004E4CDF /* DebugUISessionState.m in Sources */ = {isa = PBXBuildFile; fileRef = 452037D01EE84975004E4CDF /* DebugUISessionState.m */; }; 4520D8D51D417D8E00123472 /* Photos.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4520D8D41D417D8E00123472 /* Photos.framework */; }; 4521C3C01F59F3BA00B4C582 /* TextFieldHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4521C3BF1F59F3BA00B4C582 /* TextFieldHelper.swift */; }; 452B999020A34B6B006F2F9E /* AddContactShareToExistingContactViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 452B998F20A34B6B006F2F9E /* AddContactShareToExistingContactViewController.swift */; }; @@ -158,14 +145,11 @@ 4539B5861F79348F007141FF /* PushRegistrationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4539B5851F79348F007141FF /* PushRegistrationManager.swift */; }; 4542DF54208D40AC007B4E76 /* LoadingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4542DF53208D40AC007B4E76 /* LoadingViewController.swift */; }; 454A84042059C787008B8C75 /* MediaTileViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 454A84032059C787008B8C75 /* MediaTileViewController.swift */; }; - 4556FA681F54AA9500AF40DD /* DebugUIProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4556FA671F54AA9500AF40DD /* DebugUIProfile.swift */; }; 455A16DD1F1FEA0000F86704 /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 455A16DB1F1FEA0000F86704 /* Metal.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; 455A16DE1F1FEA0000F86704 /* MetalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 455A16DC1F1FEA0000F86704 /* MetalKit.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; - 45638BDC1F3DD0D400128435 /* DebugUICalling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45638BDB1F3DD0D400128435 /* DebugUICalling.swift */; }; 4574A5D61DD6704700C6B692 /* CallService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4574A5D51DD6704700C6B692 /* CallService.swift */; }; 4579431E1E7C8CE9008ED0C0 /* Pastelog.m in Sources */ = {isa = PBXBuildFile; fileRef = 4579431D1E7C8CE9008ED0C0 /* Pastelog.m */; }; 45794E861E00620000066731 /* CallUIAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45794E851E00620000066731 /* CallUIAdapter.swift */; }; - 457C87B82032645C008D52D6 /* DebugUINotifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = 457C87B72032645C008D52D6 /* DebugUINotifications.swift */; }; 457F671B20746193000EABCD /* QuotedReplyPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = 457F671A20746193000EABCD /* QuotedReplyPreview.swift */; }; 45847E871E4283C30080EAB3 /* Intents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 45847E861E4283C30080EAB3 /* Intents.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; 4585C4681ED8F8D200896AEA /* SafetyNumberConfirmationAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4585C4671ED8F8D200896AEA /* SafetyNumberConfirmationAlert.swift */; }; @@ -176,7 +160,6 @@ 45A663C51F92EC760027B59E /* GroupTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45A663C41F92EC760027B59E /* GroupTableViewCell.swift */; }; 45A6DAD61EBBF85500893231 /* ReminderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45A6DAD51EBBF85500893231 /* ReminderView.swift */; }; 45AE48511E0732D6004D96C2 /* TurnServerInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45AE48501E0732D6004D96C2 /* TurnServerInfo.swift */; }; - 45B27B862037FFB400A539DF /* DebugUIFileBrowser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45B27B852037FFB400A539DF /* DebugUIFileBrowser.swift */; }; 45B5360E206DD8BB00D61655 /* UIResponder+OWS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45B5360D206DD8BB00D61655 /* UIResponder+OWS.swift */; }; 45B74A742044AAB600CD42F8 /* aurora-quiet.aifc in Resources */ = {isa = PBXBuildFile; fileRef = 45B74A5B2044AAB300CD42F8 /* aurora-quiet.aifc */; }; 45B74A752044AAB600CD42F8 /* synth-quiet.aifc in Resources */ = {isa = PBXBuildFile; fileRef = 45B74A5C2044AAB300CD42F8 /* synth-quiet.aifc */; }; @@ -254,7 +237,6 @@ 7BC01A3E241F40AB00BC7C55 /* NotificationServiceExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BC01A3D241F40AB00BC7C55 /* NotificationServiceExtension.swift */; }; 7BC01A42241F40AB00BC7C55 /* SessionPushNotificationExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 7BC01A3B241F40AB00BC7C55 /* SessionPushNotificationExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 7BDCFC08242186E700641C39 /* NotificationServiceExtensionContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BDCFC07242186E700641C39 /* NotificationServiceExtensionContext.swift */; }; - 7BDCFC092421894900641C39 /* MessageFetcherJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = 452ECA4C1E087E7200E2F016 /* MessageFetcherJob.swift */; }; 7BDCFC0B2421EB7600641C39 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = B6F509951AA53F760068F56A /* Localizable.strings */; }; 8E10697B10CBC965F052A4CB /* Pods_SessionPushNotificationExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D9E02BC2732E07195B5AFA75 /* Pods_SessionPushNotificationExtension.framework */; }; 945AA2B82B621254F69FA9E8 /* Pods_SessionUtilitiesKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9117261809D69B3D7C26B8F1 /* Pods_SessionUtilitiesKit.framework */; }; @@ -1326,7 +1308,6 @@ 3303495F6651CE2F3CC9693B /* Pods-SessionUtilities.app store release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SessionUtilities.app store release.xcconfig"; path = "Pods/Target Support Files/Pods-SessionUtilities/Pods-SessionUtilities.app store release.xcconfig"; sourceTree = ""; }; 3403B95B20EA9526001A1F44 /* OWSContactShareButtonsView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSContactShareButtonsView.m; sourceTree = ""; }; 3403B95C20EA9527001A1F44 /* OWSContactShareButtonsView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSContactShareButtonsView.h; sourceTree = ""; }; - 340B02B91FA0D6C700F9CFEC /* ConversationViewItemTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ConversationViewItemTest.m; sourceTree = ""; }; 340FC87B204DAC8C007AEB0F /* NotificationSettingsOptionsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NotificationSettingsOptionsViewController.m; sourceTree = ""; }; 340FC87C204DAC8C007AEB0F /* NotificationSettingsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NotificationSettingsViewController.m; sourceTree = ""; }; 340FC87D204DAC8C007AEB0F /* DomainFrontingCountryViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DomainFrontingCountryViewController.m; sourceTree = ""; }; @@ -1364,14 +1345,9 @@ 340FC8A4204DAC8D007AEB0F /* AddToGroupViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AddToGroupViewController.h; sourceTree = ""; }; 340FC8A5204DAC8D007AEB0F /* FingerprintViewScanController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FingerprintViewScanController.h; sourceTree = ""; }; 340FC8A6204DAC8D007AEB0F /* ShowGroupMembersViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ShowGroupMembersViewController.m; sourceTree = ""; }; - 340FC8C3204DE223007AEB0F /* DebugUIBackup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebugUIBackup.h; sourceTree = ""; }; - 340FC8C4204DE223007AEB0F /* DebugUIBackup.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DebugUIBackup.m; sourceTree = ""; }; 34129B8521EF8779005457A8 /* LinkPreviewView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LinkPreviewView.swift; sourceTree = ""; }; 341341ED2187467900192D59 /* ConversationViewModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConversationViewModel.h; sourceTree = ""; }; 341341EE2187467900192D59 /* ConversationViewModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ConversationViewModel.m; sourceTree = ""; }; - 341F2C0D1F2B8AE700D07D6B /* DebugUIMisc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebugUIMisc.h; sourceTree = ""; }; - 341F2C0E1F2B8AE700D07D6B /* DebugUIMisc.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DebugUIMisc.m; sourceTree = ""; }; - 3421981B21061D2E00C57195 /* ByteParserTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ByteParserTest.swift; sourceTree = ""; }; 34277A5C20751BDC006049F2 /* OWSQuotedMessageView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSQuotedMessageView.m; sourceTree = ""; }; 34277A5D20751BDC006049F2 /* OWSQuotedMessageView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSQuotedMessageView.h; sourceTree = ""; }; 3427C64120F500DE00EEC730 /* OWSMessageTimerView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSMessageTimerView.h; sourceTree = ""; }; @@ -1383,8 +1359,6 @@ 34330AA11E79686200DF2FB9 /* OWSProgressView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSProgressView.h; sourceTree = ""; }; 34330AA21E79686200DF2FB9 /* OWSProgressView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSProgressView.m; sourceTree = ""; }; 34386A53207D271C009F5D9C /* NeverClearView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NeverClearView.swift; sourceTree = ""; }; - 343A65931FC47D5D000477A1 /* DebugUISyncMessages.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebugUISyncMessages.h; sourceTree = ""; }; - 343A65941FC47D5E000477A1 /* DebugUISyncMessages.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DebugUISyncMessages.m; sourceTree = ""; }; 343A65961FC4CFE6000477A1 /* ConversationScrollButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ConversationScrollButton.m; sourceTree = ""; }; 343A65971FC4CFE7000477A1 /* ConversationScrollButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConversationScrollButton.h; sourceTree = ""; }; 3441FD9E21A3604F00BB9542 /* BackupRestoreViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BackupRestoreViewController.swift; sourceTree = ""; }; @@ -1396,24 +1370,18 @@ 344825C5211390C800DB4BD8 /* OWSOrphanDataCleaner.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSOrphanDataCleaner.m; sourceTree = ""; }; 3448E1652215B313004B052E /* OnboardingCaptchaViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OnboardingCaptchaViewController.swift; sourceTree = ""; }; 3461284A1FD0B93F00532771 /* SAELoadViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SAELoadViewController.swift; sourceTree = ""; }; - 3461293D1FD1D72B00532771 /* ExperienceUpgradeFinder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ExperienceUpgradeFinder.swift; path = ExperienceUpgrades/ExperienceUpgradeFinder.swift; sourceTree = ""; }; + 3461293D1FD1D72B00532771 /* ExperienceUpgradeFinder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExperienceUpgradeFinder.swift; sourceTree = ""; }; 346129971FD1E4D900532771 /* SignalApp.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SignalApp.m; sourceTree = ""; }; 346129981FD1E4DA00532771 /* SignalApp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SignalApp.h; sourceTree = ""; }; 34641E1D2088DA6C00E2EDE5 /* SAEScreenLockViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SAEScreenLockViewController.h; sourceTree = ""; }; 34641E1E2088DA6D00E2EDE5 /* SAEScreenLockViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SAEScreenLockViewController.m; sourceTree = ""; }; - 34661FB720C1C0D60056EDD6 /* message_sent.aiff */ = {isa = PBXFileReference; lastKnownFileType = audio.aiff; name = message_sent.aiff; path = Session/AudioFiles/message_sent.aiff; sourceTree = SOURCE_ROOT; }; + 34661FB720C1C0D60056EDD6 /* message_sent.aiff */ = {isa = PBXFileReference; lastKnownFileType = audio.aiff; name = message_sent.aiff; path = Session/Meta/AudioFiles/message_sent.aiff; sourceTree = SOURCE_ROOT; }; 346B66301F4E29B200E5122F /* CropScaleImageViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CropScaleImageViewController.swift; sourceTree = ""; }; 347850561FD86544007B8332 /* SAEFailedViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SAEFailedViewController.swift; sourceTree = ""; }; - 34843B2221432292004DED45 /* SignalBaseTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SignalBaseTest.m; sourceTree = ""; }; - 34843B2321432293004DED45 /* SignalBaseTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SignalBaseTest.h; sourceTree = ""; }; - 34843B25214327C9004DED45 /* OWSOrphanDataCleanerTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSOrphanDataCleanerTest.m; sourceTree = ""; }; - 34843B2A214FE295004DED45 /* MockEnvironment.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MockEnvironment.m; sourceTree = ""; }; - 34843B2B214FE295004DED45 /* MockEnvironment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MockEnvironment.h; sourceTree = ""; }; 348570A620F67574004FF32B /* OWSMessageHeaderView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSMessageHeaderView.m; sourceTree = ""; }; 348570A720F67574004FF32B /* OWSMessageHeaderView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSMessageHeaderView.h; sourceTree = ""; }; 3488F9352191CC4000E524CC /* ConversationMediaView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConversationMediaView.swift; sourceTree = ""; }; 348BB25C20A0C5530047AEC2 /* ContactShareViewHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContactShareViewHelper.swift; sourceTree = ""; }; - 3491D9A021022DB7001EF5A1 /* CDSSigningCertificateTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDSSigningCertificateTest.m; sourceTree = ""; }; 3496744B2076768600080B5F /* OWSMessageBubbleView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSMessageBubbleView.h; sourceTree = ""; }; 3496744C2076768700080B5F /* OWSMessageBubbleView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSMessageBubbleView.m; sourceTree = ""; }; 3496744E2076ACCE00080B5F /* LongTextViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LongTextViewController.swift; sourceTree = ""; }; @@ -1450,26 +1418,18 @@ 34B6A904218B4C90007C4606 /* TypingIndicatorInteraction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TypingIndicatorInteraction.swift; sourceTree = ""; }; 34B6A906218B5240007C4606 /* TypingIndicatorCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TypingIndicatorCell.swift; sourceTree = ""; }; 34B6A90A218BA1D0007C4606 /* typing-animation.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = "typing-animation.gif"; sourceTree = ""; }; - 34BBC85F220E883200857249 /* ImageEditorModelTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageEditorModelTest.swift; sourceTree = ""; }; - 34BBC860220E883200857249 /* ImageEditorTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageEditorTest.swift; sourceTree = ""; }; - 34BECE291F74C12700D7438D /* DebugUIStress.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebugUIStress.h; sourceTree = ""; }; - 34BECE2A1F74C12700D7438D /* DebugUIStress.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DebugUIStress.m; sourceTree = ""; }; 34BECE2D1F7ABCE000D7438D /* GifPickerViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GifPickerViewController.swift; sourceTree = ""; }; 34BECE2F1F7ABCF800D7438D /* GifPickerLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GifPickerLayout.swift; sourceTree = ""; }; 34C3C78C20409F320000134C /* Opening.m4r */ = {isa = PBXFileReference; lastKnownFileType = file; path = Opening.m4r; sourceTree = ""; }; - 34C3C78E2040A4F70000134C /* sonarping.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; name = sonarping.mp3; path = Session/AudioFiles/sonarping.mp3; sourceTree = SOURCE_ROOT; }; + 34C3C78E2040A4F70000134C /* sonarping.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; name = sonarping.mp3; path = Session/Meta/AudioFiles/sonarping.mp3; sourceTree = SOURCE_ROOT; }; 34C4E2552118957600BEA353 /* OWSWebRTCDataProtos.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWSWebRTCDataProtos.pb.swift; sourceTree = ""; }; 34C4E2562118957600BEA353 /* WebRTCProto.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebRTCProto.swift; sourceTree = ""; }; - 34C6B0A51FA0E46F00D35993 /* test-gif.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = "test-gif.gif"; sourceTree = ""; }; - 34C6B0A71FA0E46F00D35993 /* test-mp3.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = "test-mp3.mp3"; sourceTree = ""; }; - 34C6B0A81FA0E46F00D35993 /* test-mp4.mp4 */ = {isa = PBXFileReference; lastKnownFileType = file; path = "test-mp4.mp4"; sourceTree = ""; }; - 34C6B0AD1FA0E4AA00D35993 /* test-jpg.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "test-jpg.jpg"; sourceTree = ""; }; 34CA1C261F7156F300E51C51 /* MessageDetailViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageDetailViewController.swift; sourceTree = ""; }; 34CA63192097806E00E526A0 /* OWSContactShareView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSContactShareView.h; sourceTree = ""; }; 34CA631A2097806E00E526A0 /* OWSContactShareView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSContactShareView.m; sourceTree = ""; }; - 34CF0783203E6B77005C4D61 /* busy_tone_ansi.caf */ = {isa = PBXFileReference; lastKnownFileType = file; name = busy_tone_ansi.caf; path = Session/AudioFiles/busy_tone_ansi.caf; sourceTree = SOURCE_ROOT; }; - 34CF0784203E6B77005C4D61 /* ringback_tone_ansi.caf */ = {isa = PBXFileReference; lastKnownFileType = file; name = ringback_tone_ansi.caf; path = Session/AudioFiles/ringback_tone_ansi.caf; sourceTree = SOURCE_ROOT; }; - 34CF0786203E6B78005C4D61 /* end_call_tone_cept.caf */ = {isa = PBXFileReference; lastKnownFileType = file; name = end_call_tone_cept.caf; path = Session/AudioFiles/end_call_tone_cept.caf; sourceTree = SOURCE_ROOT; }; + 34CF0783203E6B77005C4D61 /* busy_tone_ansi.caf */ = {isa = PBXFileReference; lastKnownFileType = file; name = busy_tone_ansi.caf; path = Session/Meta/AudioFiles/busy_tone_ansi.caf; sourceTree = SOURCE_ROOT; }; + 34CF0784203E6B77005C4D61 /* ringback_tone_ansi.caf */ = {isa = PBXFileReference; lastKnownFileType = file; name = ringback_tone_ansi.caf; path = Session/Meta/AudioFiles/ringback_tone_ansi.caf; sourceTree = SOURCE_ROOT; }; + 34CF0786203E6B78005C4D61 /* end_call_tone_cept.caf */ = {isa = PBXFileReference; lastKnownFileType = file; name = end_call_tone_cept.caf; path = Session/Meta/AudioFiles/end_call_tone_cept.caf; sourceTree = SOURCE_ROOT; }; 34D1F04F1F7D45A60066283D /* GifPickerCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GifPickerCell.swift; sourceTree = ""; }; 34D1F0511F7E8EA30066283D /* GiphyDownloader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GiphyDownloader.swift; sourceTree = ""; }; 34D1F0671F8678AA0066283D /* ConversationInputTextView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConversationInputTextView.h; sourceTree = ""; }; @@ -1499,39 +1459,20 @@ 34D1F0BF1F8EC1760066283D /* MessageRecipientStatusUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageRecipientStatusUtils.swift; sourceTree = ""; }; 34D2CCD82062E7D000CB1A14 /* OWSScreenLockUI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSScreenLockUI.h; sourceTree = ""; }; 34D2CCD92062E7D000CB1A14 /* OWSScreenLockUI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSScreenLockUI.m; sourceTree = ""; }; - 34D2CCDB206939B100CB1A14 /* DebugUIMessagesAction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DebugUIMessagesAction.m; sourceTree = ""; }; - 34D2CCDC206939B200CB1A14 /* DebugUIMessagesAssetLoader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DebugUIMessagesAssetLoader.m; sourceTree = ""; }; - 34D2CCDD206939B200CB1A14 /* DebugUIMessagesAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebugUIMessagesAction.h; sourceTree = ""; }; - 34D2CCDE206939B400CB1A14 /* DebugUIMessagesAssetLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebugUIMessagesAssetLoader.h; sourceTree = ""; }; - 34D2CCE220693A1700CB1A14 /* DebugUIMessagesUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebugUIMessagesUtils.h; sourceTree = ""; }; 34D5CCA71EAE3D30005515DB /* AvatarViewHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AvatarViewHelper.h; sourceTree = ""; }; 34D5CCA81EAE3D30005515DB /* AvatarViewHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AvatarViewHelper.m; sourceTree = ""; }; - 34D8C0231ED3673300188D7C /* DebugUIMessages.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebugUIMessages.h; sourceTree = ""; }; - 34D8C0241ED3673300188D7C /* DebugUIMessages.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DebugUIMessages.m; sourceTree = ""; }; - 34D8C0251ED3673300188D7C /* DebugUITableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebugUITableViewController.h; sourceTree = ""; }; - 34D8C0261ED3673300188D7C /* DebugUITableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = DebugUITableViewController.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; - 34D8C0291ED3685800188D7C /* DebugUIContacts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebugUIContacts.h; sourceTree = ""; }; - 34D8C02A1ED3685800188D7C /* DebugUIContacts.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DebugUIContacts.m; sourceTree = ""; }; 34D920E520E179C100D51158 /* OWSMessageFooterView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSMessageFooterView.h; sourceTree = ""; }; 34D920E620E179C200D51158 /* OWSMessageFooterView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSMessageFooterView.m; sourceTree = ""; }; 34D99C911F2937CC00D284D6 /* OWSAnalytics.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWSAnalytics.swift; sourceTree = ""; }; 34D99CE3217509C1000AFB39 /* AppEnvironment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppEnvironment.swift; sourceTree = ""; }; - 34DB0BEC2011548B007B313F /* OWSDatabaseConverterTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSDatabaseConverterTest.m; sourceTree = ""; }; 34DBEFFF206BD5A400025978 /* OWSMessageTextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSMessageTextView.m; sourceTree = ""; }; 34DBF000206BD5A400025978 /* OWSMessageTextView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSMessageTextView.h; sourceTree = ""; }; 34DBF001206BD5A500025978 /* OWSBubbleView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSBubbleView.m; sourceTree = ""; }; 34DBF002206BD5A500025978 /* OWSBubbleView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSBubbleView.h; sourceTree = ""; }; 34DBF005206C3CB100025978 /* OWSBubbleShapeView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSBubbleShapeView.h; sourceTree = ""; }; 34DBF006206C3CB200025978 /* OWSBubbleShapeView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSBubbleShapeView.m; sourceTree = ""; }; - 34DC9BD721543E0A00FDDCEC /* DebugContactsUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DebugContactsUtils.m; sourceTree = ""; }; - 34DC9BD821543E0B00FDDCEC /* DebugContactsUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebugContactsUtils.h; sourceTree = ""; }; 34E3E5671EC4B19400495BAC /* AudioProgressView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioProgressView.swift; sourceTree = ""; }; - 34E3EF0B1EFC235B007F6822 /* DebugUIDiskUsage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebugUIDiskUsage.h; sourceTree = ""; }; - 34E3EF0C1EFC235B007F6822 /* DebugUIDiskUsage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DebugUIDiskUsage.m; sourceTree = ""; }; - 34E3EF0E1EFC2684007F6822 /* DebugUIPage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebugUIPage.h; sourceTree = ""; }; - 34E3EF0F1EFC2684007F6822 /* DebugUIPage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DebugUIPage.m; sourceTree = ""; }; 34E88D252098C5AE00A608F4 /* ContactViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContactViewController.swift; sourceTree = ""; }; - 34E8A8D02085238900B272B1 /* ProtoParsingTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ProtoParsingTest.m; sourceTree = ""; }; 34EA693F2194933900702471 /* MediaDownloadView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaDownloadView.swift; sourceTree = ""; }; 34EA69412194DE7F00702471 /* MediaUploadView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaUploadView.swift; sourceTree = ""; }; 34F308A01ECB469700BB7697 /* OWSBezierPathView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSBezierPathView.h; sourceTree = ""; }; @@ -1541,61 +1482,48 @@ 435EAC2E5E22D3F087EB3192 /* Pods-SignalShareExtension.app store release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SignalShareExtension.app store release.xcconfig"; path = "Pods/Target Support Files/Pods-SignalShareExtension/Pods-SignalShareExtension.app store release.xcconfig"; sourceTree = ""; }; 4503F1BB20470A5B00CEE724 /* classic-quiet.aifc */ = {isa = PBXFileReference; lastKnownFileType = file; path = "classic-quiet.aifc"; sourceTree = ""; }; 4503F1BC20470A5B00CEE724 /* classic.aifc */ = {isa = PBXFileReference; lastKnownFileType = file; path = classic.aifc; sourceTree = ""; }; - 4505C2BE1E648EA300CEBF41 /* ExperienceUpgrade.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ExperienceUpgrade.swift; path = ExperienceUpgrades/ExperienceUpgrade.swift; sourceTree = ""; }; + 4505C2BE1E648EA300CEBF41 /* ExperienceUpgrade.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExperienceUpgrade.swift; sourceTree = ""; }; 4509E7991DD653700025A59F /* WebRTC.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebRTC.framework; path = ThirdParty/WebRTC/Build/WebRTC.framework; sourceTree = ""; }; 450D19111F85236600970622 /* RemoteVideoView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RemoteVideoView.h; sourceTree = ""; }; 450D19121F85236600970622 /* RemoteVideoView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RemoteVideoView.m; sourceTree = ""; }; 450DF2041E0D74AC003D14BE /* Platform.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Platform.swift; sourceTree = ""; }; - 450DF2081E0DD2C6003D14BE /* UserNotificationsAdaptee.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; name = UserNotificationsAdaptee.swift; path = UserInterface/Notifications/UserNotificationsAdaptee.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; + 450DF2081E0DD2C6003D14BE /* UserNotificationsAdaptee.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = UserNotificationsAdaptee.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 451166BF1FD86B98000739BA /* AccountManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountManager.swift; sourceTree = ""; }; 451764291DE939FD00EDB8B9 /* ContactCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContactCell.swift; sourceTree = ""; }; - 451A13B01E13DED2000A50FD /* AppNotifications.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; name = AppNotifications.swift; path = UserInterface/Notifications/AppNotifications.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; - 452037CF1EE84975004E4CDF /* DebugUISessionState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebugUISessionState.h; sourceTree = ""; }; - 452037D01EE84975004E4CDF /* DebugUISessionState.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DebugUISessionState.m; sourceTree = ""; }; + 451A13B01E13DED2000A50FD /* AppNotifications.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = AppNotifications.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 4520D8D41D417D8E00123472 /* Photos.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Photos.framework; path = System/Library/Frameworks/Photos.framework; sourceTree = SDKROOT; }; 4521C3BF1F59F3BA00B4C582 /* TextFieldHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextFieldHelper.swift; sourceTree = ""; }; 452B998F20A34B6B006F2F9E /* AddContactShareToExistingContactViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddContactShareToExistingContactViewController.swift; sourceTree = ""; }; 452C468E1E427E200087B011 /* OutboundCallInitiator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OutboundCallInitiator.swift; sourceTree = ""; }; - 452D1AF02081059C00A67F7F /* StringAdditionsTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringAdditionsTest.swift; sourceTree = ""; }; 452EC6DE205E9E30000E787C /* MediaGalleryViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaGalleryViewController.swift; sourceTree = ""; }; 452ECA4C1E087E7200E2F016 /* MessageFetcherJob.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageFetcherJob.swift; sourceTree = ""; }; 453518681FC635DD00210559 /* SessionShareExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = SessionShareExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 4535186A1FC635DD00210559 /* ShareViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareViewController.swift; sourceTree = ""; }; 4535186D1FC635DD00210559 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/MainInterface.storyboard; sourceTree = ""; }; 4535186F1FC635DD00210559 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 45360B8F1F9527DA00FA666C /* SearcherTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearcherTest.swift; sourceTree = ""; }; 4539B5851F79348F007141FF /* PushRegistrationManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PushRegistrationManager.swift; sourceTree = ""; }; 4542DF53208D40AC007B4E76 /* LoadingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadingViewController.swift; sourceTree = ""; }; 454A84032059C787008B8C75 /* MediaTileViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaTileViewController.swift; sourceTree = ""; }; - 4556FA671F54AA9500AF40DD /* DebugUIProfile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DebugUIProfile.swift; sourceTree = ""; }; 455A16DB1F1FEA0000F86704 /* Metal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Metal.framework; path = System/Library/Frameworks/Metal.framework; sourceTree = SDKROOT; }; 455A16DC1F1FEA0000F86704 /* MetalKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetalKit.framework; path = System/Library/Frameworks/MetalKit.framework; sourceTree = SDKROOT; }; - 455AC69D1F4F8B0300134004 /* ImageCacheTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageCacheTest.swift; sourceTree = ""; }; - 45638BDB1F3DD0D400128435 /* DebugUICalling.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DebugUICalling.swift; sourceTree = ""; }; - 45666F571D9B2880008FE134 /* OWSScrubbingLogFormatterTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSScrubbingLogFormatterTest.m; sourceTree = ""; }; - 456F6E2E1E261D1000FD2210 /* PeerConnectionClientTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PeerConnectionClientTest.swift; sourceTree = ""; }; 4574A5D51DD6704700C6B692 /* CallService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = CallService.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 4579431C1E7C8CE9008ED0C0 /* Pastelog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Pastelog.h; sourceTree = ""; }; 4579431D1E7C8CE9008ED0C0 /* Pastelog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Pastelog.m; sourceTree = ""; }; - 45794E851E00620000066731 /* CallUIAdapter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CallUIAdapter.swift; path = UserInterface/CallUIAdapter.swift; sourceTree = ""; }; - 457C87B72032645C008D52D6 /* DebugUINotifications.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebugUINotifications.swift; sourceTree = ""; }; + 45794E851E00620000066731 /* CallUIAdapter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallUIAdapter.swift; sourceTree = ""; }; 457F671A20746193000EABCD /* QuotedReplyPreview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuotedReplyPreview.swift; sourceTree = ""; }; 45847E861E4283C30080EAB3 /* Intents.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Intents.framework; path = System/Library/Frameworks/Intents.framework; sourceTree = SDKROOT; }; 4585C4671ED8F8D200896AEA /* SafetyNumberConfirmationAlert.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SafetyNumberConfirmationAlert.swift; sourceTree = ""; }; - 4589670F1DC117CC00E9DD21 /* SignalTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SignalTests-Bridging-Header.h"; sourceTree = ""; }; 458DE9D51DEE3FD00071BB03 /* PeerConnectionClient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PeerConnectionClient.swift; sourceTree = ""; }; 458E38351D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSDeviceProvisioningURLParser.h; sourceTree = ""; }; 458E38361D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSDeviceProvisioningURLParser.m; sourceTree = ""; }; - 458E38391D6699FA0094BD24 /* OWSDeviceProvisioningURLParserTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSDeviceProvisioningURLParserTest.m; path = Models/OWSDeviceProvisioningURLParserTest.m; sourceTree = ""; }; 459311FA1D75C948008DD4F0 /* OWSDeviceTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSDeviceTableViewCell.h; sourceTree = ""; }; 459311FB1D75C948008DD4F0 /* OWSDeviceTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSDeviceTableViewCell.m; sourceTree = ""; }; - 45A2F004204473A3002E978A /* NewMessage.aifc */ = {isa = PBXFileReference; lastKnownFileType = file; name = NewMessage.aifc; path = Session/AudioFiles/NewMessage.aifc; sourceTree = SOURCE_ROOT; }; + 45A2F004204473A3002E978A /* NewMessage.aifc */ = {isa = PBXFileReference; lastKnownFileType = file; name = NewMessage.aifc; path = Session/Meta/AudioFiles/NewMessage.aifc; sourceTree = SOURCE_ROOT; }; 45A663C41F92EC760027B59E /* GroupTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupTableViewCell.swift; sourceTree = ""; }; 45A6DAD51EBBF85500893231 /* ReminderView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReminderView.swift; sourceTree = ""; }; 45AE48501E0732D6004D96C2 /* TurnServerInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TurnServerInfo.swift; sourceTree = ""; }; 45B201741DAECBFD00C461E0 /* Signal-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Signal-Bridging-Header.h"; sourceTree = ""; }; - 45B27B852037FFB400A539DF /* DebugUIFileBrowser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebugUIFileBrowser.swift; sourceTree = ""; }; - 45B5360D206DD8BB00D61655 /* UIResponder+OWS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = "UIResponder+OWS.swift"; path = "util/UI Categories/UIResponder+OWS.swift"; sourceTree = ""; }; + 45B5360D206DD8BB00D61655 /* UIResponder+OWS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIResponder+OWS.swift"; sourceTree = ""; }; 45B74A5B2044AAB300CD42F8 /* aurora-quiet.aifc */ = {isa = PBXFileReference; lastKnownFileType = file; path = "aurora-quiet.aifc"; sourceTree = ""; }; 45B74A5C2044AAB300CD42F8 /* synth-quiet.aifc */ = {isa = PBXFileReference; lastKnownFileType = file; path = "synth-quiet.aifc"; sourceTree = ""; }; 45B74A5D2044AAB400CD42F8 /* keys-quiet.aifc */ = {isa = PBXFileReference; lastKnownFileType = file; path = "keys-quiet.aifc"; sourceTree = ""; }; @@ -1626,7 +1554,7 @@ 45C0DC1A1E68FE9000E04C47 /* UIApplication+OWS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIApplication+OWS.swift"; sourceTree = ""; }; 45C0DC1D1E69011F00E04C47 /* UIStoryboard+OWS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIStoryboard+OWS.swift"; sourceTree = ""; }; 45C9DEB71DF4E35A0065CA84 /* WebRTCCallMessageHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebRTCCallMessageHandler.swift; sourceTree = ""; }; - 45CB2FA71CB7146C00E1B343 /* Launch Screen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = "Launch Screen.storyboard"; path = "Session/src/util/Launch Screen.storyboard"; sourceTree = SOURCE_ROOT; }; + 45CB2FA71CB7146C00E1B343 /* Launch Screen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = "Launch Screen.storyboard"; path = "Session/Signal/Launch Screen.storyboard"; sourceTree = SOURCE_ROOT; }; 45CD81EE1DC030E7004C9430 /* SyncPushTokensJob.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SyncPushTokensJob.swift; sourceTree = ""; }; 45D231761DC7E8F10034FA89 /* SessionResetJob.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SessionResetJob.swift; sourceTree = ""; }; 45D308AB2049A439000189E4 /* PinEntryView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PinEntryView.h; sourceTree = ""; }; @@ -1634,28 +1562,24 @@ 45DDA6232090CEB500DE97F8 /* ConversationHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationHeaderView.swift; sourceTree = ""; }; 45DF5DF11DDB843F00C936C7 /* CompareSafetyNumbersActivity.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CompareSafetyNumbersActivity.swift; sourceTree = ""; }; 45E5A6981F61E6DD001E4A8A /* MarqueeLabel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarqueeLabel.swift; sourceTree = ""; }; - 45E7A6A61E71CA7E00D44FB5 /* DisplayableTextFilterTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DisplayableTextFilterTest.swift; sourceTree = ""; }; 45F170BA1E2FC5D3003FC1F2 /* CallAudioService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallAudioService.swift; sourceTree = ""; }; - 45F32C1D205718B000A300D5 /* MediaPageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MediaPageViewController.swift; path = Session/src/ViewControllers/MediaPageViewController.swift; sourceTree = SOURCE_ROOT; }; + 45F32C1D205718B000A300D5 /* MediaPageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MediaPageViewController.swift; path = Session/Signal/MediaPageViewController.swift; sourceTree = SOURCE_ROOT; }; 45F659721E1BD99C00444429 /* CallKitCallUIAdaptee.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallKitCallUIAdaptee.swift; sourceTree = ""; }; 45F659811E1BE77000444429 /* NonCallKitCallUIAdaptee.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NonCallKitCallUIAdaptee.swift; sourceTree = ""; }; 45FBC59A1DF8575700E9B410 /* CallKitCallManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallKitCallManager.swift; sourceTree = ""; }; 45FBC5D01DF8592E00E9B410 /* SignalCall.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SignalCall.swift; sourceTree = ""; }; 4C043929220A9EC800BAEA63 /* VoiceNoteLock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoiceNoteLock.swift; sourceTree = ""; }; - 4C04F58321C860C50090D0BB /* MantlePerfTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MantlePerfTest.swift; path = Models/MantlePerfTest.swift; sourceTree = ""; }; - 4C090A1A210FD9C7001FD7F9 /* HapticFeedback.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = HapticFeedback.swift; path = UserInterface/HapticFeedback.swift; sourceTree = ""; }; + 4C090A1A210FD9C7001FD7F9 /* HapticFeedback.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HapticFeedback.swift; sourceTree = ""; }; 4C13C9F520E57BA30089A98B /* ColorPickerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorPickerViewController.swift; sourceTree = ""; }; 4C1885D1218F8E1C00B67051 /* PhotoGridViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoGridViewCell.swift; sourceTree = ""; }; - 4C1D2337218B6BA000A0598F /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = translations/it.lproj/Localizable.strings; sourceTree = ""; }; + 4C1D2337218B6BA000A0598F /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = ""; }; 4C21D5D5223A9DC500EF8A77 /* UIAlerts+iOS9.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIAlerts+iOS9.m"; sourceTree = ""; }; 4C21D5D7223AC60F00EF8A77 /* PhotoCapture.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoCapture.swift; sourceTree = ""; }; 4C2F454E214C00E1004871FF /* AvatarTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AvatarTableViewCell.swift; sourceTree = ""; }; - 4C3EF7FC2107DDEE0007EBF7 /* ParamParserTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParamParserTest.swift; sourceTree = ""; }; - 4C3EF801210918740007EBF7 /* SSKProtoEnvelopeTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SSKProtoEnvelopeTest.swift; sourceTree = ""; }; 4C4AE69F224AF21900D4AF6F /* SendMediaNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendMediaNavigationController.swift; sourceTree = ""; }; 4C4AEC4420EC343B0020E72B /* DismissableTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DismissableTextField.swift; sourceTree = ""; }; - 4C586924224FAB83003FD070 /* AVAudioSession+OWS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "AVAudioSession+OWS.h"; path = "util/UI Categories/AVAudioSession+OWS.h"; sourceTree = ""; }; - 4C586925224FAB83003FD070 /* AVAudioSession+OWS.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = "AVAudioSession+OWS.m"; path = "util/UI Categories/AVAudioSession+OWS.m"; sourceTree = ""; }; + 4C586924224FAB83003FD070 /* AVAudioSession+OWS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "AVAudioSession+OWS.h"; sourceTree = ""; }; + 4C586925224FAB83003FD070 /* AVAudioSession+OWS.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "AVAudioSession+OWS.m"; sourceTree = ""; }; 4C61819E219E1795009BD6B5 /* typing-animation-dark.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = "typing-animation-dark.gif"; sourceTree = ""; }; 4C63CBFF210A620B003AE45C /* SignalTSan.supp */ = {isa = PBXFileReference; lastKnownFileType = text; path = SignalTSan.supp; sourceTree = ""; }; 4C6F527B20FFE8400097DEEE /* SignalUBSan.supp */ = {isa = PBXFileReference; lastKnownFileType = text; path = SignalUBSan.supp; sourceTree = ""; }; @@ -1670,7 +1594,7 @@ 4CEB78C72178EBAB00F315D2 /* OWSSessionResetJobRecord.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OWSSessionResetJobRecord.h; sourceTree = ""; }; 4CEB78C82178EBAB00F315D2 /* OWSSessionResetJobRecord.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OWSSessionResetJobRecord.m; sourceTree = ""; }; 4CFD151C22415AA400F2450F /* CallVideoHintView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallVideoHintView.swift; sourceTree = ""; }; - 4CFE6B6B21F92BA700006701 /* LegacyNotificationsAdaptee.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LegacyNotificationsAdaptee.swift; path = UserInterface/Notifications/LegacyNotificationsAdaptee.swift; sourceTree = ""; }; + 4CFE6B6B21F92BA700006701 /* LegacyNotificationsAdaptee.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyNotificationsAdaptee.swift; sourceTree = ""; }; 4CFF4C0920F55BBA005DA313 /* MenuActionsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuActionsViewController.swift; sourceTree = ""; }; 53D547348A367C8A14D37FC0 /* Pods_SignalUtilitiesKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SignalUtilitiesKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 5F3070F3395081DD0EB4F933 /* Pods-SignalUtilitiesKit.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SignalUtilitiesKit.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SignalUtilitiesKit/Pods-SignalUtilitiesKit.debug.xcconfig"; sourceTree = ""; }; @@ -1702,7 +1626,7 @@ A1C32D4D17A0652C000A904E /* AddressBook.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AddressBook.framework; path = System/Library/Frameworks/AddressBook.framework; sourceTree = SDKROOT; }; A1C32D4F17A06537000A904E /* AddressBookUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AddressBookUI.framework; path = System/Library/Frameworks/AddressBookUI.framework; sourceTree = SDKROOT; }; A1FDCBEE16DAA6C300868894 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; }; - A5509EC91A69AB8B00ABA4BC /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = Main.storyboard; path = Storyboard/Main.storyboard; sourceTree = ""; }; + A5509EC91A69AB8B00ABA4BC /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; }; A6344D429FFAC3B44E6A06FA /* Pods-SessionSnodeKit.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SessionSnodeKit.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SessionSnodeKit/Pods-SessionSnodeKit.debug.xcconfig"; sourceTree = ""; }; AD2AB1207E8888E4262D781B /* Pods-SignalTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SignalTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SignalTests/Pods-SignalTests.debug.xcconfig"; sourceTree = ""; }; AD83FF381A73426500B5C81A /* audio_pause_button_blue.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = audio_pause_button_blue.png; sourceTree = ""; }; @@ -1727,24 +1651,17 @@ B633C5421A1D190B0059AC12 /* mute_on@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "mute_on@2x.png"; sourceTree = ""; }; B633C54C1A1D190B0059AC12 /* quit@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "quit@2x.png"; sourceTree = ""; }; B633C5501A1D190B0059AC12 /* savephoto@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "savephoto@2x.png"; sourceTree = ""; }; - B646D10E1AA5461A004133BA /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = translations/fr.lproj/Localizable.strings; sourceTree = ""; }; - B657DDC91911A40500F45B0C /* Signal.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = Signal.entitlements; sourceTree = ""; }; - B660F69E1C29868000687D6E /* SignalTests-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "SignalTests-Info.plist"; sourceTree = ""; }; - B660F69F1C29868000687D6E /* whisperFake.cer */ = {isa = PBXFileReference; lastKnownFileType = file; path = whisperFake.cer; sourceTree = ""; }; - B660F6A01C29868000687D6E /* TestUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TestUtil.h; sourceTree = ""; }; - B660F6AD1C29868000687D6E /* FunctionalUtilTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FunctionalUtilTest.m; sourceTree = ""; }; - B660F6B31C29868000687D6E /* UtilTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UtilTest.h; sourceTree = ""; }; - B660F6B41C29868000687D6E /* UtilTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UtilTest.m; sourceTree = ""; }; + B646D10E1AA5461A004133BA /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = ""; }; + B657DDC91911A40500F45B0C /* Signal.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Signal.entitlements; sourceTree = ""; }; B66DBF4919D5BBC8006EA940 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; - B676BCEF1AA544E7009637B8 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = translations/de.lproj/Localizable.strings; sourceTree = ""; }; - B676BCF11AA5451E009637B8 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = translations/es.lproj/Localizable.strings; sourceTree = ""; }; - B67EBF5C19194AC60084CCFD /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; name = Settings.bundle; path = SettingsBundle/Settings.bundle; sourceTree = SOURCE_ROOT; }; - B68CB7DC1AA547100065AC3F /* pt_BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pt_BR; path = translations/pt_BR.lproj/Localizable.strings; sourceTree = ""; }; - B68CB7E01AA548420065AC3F /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = translations/ru.lproj/Localizable.strings; sourceTree = ""; }; - B68CB7E61AA548870065AC3F /* zh_CN */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = zh_CN; path = translations/zh_CN.lproj/Localizable.strings; sourceTree = ""; }; + B676BCEF1AA544E7009637B8 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = ""; }; + B676BCF11AA5451E009637B8 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = ""; }; + B67EBF5C19194AC60084CCFD /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; name = Settings.bundle; path = Session/Meta/Settings.bundle; sourceTree = SOURCE_ROOT; }; + B68CB7DC1AA547100065AC3F /* pt_BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pt_BR; path = pt_BR.lproj/Localizable.strings; sourceTree = ""; }; + B68CB7E01AA548420065AC3F /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = ""; }; + B68CB7E61AA548870065AC3F /* zh_CN */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = zh_CN; path = zh_CN.lproj/Localizable.strings; sourceTree = ""; }; B69CD25019773E79005CE69A /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; B6B226961BE4B7D200860F4D /* ContactsUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ContactsUI.framework; path = System/Library/Frameworks/ContactsUI.framework; sourceTree = SDKROOT; }; - B6F509961AA53F760068F56A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = translations/en.lproj/Localizable.strings; sourceTree = ""; }; B6FE7EB61ADD62FA00A6D22F /* PushKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PushKit.framework; path = System/Library/Frameworks/PushKit.framework; sourceTree = SDKROOT; }; B80A579E23DFF1F300876683 /* NewClosedGroupVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewClosedGroupVC.swift; sourceTree = ""; }; B80C6B562384A56D00FDBC8B /* DeviceLinksVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceLinksVC.swift; sourceTree = ""; }; @@ -1776,7 +1693,6 @@ B886B4A62398B23E00211ABE /* QRCodeVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeVC.swift; sourceTree = ""; }; B886B4A82398BA1500211ABE /* QRCode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCode.swift; sourceTree = ""; }; B88847BB23E10BC6009836D2 /* GroupMembersVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupMembersVC.swift; sourceTree = ""; }; - B891105B2320872800F15FCC /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; B893063E2383961A005EAA8E /* ScanQRCodeWrapperVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanQRCodeWrapperVC.swift; sourceTree = ""; }; B894D0702339D6F300B4D94D /* DeviceLinkingModalDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceLinkingModalDelegate.swift; sourceTree = ""; }; B894D0742339EDCF00B4D94D /* NukeDataModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NukeDataModal.swift; sourceTree = ""; }; @@ -2468,10 +2384,10 @@ C38EF3ED255B6DF6007E1867 /* TappableStackView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TappableStackView.swift; path = SignalUtilitiesKit/TappableStackView.swift; sourceTree = SOURCE_ROOT; }; C38EF3EE255B6DF6007E1867 /* GradientView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GradientView.swift; path = SignalUtilitiesKit/GradientView.swift; sourceTree = SOURCE_ROOT; }; C38EF458255B710A007E1867 /* SignalUtilitiesKit-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SignalUtilitiesKit-Prefix.pch"; sourceTree = ""; }; - C396469C2509D3ED00B0B9F5 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = translations/pl.lproj/Localizable.strings; sourceTree = ""; }; - C396469D2509D3F400B0B9F5 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = translations/ja.lproj/Localizable.strings; sourceTree = ""; }; - C396469E2509D40400B0B9F5 /* vi-VN */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "vi-VN"; path = "translations/vi-VN.lproj/Localizable.strings"; sourceTree = ""; }; - C396469F2509D41100B0B9F5 /* id-ID */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "id-ID"; path = "translations/id-ID.lproj/Localizable.strings"; sourceTree = ""; }; + C396469C2509D3ED00B0B9F5 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Localizable.strings; sourceTree = ""; }; + C396469D2509D3F400B0B9F5 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = ""; }; + C396469E2509D40400B0B9F5 /* vi-VN */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "vi-VN"; path = "vi-VN.lproj/Localizable.strings"; sourceTree = ""; }; + C396469F2509D41100B0B9F5 /* id-ID */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "id-ID"; path = "id-ID.lproj/Localizable.strings"; sourceTree = ""; }; C396DAE82518408900FF6DC5 /* ParsingState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParsingState.swift; sourceTree = ""; }; C396DAE92518408A00FF6DC5 /* String+Lines.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+Lines.swift"; sourceTree = ""; }; C396DAEA2518408A00FF6DC5 /* EnumeratedView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnumeratedView.swift; sourceTree = ""; }; @@ -2514,8 +2430,8 @@ C3A7227F2558C4E10043A11F /* AttachmentStream.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttachmentStream.swift; sourceTree = ""; }; C3A722912558C8940043A11F /* OpenGroupAPIDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenGroupAPIDelegate.swift; sourceTree = ""; }; C3A7229B2558E4310043A11F /* OpenGroupMessage+Conversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OpenGroupMessage+Conversion.swift"; sourceTree = ""; }; - C3AA6BB824CE8F1B002358B6 /* Migrating Translations from Android.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = "Migrating Translations from Android.md"; sourceTree = ""; }; - C3AECBEA24EF5244005743DE /* fa */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fa; path = translations/fa.lproj/Localizable.strings; sourceTree = ""; }; + C3AA6BB824CE8F1B002358B6 /* Migrating Translations from Android.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; name = "Migrating Translations from Android.md"; path = "Meta/Translations/Migrating Translations from Android.md"; sourceTree = ""; }; + C3AECBEA24EF5244005743DE /* fa */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fa; path = fa.lproj/Localizable.strings; sourceTree = ""; }; C3BBE0752554CDA60050F1E3 /* Configuration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Configuration.swift; sourceTree = ""; }; C3BBE07F2554CDD70050F1E3 /* Storage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Storage.swift; sourceTree = ""; }; C3BBE0B42554F0E10050F1E3 /* ProofOfWork.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProofOfWork.swift; sourceTree = ""; }; @@ -2662,6 +2578,7 @@ C3E5C2F9251DBABB0040DFFC /* EditClosedGroupVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditClosedGroupVC.swift; sourceTree = ""; }; C3E7134E251C867C009649BB /* Sodium+Conversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Sodium+Conversion.swift"; sourceTree = ""; }; C3F0A52F255C80BC007BE2A3 /* NoopNotificationsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoopNotificationsManager.swift; sourceTree = ""; }; + C3F0A5B2255C915C007BE2A3 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; C88965DE4F4EC4FC919BEC4E /* Pods-SessionUIKit.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SessionUIKit.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SessionUIKit/Pods-SessionUIKit.debug.xcconfig"; sourceTree = ""; }; CB3724C70247A916D43271FE /* Pods_Session.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Session.framework; sourceTree = BUILT_PRODUCTS_DIR; }; D2179CFB16BB0B3A0006F3AB /* CoreTelephony.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreTelephony.framework; path = System/Library/Frameworks/CoreTelephony.framework; sourceTree = SDKROOT; }; @@ -2682,8 +2599,8 @@ E1A0AD8B16E13FDD0071E604 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; E7E2FBF1546840C91B7E4879 /* Pods-SessionUtilities.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SessionUtilities.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SessionUtilities/Pods-SessionUtilities.debug.xcconfig"; sourceTree = ""; }; E85DB184824BA9DC302EC8B3 /* Pods-SignalTests.app store release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SignalTests.app store release.xcconfig"; path = "Pods/Target Support Files/Pods-SignalTests/Pods-SignalTests.app store release.xcconfig"; sourceTree = ""; }; - EF764C331DB67CC5000D9A87 /* UIViewController+Permissions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIViewController+Permissions.h"; path = "util/UIViewController+Permissions.h"; sourceTree = ""; }; - EF764C341DB67CC5000D9A87 /* UIViewController+Permissions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIViewController+Permissions.m"; path = "util/UIViewController+Permissions.m"; sourceTree = ""; }; + EF764C331DB67CC5000D9A87 /* UIViewController+Permissions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIViewController+Permissions.h"; sourceTree = ""; }; + EF764C341DB67CC5000D9A87 /* UIViewController+Permissions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIViewController+Permissions.m"; sourceTree = ""; }; F121FB43E2A1C1CF7F2AFC23 /* Pods-SessionPushNotificationExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SessionPushNotificationExtension.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SessionPushNotificationExtension/Pods-SessionPushNotificationExtension.debug.xcconfig"; sourceTree = ""; }; F62ECF7B8AF4F8089AA705B3 /* Pods-LokiPushNotificationService.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LokiPushNotificationService.debug.xcconfig"; path = "Pods/Target Support Files/Pods-LokiPushNotificationService/Pods-LokiPushNotificationService.debug.xcconfig"; sourceTree = ""; }; F9BBF530D71905BA9007675F /* Pods-SessionShareExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SessionShareExtension.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SessionShareExtension/Pods-SessionShareExtension.debug.xcconfig"; sourceTree = ""; }; @@ -2865,76 +2782,17 @@ 45B74A722044AAB600CD42F8 /* synth.aifc */, ); name = messageReceivedSounds; - path = Session/AudioFiles/messageReceivedSounds; + path = Session/Meta/AudioFiles/messageReceivedSounds; sourceTree = SOURCE_ROOT; }; - 340FC875204DAC8C007AEB0F /* Registration */ = { - isa = PBXGroup; - children = ( - 3441FD9E21A3604F00BB9542 /* BackupRestoreViewController.swift */, - 3448E1652215B313004B052E /* OnboardingCaptchaViewController.swift */, - ); - path = Registration; - sourceTree = ""; - }; - 340FC87A204DAC8C007AEB0F /* AppSettings */ = { - isa = PBXGroup; - children = ( - 340FC884204DAC8C007AEB0F /* AboutTableViewController.h */, - 340FC893204DAC8C007AEB0F /* AboutTableViewController.m */, - 340FC892204DAC8C007AEB0F /* AddToBlockListViewController.h */, - 340FC886204DAC8C007AEB0F /* AddToBlockListViewController.m */, - 340FC881204DAC8C007AEB0F /* AdvancedSettingsTableViewController.h */, - 340FC88C204DAC8C007AEB0F /* AdvancedSettingsTableViewController.m */, - 340FC890204DAC8C007AEB0F /* BlockListViewController.h */, - 340FC887204DAC8C007AEB0F /* BlockListViewController.m */, - 340FC889204DAC8C007AEB0F /* DomainFrontingCountryViewController.h */, - 340FC87D204DAC8C007AEB0F /* DomainFrontingCountryViewController.m */, - 340FC88B204DAC8C007AEB0F /* NotificationSettingsOptionsViewController.h */, - 340FC87B204DAC8C007AEB0F /* NotificationSettingsOptionsViewController.m */, - 340FC88A204DAC8C007AEB0F /* NotificationSettingsViewController.h */, - 340FC87C204DAC8C007AEB0F /* NotificationSettingsViewController.m */, - 340FC87F204DAC8C007AEB0F /* OWSBackupSettingsViewController.h */, - 340FC88E204DAC8C007AEB0F /* OWSBackupSettingsViewController.m */, - 340FC888204DAC8C007AEB0F /* OWSQRCodeScanningViewController.h */, - 340FC896204DAC8C007AEB0F /* OWSQRCodeScanningViewController.m */, - 340FC894204DAC8C007AEB0F /* OWSSoundSettingsViewController.h */, - 340FC883204DAC8C007AEB0F /* OWSSoundSettingsViewController.m */, - 340FC88F204DAC8C007AEB0F /* PrivacySettingsTableViewController.h */, - 340FC87E204DAC8C007AEB0F /* PrivacySettingsTableViewController.m */, - ); - path = AppSettings; - sourceTree = ""; - }; - 340FC897204DAC8D007AEB0F /* ThreadSettings */ = { - isa = PBXGroup; - children = ( - 340FC8A4204DAC8D007AEB0F /* AddToGroupViewController.h */, - 340FC89B204DAC8D007AEB0F /* AddToGroupViewController.m */, - 340FC89D204DAC8D007AEB0F /* FingerprintViewController.h */, - 340FC8A2204DAC8D007AEB0F /* FingerprintViewController.m */, - 340FC8A5204DAC8D007AEB0F /* FingerprintViewScanController.h */, - 340FC89F204DAC8D007AEB0F /* FingerprintViewScanController.m */, - 340FC898204DAC8D007AEB0F /* OWSAddToContactViewController.h */, - 340FC8A1204DAC8D007AEB0F /* OWSAddToContactViewController.m */, - 340FC8A0204DAC8D007AEB0F /* OWSConversationSettingsViewController.h */, - 340FC89A204DAC8D007AEB0F /* OWSConversationSettingsViewController.m */, - 340FC899204DAC8D007AEB0F /* OWSConversationSettingsViewDelegate.h */, - 340FC89E204DAC8D007AEB0F /* ShowGroupMembersViewController.h */, - 340FC8A6204DAC8D007AEB0F /* ShowGroupMembersViewController.m */, - 340FC8A3204DAC8D007AEB0F /* UpdateGroupViewController.h */, - 340FC89C204DAC8D007AEB0F /* UpdateGroupViewController.m */, - ); - path = ThreadSettings; - sourceTree = ""; - }; 34330A581E7875FB00DF2FB9 /* Fonts */ = { isa = PBXGroup; children = ( 34330A5B1E787A9800DF2FB9 /* dripicons-v2.ttf */, 34330A5D1E787BD800DF2FB9 /* ElegantIcons.ttf */, 34330A591E7875FB00DF2FB9 /* fontawesome-webfont.ttf */, - B8BB82BA2394D47000BA5194 /* Loki */, + B8CCF6342396005F0091D419 /* SpaceMono-Regular.ttf */, + C34C8F7323A7830A00D82669 /* SpaceMono-Bold.ttf */, ); path = Fonts; sourceTree = ""; @@ -2966,149 +2824,15 @@ path = ConversationView; sourceTree = ""; }; - 34843B29214FE295004DED45 /* mocks */ = { - isa = PBXGroup; - children = ( - 34843B2B214FE295004DED45 /* MockEnvironment.h */, - 34843B2A214FE295004DED45 /* MockEnvironment.m */, - ); - path = mocks; - sourceTree = ""; - }; - 34969558219B605E00DCFE74 /* Photos */ = { - isa = PBXGroup; - children = ( - 4C4AE69F224AF21900D4AF6F /* SendMediaNavigationController.swift */, - 34969559219B605E00DCFE74 /* ImagePickerController.swift */, - 3496955A219B605E00DCFE74 /* PhotoCollectionPickerController.swift */, - 3496955B219B605E00DCFE74 /* PhotoLibrary.swift */, - 4CA485BA2232339F004B9E7D /* PhotoCaptureViewController.swift */, - 4C21D5D7223AC60F00EF8A77 /* PhotoCapture.swift */, - ); - path = Photos; - sourceTree = ""; - }; - 3496956121A301A100DCFE74 /* Backup */ = { - isa = PBXGroup; - children = ( - 3496956421A301A100DCFE74 /* OWSBackup.h */, - 3496956921A301A100DCFE74 /* OWSBackup.m */, - 3496956B21A301A100DCFE74 /* OWSBackupAPI.swift */, - 3496956821A301A100DCFE74 /* OWSBackupExportJob.h */, - 3496956221A301A100DCFE74 /* OWSBackupExportJob.m */, - 3496956C21A301A100DCFE74 /* OWSBackupImportJob.h */, - 3496956621A301A100DCFE74 /* OWSBackupImportJob.m */, - 3496956D21A301A100DCFE74 /* OWSBackupIO.h */, - 3496956521A301A100DCFE74 /* OWSBackupIO.m */, - 3496956721A301A100DCFE74 /* OWSBackupJob.h */, - 3496956A21A301A100DCFE74 /* OWSBackupJob.m */, - 3496956321A301A100DCFE74 /* OWSBackupLazyRestore.swift */, - ); - path = Backup; - sourceTree = ""; - }; - 34B3F8331E8DF1700035BE1A /* ViewControllers */ = { - isa = PBXGroup; - children = ( - 4CFD151B22415A6C00F2450F /* Call */, - 452B998F20A34B6B006F2F9E /* AddContactShareToExistingContactViewController.swift */, - 340FC87A204DAC8C007AEB0F /* AppSettings */, - 34D5CCA71EAE3D30005515DB /* AvatarViewHelper.h */, - 34D5CCA81EAE3D30005515DB /* AvatarViewHelper.m */, - 4C13C9F520E57BA30089A98B /* ColorPickerViewController.swift */, - 348BB25C20A0C5530047AEC2 /* ContactShareViewHelper.swift */, - 34B3F83E1E8DF1700035BE1A /* ContactsPicker.swift */, - 34E88D252098C5AE00A608F4 /* ContactViewController.swift */, - 3448BFC01EDF0EA7005B2D69 /* ConversationView */, - 346B66301F4E29B200E5122F /* CropScaleImageViewController.swift */, - 34D8C0221ED3673300188D7C /* DebugUI */, - 34BECE2C1F7ABCE000D7438D /* GifPicker */, - 34B3F84C1E8DF1700035BE1A /* InviteFlow.swift */, - 4542DF53208D40AC007B4E76 /* LoadingViewController.swift */, - 3496744E2076ACCE00080B5F /* LongTextViewController.swift */, - 45B9EE9A200E91FB005D2F2D /* MediaDetailViewController.h */, - 45B9EE9B200E91FB005D2F2D /* MediaDetailViewController.m */, - 452EC6DE205E9E30000E787C /* MediaGalleryViewController.swift */, - 45F32C1D205718B000A300D5 /* MediaPageViewController.swift */, - 454A84032059C787008B8C75 /* MediaTileViewController.swift */, - 4CFF4C0920F55BBA005DA313 /* MenuActionsViewController.swift */, - 34CA1C261F7156F300E51C51 /* MessageDetailViewController.swift */, - 34A6C27F21E503E600B5B12E /* OWSImagePickerController.swift */, - 34969558219B605E00DCFE74 /* Photos */, - 340FC875204DAC8C007AEB0F /* Registration */, - 4585C4671ED8F8D200896AEA /* SafetyNumberConfirmationAlert.swift */, - 34B3F86D1E8DF1700035BE1A /* SignalsNavigationController.h */, - 34B3F86E1E8DF1700035BE1A /* SignalsNavigationController.m */, - 340FC897204DAC8D007AEB0F /* ThreadSettings */, - 34D1F0BE1F8EC1760066283D /* Utils */, - ); - path = ViewControllers; - sourceTree = ""; - }; - 34B3F8951E8DF1B90035BE1A /* ViewControllers */ = { - isa = PBXGroup; - children = ( - 340B02B91FA0D6C700F9CFEC /* ConversationViewItemTest.m */, - ); - path = ViewControllers; - sourceTree = ""; - }; - 34BBC85E220E883200857249 /* ImageEditor */ = { - isa = PBXGroup; - children = ( - 34BBC85F220E883200857249 /* ImageEditorModelTest.swift */, - 34BBC860220E883200857249 /* ImageEditorTest.swift */, - ); - path = ImageEditor; - sourceTree = ""; - }; - 34BECE2C1F7ABCE000D7438D /* GifPicker */ = { - isa = PBXGroup; - children = ( - 34D1F04F1F7D45A60066283D /* GifPickerCell.swift */, - 34BECE2F1F7ABCF800D7438D /* GifPickerLayout.swift */, - 34BECE2D1F7ABCE000D7438D /* GifPickerViewController.swift */, - ); - path = GifPicker; - sourceTree = ""; - }; - 34BEDB0F21C41E71007B0EAE /* views */ = { - isa = PBXGroup; - children = ( - 34BBC85E220E883200857249 /* ImageEditor */, - ); - path = views; - sourceTree = ""; - }; 34C3C78B20409F320000134C /* ringtoneSounds */ = { isa = PBXGroup; children = ( 34C3C78C20409F320000134C /* Opening.m4r */, ); name = ringtoneSounds; - path = Session/AudioFiles/ringtoneSounds; + path = Session/Meta/AudioFiles/ringtoneSounds; sourceTree = SOURCE_ROOT; }; - 34C4E2542118957600BEA353 /* Generated */ = { - isa = PBXGroup; - children = ( - 34C4E2552118957600BEA353 /* OWSWebRTCDataProtos.pb.swift */, - 34C4E2562118957600BEA353 /* WebRTCProto.swift */, - ); - path = Generated; - sourceTree = ""; - }; - 34C6B0A41FA0E46F00D35993 /* Assets */ = { - isa = PBXGroup; - children = ( - 34C6B0A51FA0E46F00D35993 /* test-gif.gif */, - 34C6B0AD1FA0E4AA00D35993 /* test-jpg.jpg */, - 34C6B0A71FA0E46F00D35993 /* test-mp3.mp3 */, - 34C6B0A81FA0E46F00D35993 /* test-mp4.mp4 */, - ); - path = Assets; - sourceTree = ""; - }; 34D1F0951F867BFC0066283D /* Cells */ = { isa = PBXGroup; children = ( @@ -3155,83 +2879,6 @@ path = Cells; sourceTree = ""; }; - 34D1F0BE1F8EC1760066283D /* Utils */ = { - isa = PBXGroup; - children = ( - 34D1F0BF1F8EC1760066283D /* MessageRecipientStatusUtils.swift */, - ); - path = Utils; - sourceTree = ""; - }; - 34D8C0221ED3673300188D7C /* DebugUI */ = { - isa = PBXGroup; - children = ( - 34DC9BD821543E0B00FDDCEC /* DebugContactsUtils.h */, - 34DC9BD721543E0A00FDDCEC /* DebugContactsUtils.m */, - 340FC8C3204DE223007AEB0F /* DebugUIBackup.h */, - 340FC8C4204DE223007AEB0F /* DebugUIBackup.m */, - 45638BDB1F3DD0D400128435 /* DebugUICalling.swift */, - 34D8C0291ED3685800188D7C /* DebugUIContacts.h */, - 34D8C02A1ED3685800188D7C /* DebugUIContacts.m */, - 34E3EF0B1EFC235B007F6822 /* DebugUIDiskUsage.h */, - 34E3EF0C1EFC235B007F6822 /* DebugUIDiskUsage.m */, - 45B27B852037FFB400A539DF /* DebugUIFileBrowser.swift */, - 34D8C0231ED3673300188D7C /* DebugUIMessages.h */, - 34D8C0241ED3673300188D7C /* DebugUIMessages.m */, - 34D2CCDD206939B200CB1A14 /* DebugUIMessagesAction.h */, - 34D2CCDB206939B100CB1A14 /* DebugUIMessagesAction.m */, - 34D2CCDE206939B400CB1A14 /* DebugUIMessagesAssetLoader.h */, - 34D2CCDC206939B200CB1A14 /* DebugUIMessagesAssetLoader.m */, - 34D2CCE220693A1700CB1A14 /* DebugUIMessagesUtils.h */, - 341F2C0D1F2B8AE700D07D6B /* DebugUIMisc.h */, - 341F2C0E1F2B8AE700D07D6B /* DebugUIMisc.m */, - 457C87B72032645C008D52D6 /* DebugUINotifications.swift */, - 34E3EF0E1EFC2684007F6822 /* DebugUIPage.h */, - 34E3EF0F1EFC2684007F6822 /* DebugUIPage.m */, - 4556FA671F54AA9500AF40DD /* DebugUIProfile.swift */, - 452037CF1EE84975004E4CDF /* DebugUISessionState.h */, - 452037D01EE84975004E4CDF /* DebugUISessionState.m */, - 34BECE291F74C12700D7438D /* DebugUIStress.h */, - 34BECE2A1F74C12700D7438D /* DebugUIStress.m */, - 343A65931FC47D5D000477A1 /* DebugUISyncMessages.h */, - 343A65941FC47D5E000477A1 /* DebugUISyncMessages.m */, - 34D8C0251ED3673300188D7C /* DebugUITableViewController.h */, - 34D8C0261ED3673300188D7C /* DebugUITableViewController.m */, - ); - path = DebugUI; - sourceTree = ""; - }; - 4505C2BD1E648E6E00CEBF41 /* ExperienceUpgrades */ = { - isa = PBXGroup; - children = ( - 4505C2BE1E648EA300CEBF41 /* ExperienceUpgrade.swift */, - 3461293D1FD1D72B00532771 /* ExperienceUpgradeFinder.swift */, - ); - name = ExperienceUpgrades; - sourceTree = ""; - }; - 450DF2061E0DD28D003D14BE /* UserInterface */ = { - isa = PBXGroup; - children = ( - 450DF2071E0DD29E003D14BE /* Notifications */, - 4C090A1A210FD9C7001FD7F9 /* HapticFeedback.swift */, - 34B3F8331E8DF1700035BE1A /* ViewControllers */, - 76EB052B18170B33006006FC /* Views */, - 4CC613352227A00400E21A3A /* ConversationSearch.swift */, - ); - name = UserInterface; - sourceTree = ""; - }; - 450DF2071E0DD29E003D14BE /* Notifications */ = { - isa = PBXGroup; - children = ( - 451A13B01E13DED2000A50FD /* AppNotifications.swift */, - 450DF2081E0DD2C6003D14BE /* UserNotificationsAdaptee.swift */, - 4CFE6B6B21F92BA700006701 /* LegacyNotificationsAdaptee.swift */, - ); - name = Notifications; - sourceTree = ""; - }; 453518691FC635DD00210559 /* SessionShareExtension */ = { isa = PBXGroup; children = ( @@ -3248,177 +2895,114 @@ path = SessionShareExtension; sourceTree = ""; }; - 45464DB81DFA03D8001D3FD6 /* Signaling */ = { - isa = PBXGroup; - children = ( - 45C9DEB71DF4E35A0065CA84 /* WebRTCCallMessageHandler.swift */, - 45AE48501E0732D6004D96C2 /* TurnServerInfo.swift */, - ); - name = Signaling; - sourceTree = ""; - }; - 45794E841E0061CF00066731 /* UserInterface */ = { - isa = PBXGroup; - children = ( - 45FBC57A1DF8575700E9B410 /* CallKit */, - 45794E851E00620000066731 /* CallUIAdapter.swift */, - 45F659811E1BE77000444429 /* NonCallKitCallUIAdaptee.swift */, - ); - name = UserInterface; - sourceTree = ""; - }; - 457F3AC01D14A0F700C51351 /* Models */ = { - isa = PBXGroup; - children = ( - 451166BF1FD86B98000739BA /* AccountManager.swift */, - 45DF5DF11DDB843F00C936C7 /* CompareSafetyNumbersActivity.swift */, - 458E38351D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.h */, - 458E38361D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m */, - 4CB5F26820F7D060004D1B42 /* MessageActions.swift */, - ); - path = Models; - sourceTree = ""; - }; - 458E38381D6699110094BD24 /* Models */ = { - isa = PBXGroup; - children = ( - 4C04F58321C860C50090D0BB /* MantlePerfTest.swift */, - 458E38391D6699FA0094BD24 /* OWSDeviceProvisioningURLParserTest.m */, - ); - name = Models; - sourceTree = ""; - }; - 45CD81A41DBFF8CF004C9430 /* Storyboards */ = { - isa = PBXGroup; - children = ( - 45CB2FA71CB7146C00E1B343 /* Launch Screen.storyboard */, - A5509EC91A69AB8B00ABA4BC /* Main.storyboard */, - ); - name = Storyboards; - sourceTree = ""; - }; - 45D231751DC7E8C50034FA89 /* Jobs */ = { - isa = PBXGroup; - children = ( - 45D231761DC7E8F10034FA89 /* SessionResetJob.swift */, - 45CD81EE1DC030E7004C9430 /* SyncPushTokensJob.swift */, - 452ECA4C1E087E7200E2F016 /* MessageFetcherJob.swift */, - 4CC0B59B20EC5F2E00CF6EE0 /* ConversationConfigurationSyncOperation.swift */, - 4CEB78C72178EBAB00F315D2 /* OWSSessionResetJobRecord.h */, - 4CEB78C82178EBAB00F315D2 /* OWSSessionResetJobRecord.m */, - ); - path = Jobs; - sourceTree = ""; - }; - 45FBC57A1DF8575700E9B410 /* CallKit */ = { - isa = PBXGroup; - children = ( - 45FBC59A1DF8575700E9B410 /* CallKitCallManager.swift */, - 45F659721E1BD99C00444429 /* CallKitCallUIAdaptee.swift */, - ); - name = CallKit; - path = Speakerbox; - sourceTree = ""; - }; - 4C3EF8002109184A0007EBF7 /* SSKTests */ = { - isa = PBXGroup; - children = ( - 4C3EF7FC2107DDEE0007EBF7 /* ParamParserTest.swift */, - 4C3EF801210918740007EBF7 /* SSKProtoEnvelopeTest.swift */, - ); - path = SSKTests; - sourceTree = ""; - }; - 4CFD151B22415A6C00F2450F /* Call */ = { - isa = PBXGroup; - children = ( - 34B3F83B1E8DF1700035BE1A /* CallViewController.swift */, - 4CFD151C22415AA400F2450F /* CallVideoHintView.swift */, - ); - path = Call; - sourceTree = ""; - }; - 76EB03C118170B33006006FC /* src */ = { + 76EB03C118170B33006006FC /* Signal */ = { isa = PBXGroup; children = ( 76EB03C218170B33006006FC /* AppDelegate.h */, 76EB03C318170B33006006FC /* AppDelegate.m */, - 76EB03FE18170B33006006FC /* call */, - 76EB041118170B33006006FC /* environment */, - 34C4E2542118957600BEA353 /* Generated */, - 45D231751DC7E8C50034FA89 /* Jobs */, - B8439518228510E9000563FE /* Loki */, - 457F3AC01D14A0F700C51351 /* Models */, - 76EB041D18170B33006006FC /* network */, - 45B201741DAECBFD00C461E0 /* Signal-Bridging-Header.h */, - 45CD81A41DBFF8CF004C9430 /* Storyboards */, - 450DF2061E0DD28D003D14BE /* UserInterface */, - 76EB04C818170B33006006FC /* util */, - ); - path = src; - sourceTree = ""; - }; - 76EB03FE18170B33006006FC /* call */ = { - isa = PBXGroup; - children = ( - 45794E841E0061CF00066731 /* UserInterface */, - 45464DB81DFA03D8001D3FD6 /* Signaling */, + 45FBC59A1DF8575700E9B410 /* CallKitCallManager.swift */, + 45F659721E1BD99C00444429 /* CallKitCallUIAdaptee.swift */, + 45794E851E00620000066731 /* CallUIAdapter.swift */, + 45F659811E1BE77000444429 /* NonCallKitCallUIAdaptee.swift */, + 45C9DEB71DF4E35A0065CA84 /* WebRTCCallMessageHandler.swift */, + 45AE48501E0732D6004D96C2 /* TurnServerInfo.swift */, 45FBC5D01DF8592E00E9B410 /* SignalCall.swift */, 458DE9D51DEE3FD00071BB03 /* PeerConnectionClient.swift */, 4574A5D51DD6704700C6B692 /* CallService.swift */, 45F170BA1E2FC5D3003FC1F2 /* CallAudioService.swift */, 452C468E1E427E200087B011 /* OutboundCallInitiator.swift */, - ); - path = call; - sourceTree = ""; - }; - 76EB041118170B33006006FC /* environment */ = { - isa = PBXGroup; - children = ( 34D99CE3217509C1000AFB39 /* AppEnvironment.swift */, - 4505C2BD1E648E6E00CEBF41 /* ExperienceUpgrades */, + 4505C2BE1E648EA300CEBF41 /* ExperienceUpgrade.swift */, + 3461293D1FD1D72B00532771 /* ExperienceUpgradeFinder.swift */, 4539B5851F79348F007141FF /* PushRegistrationManager.swift */, 346129981FD1E4DA00532771 /* SignalApp.h */, 346129971FD1E4D900532771 /* SignalApp.m */, - ); - path = environment; - sourceTree = ""; - }; - 76EB041D18170B33006006FC /* network */ = { - isa = PBXGroup; - children = ( + 34C4E2552118957600BEA353 /* OWSWebRTCDataProtos.pb.swift */, + 34C4E2562118957600BEA353 /* WebRTCProto.swift */, + 45D231761DC7E8F10034FA89 /* SessionResetJob.swift */, + 45CD81EE1DC030E7004C9430 /* SyncPushTokensJob.swift */, + 452ECA4C1E087E7200E2F016 /* MessageFetcherJob.swift */, + 45CB2FA71CB7146C00E1B343 /* Launch Screen.storyboard */, + A5509EC91A69AB8B00ABA4BC /* Main.storyboard */, 3430FE171F7751D4000EC51B /* GiphyAPI.swift */, 34D1F0511F7E8EA30066283D /* GiphyDownloader.swift */, - ); - path = network; - sourceTree = ""; - }; - 76EB04C818170B33006006FC /* util */ = { - isa = PBXGroup; - children = ( - 4CC1ECFA211A553000CC13BE /* AppUpdateNag.swift */, - 3496956121A301A100DCFE74 /* Backup */, - B90418E4183E9DD40038554A /* DateUtil.h */, - B90418E5183E9DD40038554A /* DateUtil.m */, - 34B0796C1FCF46B000E248C2 /* MainAppContext.h */, - 34B0796B1FCF46B000E248C2 /* MainAppContext.m */, - 34D99C911F2937CC00D284D6 /* OWSAnalytics.swift */, - 344825C4211390C700DB4BD8 /* OWSOrphanDataCleaner.h */, - 344825C5211390C800DB4BD8 /* OWSOrphanDataCleaner.m */, - 34D2CCD82062E7D000CB1A14 /* OWSScreenLockUI.h */, - 34D2CCD92062E7D000CB1A14 /* OWSScreenLockUI.m */, - 4579431C1E7C8CE9008ED0C0 /* Pastelog.h */, - 4579431D1E7C8CE9008ED0C0 /* Pastelog.m */, - 450DF2041E0D74AC003D14BE /* Platform.swift */, - 4521C3BF1F59F3BA00B4C582 /* TextFieldHelper.swift */, - FCFA64B11A24F29E0007FB87 /* UI Categories */, - ); - path = util; - sourceTree = ""; - }; - 76EB052B18170B33006006FC /* Views */ = { - isa = PBXGroup; - children = ( + 4CC0B59B20EC5F2E00CF6EE0 /* ConversationConfigurationSyncOperation.swift */, + 4CEB78C72178EBAB00F315D2 /* OWSSessionResetJobRecord.h */, + 4CEB78C82178EBAB00F315D2 /* OWSSessionResetJobRecord.m */, + 451166BF1FD86B98000739BA /* AccountManager.swift */, + 45DF5DF11DDB843F00C936C7 /* CompareSafetyNumbersActivity.swift */, + 458E38351D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.h */, + 458E38361D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m */, + 4CB5F26820F7D060004D1B42 /* MessageActions.swift */, + 451A13B01E13DED2000A50FD /* AppNotifications.swift */, + 450DF2081E0DD2C6003D14BE /* UserNotificationsAdaptee.swift */, + 4CFE6B6B21F92BA700006701 /* LegacyNotificationsAdaptee.swift */, + 4C090A1A210FD9C7001FD7F9 /* HapticFeedback.swift */, + 34B3F83B1E8DF1700035BE1A /* CallViewController.swift */, + 4CFD151C22415AA400F2450F /* CallVideoHintView.swift */, + 340FC884204DAC8C007AEB0F /* AboutTableViewController.h */, + 340FC893204DAC8C007AEB0F /* AboutTableViewController.m */, + 340FC892204DAC8C007AEB0F /* AddToBlockListViewController.h */, + 340FC886204DAC8C007AEB0F /* AddToBlockListViewController.m */, + 340FC881204DAC8C007AEB0F /* AdvancedSettingsTableViewController.h */, + 340FC88C204DAC8C007AEB0F /* AdvancedSettingsTableViewController.m */, + 340FC890204DAC8C007AEB0F /* BlockListViewController.h */, + 340FC887204DAC8C007AEB0F /* BlockListViewController.m */, + 340FC889204DAC8C007AEB0F /* DomainFrontingCountryViewController.h */, + 340FC87D204DAC8C007AEB0F /* DomainFrontingCountryViewController.m */, + 340FC88B204DAC8C007AEB0F /* NotificationSettingsOptionsViewController.h */, + 340FC87B204DAC8C007AEB0F /* NotificationSettingsOptionsViewController.m */, + 340FC88A204DAC8C007AEB0F /* NotificationSettingsViewController.h */, + 340FC87C204DAC8C007AEB0F /* NotificationSettingsViewController.m */, + 340FC87F204DAC8C007AEB0F /* OWSBackupSettingsViewController.h */, + 340FC88E204DAC8C007AEB0F /* OWSBackupSettingsViewController.m */, + 340FC888204DAC8C007AEB0F /* OWSQRCodeScanningViewController.h */, + 340FC896204DAC8C007AEB0F /* OWSQRCodeScanningViewController.m */, + 340FC894204DAC8C007AEB0F /* OWSSoundSettingsViewController.h */, + 340FC883204DAC8C007AEB0F /* OWSSoundSettingsViewController.m */, + 340FC88F204DAC8C007AEB0F /* PrivacySettingsTableViewController.h */, + 340FC87E204DAC8C007AEB0F /* PrivacySettingsTableViewController.m */, + 34D5CCA71EAE3D30005515DB /* AvatarViewHelper.h */, + 34D5CCA81EAE3D30005515DB /* AvatarViewHelper.m */, + 4C13C9F520E57BA30089A98B /* ColorPickerViewController.swift */, + 348BB25C20A0C5530047AEC2 /* ContactShareViewHelper.swift */, + 34B3F83E1E8DF1700035BE1A /* ContactsPicker.swift */, + 34E88D252098C5AE00A608F4 /* ContactViewController.swift */, + 346B66301F4E29B200E5122F /* CropScaleImageViewController.swift */, + 34D1F04F1F7D45A60066283D /* GifPickerCell.swift */, + 34BECE2F1F7ABCF800D7438D /* GifPickerLayout.swift */, + 34BECE2D1F7ABCE000D7438D /* GifPickerViewController.swift */, + 34B3F84C1E8DF1700035BE1A /* InviteFlow.swift */, + 4542DF53208D40AC007B4E76 /* LoadingViewController.swift */, + 3496744E2076ACCE00080B5F /* LongTextViewController.swift */, + 45B9EE9A200E91FB005D2F2D /* MediaDetailViewController.h */, + 45B9EE9B200E91FB005D2F2D /* MediaDetailViewController.m */, + 452EC6DE205E9E30000E787C /* MediaGalleryViewController.swift */, + 45F32C1D205718B000A300D5 /* MediaPageViewController.swift */, + 454A84032059C787008B8C75 /* MediaTileViewController.swift */, + 4CFF4C0920F55BBA005DA313 /* MenuActionsViewController.swift */, + 34CA1C261F7156F300E51C51 /* MessageDetailViewController.swift */, + 452B998F20A34B6B006F2F9E /* AddContactShareToExistingContactViewController.swift */, + 4C4AE69F224AF21900D4AF6F /* SendMediaNavigationController.swift */, + 34969559219B605E00DCFE74 /* ImagePickerController.swift */, + 3496955A219B605E00DCFE74 /* PhotoCollectionPickerController.swift */, + 3496955B219B605E00DCFE74 /* PhotoLibrary.swift */, + 4CA485BA2232339F004B9E7D /* PhotoCaptureViewController.swift */, + 4C21D5D7223AC60F00EF8A77 /* PhotoCapture.swift */, + 3441FD9E21A3604F00BB9542 /* BackupRestoreViewController.swift */, + 3448E1652215B313004B052E /* OnboardingCaptchaViewController.swift */, + 4585C4671ED8F8D200896AEA /* SafetyNumberConfirmationAlert.swift */, + 34B3F86D1E8DF1700035BE1A /* SignalsNavigationController.h */, + 34B3F86E1E8DF1700035BE1A /* SignalsNavigationController.m */, + 340FC8A4204DAC8D007AEB0F /* AddToGroupViewController.h */, + 340FC89B204DAC8D007AEB0F /* AddToGroupViewController.m */, + 340FC89D204DAC8D007AEB0F /* FingerprintViewController.h */, + 340FC8A2204DAC8D007AEB0F /* FingerprintViewController.m */, + 340FC8A5204DAC8D007AEB0F /* FingerprintViewScanController.h */, + 340FC89F204DAC8D007AEB0F /* FingerprintViewScanController.m */, + 340FC898204DAC8D007AEB0F /* OWSAddToContactViewController.h */, + 340FC8A1204DAC8D007AEB0F /* OWSAddToContactViewController.m */, + 340FC8A0204DAC8D007AEB0F /* OWSConversationSettingsViewController.h */, 34E3E5671EC4B19400495BAC /* AudioProgressView.swift */, 4C2F454E214C00E1004871FF /* AvatarTableViewCell.swift */, 4CA46F4B219CCC630038ABDE /* CaptionView.swift */, @@ -3443,9 +3027,52 @@ 450D19121F85236600970622 /* RemoteVideoView.m */, 34B6A902218B3F62007C4606 /* TypingIndicatorView.swift */, 4C043929220A9EC800BAEA63 /* VoiceNoteLock.swift */, + 4CC1ECFA211A553000CC13BE /* AppUpdateNag.swift */, + 3496956421A301A100DCFE74 /* OWSBackup.h */, + 3496956921A301A100DCFE74 /* OWSBackup.m */, + 3496956B21A301A100DCFE74 /* OWSBackupAPI.swift */, + 3496956821A301A100DCFE74 /* OWSBackupExportJob.h */, + 3496956221A301A100DCFE74 /* OWSBackupExportJob.m */, + 3496956C21A301A100DCFE74 /* OWSBackupImportJob.h */, + 3496956621A301A100DCFE74 /* OWSBackupImportJob.m */, + 3496956D21A301A100DCFE74 /* OWSBackupIO.h */, + 3496956521A301A100DCFE74 /* OWSBackupIO.m */, + 3496956721A301A100DCFE74 /* OWSBackupJob.h */, + 3496956A21A301A100DCFE74 /* OWSBackupJob.m */, + 3496956321A301A100DCFE74 /* OWSBackupLazyRestore.swift */, + B90418E4183E9DD40038554A /* DateUtil.h */, + B90418E5183E9DD40038554A /* DateUtil.m */, + 34B0796C1FCF46B000E248C2 /* MainAppContext.h */, + 34B0796B1FCF46B000E248C2 /* MainAppContext.m */, + 34D99C911F2937CC00D284D6 /* OWSAnalytics.swift */, + 344825C4211390C700DB4BD8 /* OWSOrphanDataCleaner.h */, + 344825C5211390C800DB4BD8 /* OWSOrphanDataCleaner.m */, + 34D2CCD82062E7D000CB1A14 /* OWSScreenLockUI.h */, + 34D2CCD92062E7D000CB1A14 /* OWSScreenLockUI.m */, + 4C21D5D5223A9DC500EF8A77 /* UIAlerts+iOS9.m */, + 45C0DC1A1E68FE9000E04C47 /* UIApplication+OWS.swift */, + 45C0DC1D1E69011F00E04C47 /* UIStoryboard+OWS.swift */, + EF764C331DB67CC5000D9A87 /* UIViewController+Permissions.h */, + EF764C341DB67CC5000D9A87 /* UIViewController+Permissions.m */, + 45B5360D206DD8BB00D61655 /* UIResponder+OWS.swift */, + 4C586924224FAB83003FD070 /* AVAudioSession+OWS.h */, + 4C586925224FAB83003FD070 /* AVAudioSession+OWS.m */, + 4579431C1E7C8CE9008ED0C0 /* Pastelog.h */, + 4579431D1E7C8CE9008ED0C0 /* Pastelog.m */, + 450DF2041E0D74AC003D14BE /* Platform.swift */, + 4521C3BF1F59F3BA00B4C582 /* TextFieldHelper.swift */, + 4CC613352227A00400E21A3A /* ConversationSearch.swift */, + 340FC89A204DAC8D007AEB0F /* OWSConversationSettingsViewController.m */, + 340FC899204DAC8D007AEB0F /* OWSConversationSettingsViewDelegate.h */, + 340FC89E204DAC8D007AEB0F /* ShowGroupMembersViewController.h */, + 340FC8A6204DAC8D007AEB0F /* ShowGroupMembersViewController.m */, + 340FC8A3204DAC8D007AEB0F /* UpdateGroupViewController.h */, + 340FC89C204DAC8D007AEB0F /* UpdateGroupViewController.m */, + 34D1F0BF1F8EC1760066283D /* MessageRecipientStatusUtils.swift */, + 3448BFC01EDF0EA7005B2D69 /* ConversationView */, + 34A6C27F21E503E600B5B12E /* OWSImagePickerController.swift */, ); - name = Views; - path = views; + path = Signal; sourceTree = ""; }; 7BC01A3C241F40AB00BC7C55 /* SessionPushNotificationExtension */ = { @@ -3530,63 +3157,6 @@ path = Images; sourceTree = ""; }; - B660F66C1C29867F00687D6E /* test */ = { - isa = PBXGroup; - children = ( - 34C6B0A41FA0E46F00D35993 /* Assets */, - B660F6731C29867F00687D6E /* call */, - 34843B29214FE295004DED45 /* mocks */, - 458E38381D6699110094BD24 /* Models */, - 34843B2321432293004DED45 /* SignalBaseTest.h */, - 34843B2221432292004DED45 /* SignalBaseTest.m */, - 4589670F1DC117CC00E9DD21 /* SignalTests-Bridging-Header.h */, - 4C3EF8002109184A0007EBF7 /* SSKTests */, - B660F69D1C29868000687D6E /* Supporting Files */, - B660F6A01C29868000687D6E /* TestUtil.h */, - B660F6A21C29868000687D6E /* util */, - 34B3F8951E8DF1B90035BE1A /* ViewControllers */, - 34BEDB0F21C41E71007B0EAE /* views */, - ); - path = test; - sourceTree = ""; - }; - B660F6731C29867F00687D6E /* call */ = { - isa = PBXGroup; - children = ( - 456F6E2E1E261D1000FD2210 /* PeerConnectionClientTest.swift */, - ); - path = call; - sourceTree = ""; - }; - B660F69D1C29868000687D6E /* Supporting Files */ = { - isa = PBXGroup; - children = ( - B660F69E1C29868000687D6E /* SignalTests-Info.plist */, - B660F69F1C29868000687D6E /* whisperFake.cer */, - ); - path = "Supporting Files"; - sourceTree = ""; - }; - B660F6A21C29868000687D6E /* util */ = { - isa = PBXGroup; - children = ( - 3421981B21061D2E00C57195 /* ByteParserTest.swift */, - 3491D9A021022DB7001EF5A1 /* CDSSigningCertificateTest.m */, - 45E7A6A61E71CA7E00D44FB5 /* DisplayableTextFilterTest.swift */, - B660F6AD1C29868000687D6E /* FunctionalUtilTest.m */, - 455AC69D1F4F8B0300134004 /* ImageCacheTest.swift */, - 34DB0BEC2011548B007B313F /* OWSDatabaseConverterTest.m */, - 34843B25214327C9004DED45 /* OWSOrphanDataCleanerTest.m */, - 45666F571D9B2880008FE134 /* OWSScrubbingLogFormatterTest.m */, - 34E8A8D02085238900B272B1 /* ProtoParsingTest.m */, - 45360B8F1F9527DA00FA666C /* SearcherTest.swift */, - 452D1AF02081059C00A67F7F /* StringAdditionsTest.swift */, - B660F6B31C29868000687D6E /* UtilTest.h */, - B660F6B41C29868000687D6E /* UtilTest.m */, - ); - path = util; - sourceTree = ""; - }; B6B6C3C419193F5B00C0B76B /* Translations */ = { isa = PBXGroup; children = ( @@ -3594,26 +3164,7 @@ C3AA6BB824CE8F1B002358B6 /* Migrating Translations from Android.md */, ); name = Translations; - sourceTree = ""; - }; - B8439518228510E9000563FE /* Loki */ = { - isa = PBXGroup; - children = ( - B8CCF63B239757C10091D419 /* Components */, - C31F812425258F9C00DD9FD9 /* Database */, - C32B405424A961E1001117B5 /* Dependencies */, - B8CCF63C239757DB0091D419 /* Utilities */, - B8CCF63D2397580E0091D419 /* View Controllers */, - ); - path = Loki; - sourceTree = ""; - }; - B8BB82BA2394D47000BA5194 /* Loki */ = { - isa = PBXGroup; - children = ( - B8CCF6342396005F0091D419 /* SpaceMono-Regular.ttf */, - ); - path = Loki; + path = ..; sourceTree = ""; }; B8CCF63B239757C10091D419 /* Components */ = { @@ -4871,6 +4422,27 @@ path = "Shared Sender Keys"; sourceTree = ""; }; + C3F0A58F255C8E3D007BE2A3 /* Meta */ = { + isa = PBXGroup; + children = ( + C35E8AA42485C83B00ACB629 /* CSV */, + 34330A581E7875FB00DF2FB9 /* Fonts */, + B633C4FD1A1D190B0059AC12 /* Images */, + B66DBF4919D5BBC8006EA940 /* Images.xcassets */, + D221A099169C9E5E00537ABF /* main.m */, + B67EBF5C19194AC60084CCFD /* Settings.bundle */, + B657DDC91911A40500F45B0C /* Signal.entitlements */, + 45B201741DAECBFD00C461E0 /* Signal-Bridging-Header.h */, + D221A095169C9E5E00537ABF /* Signal-Info.plist */, + D221A09B169C9E5E00537ABF /* Signal-Prefix.pch */, + 4C63CBFF210A620B003AE45C /* SignalTSan.supp */, + 4C6F527B20FFE8400097DEEE /* SignalUBSan.supp */, + 34074F54203D0722004596AE /* Sounds */, + B6B6C3C419193F5B00C0B76B /* Translations */, + ); + path = Meta; + sourceTree = ""; + }; D221A07E169C9E5E00537ABF = { isa = PBXGroup; children = ( @@ -4961,51 +4533,17 @@ D221A093169C9E5E00537ABF /* Session */ = { isa = PBXGroup; children = ( - C35E8AA42485C83B00ACB629 /* CSV */, - 34330A581E7875FB00DF2FB9 /* Fonts */, - B633C4FD1A1D190B0059AC12 /* Images */, - B66DBF4919D5BBC8006EA940 /* Images.xcassets */, - B67EBF5C19194AC60084CCFD /* Settings.bundle */, - B657DDC91911A40500F45B0C /* Signal.entitlements */, - C34C8F7323A7830A00D82669 /* SpaceMono-Bold.ttf */, - 34074F54203D0722004596AE /* Sounds */, - 76EB03C118170B33006006FC /* src */, - D221A094169C9E5E00537ABF /* Supporting Files */, - B660F66C1C29867F00687D6E /* test */, + C3F0A58F255C8E3D007BE2A3 /* Meta */, + B8CCF63B239757C10091D419 /* Components */, + C31F812425258F9C00DD9FD9 /* Database */, + C32B405424A961E1001117B5 /* Dependencies */, + 76EB03C118170B33006006FC /* Signal */, + B8CCF63C239757DB0091D419 /* Utilities */, + B8CCF63D2397580E0091D419 /* View Controllers */, ); path = Session; sourceTree = ""; }; - D221A094169C9E5E00537ABF /* Supporting Files */ = { - isa = PBXGroup; - children = ( - 4C63CBFF210A620B003AE45C /* SignalTSan.supp */, - 4C6F527B20FFE8400097DEEE /* SignalUBSan.supp */, - B6B6C3C419193F5B00C0B76B /* Translations */, - D221A099169C9E5E00537ABF /* main.m */, - D221A095169C9E5E00537ABF /* Signal-Info.plist */, - B891105B2320872800F15FCC /* GoogleService-Info.plist */, - D221A09B169C9E5E00537ABF /* Signal-Prefix.pch */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; - FCFA64B11A24F29E0007FB87 /* UI Categories */ = { - isa = PBXGroup; - children = ( - 4C21D5D5223A9DC500EF8A77 /* UIAlerts+iOS9.m */, - 45C0DC1A1E68FE9000E04C47 /* UIApplication+OWS.swift */, - 45C0DC1D1E69011F00E04C47 /* UIStoryboard+OWS.swift */, - EF764C331DB67CC5000D9A87 /* UIViewController+Permissions.h */, - EF764C341DB67CC5000D9A87 /* UIViewController+Permissions.m */, - 45B5360D206DD8BB00D61655 /* UIResponder+OWS.swift */, - 4C586924224FAB83003FD070 /* AVAudioSession+OWS.h */, - 4C586925224FAB83003FD070 /* AVAudioSession+OWS.m */, - ); - name = "UI Categories"; - path = ..; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -6082,7 +5620,6 @@ files = ( 7BDCFC08242186E700641C39 /* NotificationServiceExtensionContext.swift in Sources */, 7BC01A3E241F40AB00BC7C55 /* NotificationServiceExtension.swift in Sources */, - 7BDCFC092421894900641C39 /* MessageFetcherJob.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -6687,10 +6224,8 @@ C396DAF12518408B00FF6DC5 /* EnumeratedView.swift in Sources */, 34D1F0BD1F8D108C0066283D /* AttachmentUploadView.m in Sources */, 452EC6DF205E9E30000E787C /* MediaGalleryViewController.swift in Sources */, - 34DC9BD921543E0C00FDDCEC /* DebugContactsUtils.m in Sources */, 34DBF007206C3CB200025978 /* OWSBubbleShapeView.m in Sources */, 4C04392A220A9EC800BAEA63 /* VoiceNoteLock.swift in Sources */, - 34D8C02B1ED3685800188D7C /* DebugUIContacts.m in Sources */, 3496956E21A301A100DCFE74 /* OWSBackupExportJob.m in Sources */, 4C1885D2218F8E1C00B67051 /* PhotoGridViewCell.swift in Sources */, 45C9DEB81DF4E35A0065CA84 /* WebRTCCallMessageHandler.swift in Sources */, @@ -6701,10 +6236,8 @@ B8783E9E23EB948D00404FB8 /* UILabel+Interaction.swift in Sources */, B80C6B5B2384C7F900FDBC8B /* DeviceNameModalDelegate.swift in Sources */, 340FC8B8204DAC8D007AEB0F /* AddToGroupViewController.m in Sources */, - 341F2C0F1F2B8AE700D07D6B /* DebugUIMisc.m in Sources */, B893063F2383961A005EAA8E /* ScanQRCodeWrapperVC.swift in Sources */, B879D449247E1BE300DB3608 /* PathVC.swift in Sources */, - 34E3EF0D1EFC235B007F6822 /* DebugUIDiskUsage.m in Sources */, 454A84042059C787008B8C75 /* MediaTileViewController.swift in Sources */, C364535C252467900045C478 /* AudioUtilities.swift in Sources */, 340FC8B4204DAC8D007AEB0F /* OWSBackupSettingsViewController.m in Sources */, @@ -6724,7 +6257,6 @@ 4505C2BF1E648EA300CEBF41 /* ExperienceUpgrade.swift in Sources */, EF764C351DB67CC5000D9A87 /* UIViewController+Permissions.m in Sources */, 45CD81EF1DC030E7004C9430 /* SyncPushTokensJob.swift in Sources */, - 34D2CCE0206939B400CB1A14 /* DebugUIMessagesAssetLoader.m in Sources */, 4CEB78C92178EBAB00F315D2 /* OWSSessionResetJobRecord.m in Sources */, 45794E861E00620000066731 /* CallUIAdapter.swift in Sources */, 340FC8BA204DAC8D007AEB0F /* FingerprintViewScanController.m in Sources */, @@ -6745,12 +6277,10 @@ 3496744F2076ACD000080B5F /* LongTextViewController.swift in Sources */, 34B3F8931E8DF1710035BE1A /* SignalsNavigationController.m in Sources */, 34F308A21ECB469700BB7697 /* OWSBezierPathView.m in Sources */, - 45B27B862037FFB400A539DF /* DebugUIFileBrowser.swift in Sources */, B886B4A92398BA1500211ABE /* QRCode.swift in Sources */, 3496955D219B605E00DCFE74 /* PhotoCollectionPickerController.swift in Sources */, 3403B95D20EA9527001A1F44 /* OWSContactShareButtonsView.m in Sources */, 34B0796D1FCF46B100E248C2 /* MainAppContext.m in Sources */, - 34E3EF101EFC2684007F6822 /* DebugUIPage.m in Sources */, B80C6B572384A56D00FDBC8B /* DeviceLinksVC.swift in Sources */, 34A8B3512190A40E00218A25 /* MediaAlbumCellView.swift in Sources */, 34D1F0AE1F867BFC0066283D /* OWSMessageCell.m in Sources */, @@ -6763,11 +6293,9 @@ C3D0972B2510499C00F6E3E4 /* BackgroundPoller.swift in Sources */, C3548F0624456447009433A8 /* PNModeVC.swift in Sources */, B80A579F23DFF1F300876683 /* NewClosedGroupVC.swift in Sources */, - 452037D11EE84975004E4CDF /* DebugUISessionState.m in Sources */, D221A09A169C9E5E00537ABF /* main.m in Sources */, 3496957221A301A100DCFE74 /* OWSBackup.m in Sources */, B86BD08623399CEF000F5AE3 /* SeedModal.swift in Sources */, - 45638BDC1F3DD0D400128435 /* DebugUICalling.swift in Sources */, 34E3E5681EC4B19400495BAC /* AudioProgressView.swift in Sources */, 34D1F0521F7E8EA30066283D /* GiphyDownloader.swift in Sources */, 340FC8BC204DAC8D007AEB0F /* FingerprintViewController.m in Sources */, @@ -6782,10 +6310,8 @@ C331FFFE2558FF3B00070591 /* ConversationCell.swift in Sources */, C3DFFAC623E96F0D0058DAF8 /* Sheet.swift in Sources */, C31FFE57254A5FFE00F19441 /* KeyPairUtilities.swift in Sources */, - 343A65951FC47D5E000477A1 /* DebugUISyncMessages.m in Sources */, 45C0DC1E1E69011F00E04C47 /* UIStoryboard+OWS.swift in Sources */, 452ECA4D1E087E7200E2F016 /* MessageFetcherJob.swift in Sources */, - 4556FA681F54AA9500AF40DD /* DebugUIProfile.swift in Sources */, 45A6DAD61EBBF85500893231 /* ReminderView.swift in Sources */, 34D1F0881F8678AA0066283D /* ConversationViewLayout.m in Sources */, B82B408E239DC00D00A248E7 /* DisplayNameVC.swift in Sources */, @@ -6801,7 +6327,6 @@ 348BB25D20A0C5530047AEC2 /* ContactShareViewHelper.swift in Sources */, 34B3F8801E8DF1700035BE1A /* InviteFlow.swift in Sources */, B85357C523A1F13800AAF6CD /* LinkDeviceVC.swift in Sources */, - 457C87B82032645C008D52D6 /* DebugUINotifications.swift in Sources */, 4C21D5D8223AC60F00EF8A77 /* PhotoCapture.swift in Sources */, C331FFF32558FF0300070591 /* PathStatusView.swift in Sources */, 4C13C9F620E57BA30089A98B /* ColorPickerViewController.swift in Sources */, @@ -6821,14 +6346,12 @@ C331FFF42558FF0300070591 /* PNOptionView.swift in Sources */, 34B3F8751E8DF1700035BE1A /* CallViewController.swift in Sources */, 4C4AE6A1224AF35700D4AF6F /* SendMediaNavigationController.swift in Sources */, - 34D8C0281ED3673300188D7C /* DebugUITableViewController.m in Sources */, 45F32C222057297A00A300D5 /* MediaDetailViewController.m in Sources */, C3DAB3242480CB2B00725F25 /* SRCopyableLabel.swift in Sources */, B8B26C8F234D629C004ED98C /* MentionCandidateSelectionView.swift in Sources */, C396DAF02518408B00FF6DC5 /* String+Lines.swift in Sources */, B8CCF63F23975CFB0091D419 /* JoinPublicChatVC.swift in Sources */, 34ABC0E421DD20C500ED9469 /* ConversationMessageMapping.swift in Sources */, - 34D8C0271ED3673300188D7C /* DebugUIMessages.m in Sources */, 34DBF003206BD5A500025978 /* OWSMessageTextView.m in Sources */, 34D1F0B41F86D31D0066283D /* ConversationCollectionView.m in Sources */, 45D308AD2049A439000189E4 /* PinEntryView.m in Sources */, @@ -6884,7 +6407,6 @@ 4CB5F26920F7D060004D1B42 /* MessageActions.swift in Sources */, C3E7134F251C867C009649BB /* Sodium+Conversion.swift in Sources */, 340FC8B5204DAC8D007AEB0F /* AboutTableViewController.m in Sources */, - 34BECE2B1F74C12700D7438D /* DebugUIStress.m in Sources */, C33100082558FF6D00070591 /* NewConversationButtonSet.swift in Sources */, 340FC8B9204DAC8D007AEB0F /* UpdateGroupViewController.m in Sources */, B8BB82A5238F627000BA5194 /* HomeVC.swift in Sources */, @@ -6893,13 +6415,11 @@ 3448E1662215B313004B052E /* OnboardingCaptchaViewController.swift in Sources */, 4574A5D61DD6704700C6B692 /* CallService.swift in Sources */, 4521C3C01F59F3BA00B4C582 /* TextFieldHelper.swift in Sources */, - 34D2CCDF206939B400CB1A14 /* DebugUIMessagesAction.m in Sources */, 340FC8AC204DAC8D007AEB0F /* PrivacySettingsTableViewController.m in Sources */, B88847BC23E10BC6009836D2 /* GroupMembersVC.swift in Sources */, B85357BF23A1AE0800AAF6CD /* SeedReminderView.swift in Sources */, C31F812625258FB000DD9FD9 /* Storage+VolumeSamples.swift in Sources */, B85357C723A1FB5100AAF6CD /* LinkDeviceVCDelegate.swift in Sources */, - 340FC8C5204DE223007AEB0F /* DebugUIBackup.m in Sources */, C35E8AAE2485E51D00ACB629 /* IP2Country.swift in Sources */, 340FC8AE204DAC8D007AEB0F /* OWSSoundSettingsViewController.m in Sources */, 4579431E1E7C8CE9008ED0C0 /* Pastelog.m in Sources */, @@ -6983,7 +6503,6 @@ B6F509951AA53F760068F56A /* Localizable.strings */ = { isa = PBXVariantGroup; children = ( - B6F509961AA53F760068F56A /* en */, B676BCEF1AA544E7009637B8 /* de */, B676BCF11AA5451E009637B8 /* es */, B646D10E1AA5461A004133BA /* fr */, @@ -6996,8 +6515,10 @@ C396469D2509D3F400B0B9F5 /* ja */, C396469E2509D40400B0B9F5 /* vi-VN */, C396469F2509D41100B0B9F5 /* id-ID */, + C3F0A5B2255C915C007BE2A3 /* en */, ); name = Localizable.strings; + path = Meta/Translations; sourceTree = ""; }; /* End PBXVariantGroup section */ @@ -8178,7 +7699,7 @@ CLANG_ENABLE_MODULES = YES; CLANG_UNDEFINED_BEHAVIOR_SANITIZER_INTEGER = YES; CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES; - CODE_SIGN_ENTITLEMENTS = Session/Signal.entitlements; + CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CURRENT_PROJECT_VERSION = 139; @@ -8189,7 +7710,7 @@ ); GCC_OPTIMIZATION_LEVEL = 0; GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "Session/Signal-Prefix.pch"; + GCC_PREFIX_HEADER = "Session/Meta/Signal-Prefix.pch"; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", @@ -8208,7 +7729,7 @@ "\"$(SRCROOT)/MMDrawerController\"", "\"$(SRCROOT)/Libraries\"/**", ); - INFOPLIST_FILE = "$(SRCROOT)/Session/Signal-Info.plist"; + INFOPLIST_FILE = "$(SRCROOT)/Session/Meta/Signal-Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( @@ -8225,7 +7746,7 @@ PROVISIONING_PROFILE_SPECIFIER = ""; RUN_CLANG_STATIC_ANALYZER = YES; SDKROOT = iphoneos; - SWIFT_OBJC_BRIDGING_HEADER = "Session/src/Signal-Bridging-Header.h"; + SWIFT_OBJC_BRIDGING_HEADER = "Session/Meta/Signal-Bridging-Header.h"; SWIFT_OBJC_INTERFACE_HEADER_NAME = "Session-Swift.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; @@ -8245,7 +7766,7 @@ CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES; CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES; CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Session/Signal.entitlements; + CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CURRENT_PROJECT_VERSION = 139; @@ -8256,7 +7777,7 @@ ); GCC_OPTIMIZATION_LEVEL = 3; GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "Session/Signal-Prefix.pch"; + GCC_PREFIX_HEADER = "Session/Meta/Signal-Prefix.pch"; GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", HAVE_CONFIG_H, @@ -8275,7 +7796,7 @@ "\"$(SRCROOT)/MMDrawerController\"", "\"$(SRCROOT)/Libraries\"/**", ); - INFOPLIST_FILE = "$(SRCROOT)/Session/Signal-Info.plist"; + INFOPLIST_FILE = "$(SRCROOT)/Session/Meta/Signal-Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( @@ -8290,7 +7811,7 @@ PROVISIONING_PROFILE = ""; RUN_CLANG_STATIC_ANALYZER = YES; SDKROOT = iphoneos; - SWIFT_OBJC_BRIDGING_HEADER = "Session/src/Signal-Bridging-Header.h"; + SWIFT_OBJC_BRIDGING_HEADER = "Session/Meta/Signal-Bridging-Header.h"; SWIFT_OBJC_INTERFACE_HEADER_NAME = "Session-Swift.h"; SWIFT_VERSION = 5.0; TEST_AFTER_BUILD = YES;