From f95526bff70bb97dd0b6dae37545386a378f6a5d Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Fri, 14 Dec 2018 12:31:55 -0500 Subject: [PATCH] Start sketching out image editor. --- Signal.xcodeproj/project.pbxproj | 12 ++++ Signal/test/views/ImageEditorTest.swift | 39 +++++++++++ .../Views/ImageEditor/ImageEditor.swift | 68 ++++++++++++++++++- 3 files changed, 117 insertions(+), 2 deletions(-) create mode 100644 Signal/test/views/ImageEditorTest.swift diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index b3a974951..5f3c2779d 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -236,6 +236,7 @@ 34BECE2E1F7ABCE000D7438D /* GifPickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34BECE2D1F7ABCE000D7438D /* GifPickerViewController.swift */; }; 34BECE301F7ABCF800D7438D /* GifPickerLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34BECE2F1F7ABCF800D7438D /* GifPickerLayout.swift */; }; 34BEDB0E21C405B0007B0EAE /* ImageEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34BEDB0D21C405B0007B0EAE /* ImageEditor.swift */; }; + 34BEDB1121C41E71007B0EAE /* ImageEditorTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34BEDB1021C41E71007B0EAE /* ImageEditorTest.swift */; }; 34C3C78D20409F320000134C /* Opening.m4r in Resources */ = {isa = PBXBuildFile; fileRef = 34C3C78C20409F320000134C /* Opening.m4r */; }; 34C3C78F2040A4F70000134C /* sonarping.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 34C3C78E2040A4F70000134C /* sonarping.mp3 */; }; 34C3C7922040B0DD0000134C /* OWSAudioPlayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 34C3C7902040B0DC0000134C /* OWSAudioPlayer.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -908,6 +909,7 @@ 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 = ""; }; 34BEDB0D21C405B0007B0EAE /* ImageEditor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageEditor.swift; sourceTree = ""; }; + 34BEDB1021C41E71007B0EAE /* ImageEditorTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageEditorTest.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 = Signal/AudioFiles/sonarping.mp3; sourceTree = SOURCE_ROOT; }; 34C3C7902040B0DC0000134C /* OWSAudioPlayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSAudioPlayer.h; sourceTree = ""; }; @@ -1869,6 +1871,14 @@ path = ImageEditor; sourceTree = ""; }; + 34BEDB0F21C41E71007B0EAE /* views */ = { + isa = PBXGroup; + children = ( + 34BEDB1021C41E71007B0EAE /* ImageEditorTest.swift */, + ); + path = views; + sourceTree = ""; + }; 34C3C78B20409F320000134C /* ringtoneSounds */ = { isa = PBXGroup; children = ( @@ -2401,6 +2411,7 @@ B660F6A01C29868000687D6E /* TestUtil.h */, B660F6A21C29868000687D6E /* util */, 34B3F8951E8DF1B90035BE1A /* ViewControllers */, + 34BEDB0F21C41E71007B0EAE /* views */, ); path = test; sourceTree = ""; @@ -3591,6 +3602,7 @@ files = ( 456F6E2F1E261D1000FD2210 /* PeerConnectionClientTest.swift in Sources */, 458967111DC117CC00E9DD21 /* AccountManagerTest.swift in Sources */, + 34BEDB1121C41E71007B0EAE /* ImageEditorTest.swift in Sources */, 3491D9A121022DB7001EF5A1 /* CDSSigningCertificateTest.m in Sources */, 340B02BA1FA0D6C700F9CFEC /* ConversationViewItemTest.m in Sources */, 458E383A1D6699FA0094BD24 /* OWSDeviceProvisioningURLParserTest.m in Sources */, diff --git a/Signal/test/views/ImageEditorTest.swift b/Signal/test/views/ImageEditorTest.swift new file mode 100644 index 000000000..eea5418ad --- /dev/null +++ b/Signal/test/views/ImageEditorTest.swift @@ -0,0 +1,39 @@ +// +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. +// + +import XCTest +@testable import Signal +@testable import SignalMessaging + +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() + let item = ImageEditorItem() + contents.append(item: item) + XCTAssertEqual(1, contents.itemMap.count) + XCTAssertEqual(1, contents.itemIds.count) + + let contentsCopy = contents.clone() + XCTAssertEqual(1, contents.itemMap.count) + XCTAssertEqual(1, contents.itemIds.count) + XCTAssertEqual(1, contentsCopy.itemMap.count) + XCTAssertEqual(1, contentsCopy.itemIds.count) + + contentsCopy.remove(item: item) + XCTAssertEqual(1, contents.itemMap.count) + XCTAssertEqual(1, contents.itemIds.count) + XCTAssertEqual(0, contentsCopy.itemMap.count) + XCTAssertEqual(0, contentsCopy.itemIds.count) + } +} diff --git a/SignalMessaging/Views/ImageEditor/ImageEditor.swift b/SignalMessaging/Views/ImageEditor/ImageEditor.swift index 67f742726..de9e6b365 100644 --- a/SignalMessaging/Views/ImageEditor/ImageEditor.swift +++ b/SignalMessaging/Views/ImageEditor/ImageEditor.swift @@ -22,10 +22,74 @@ public class ImageEditorItem: NSObject { } } +@objc +public class ImageEditorContents: NSObject { + + var itemMap = [String: ImageEditorItem]() + var itemIds = [String]() + + @objc + public override init() { + + } + + @objc + public init(itemMap: [String: ImageEditorItem], + itemIds: [String]) { + + self.itemMap = itemMap + self.itemIds = itemIds + } + + @objc + public func clone() -> ImageEditorContents { + return ImageEditorContents(itemMap: itemMap, itemIds: itemIds) + } + + @objc + public func append(item: ImageEditorItem) { + if itemMap[item.itemId] != nil { + owsFail("Unexpected duplicate item in item map: \(item.itemId)") + } + itemMap[item.itemId] = item + + if itemIds.contains(item.itemId) { + owsFail("Unexpected duplicate item in item list: \(item.itemId)") + } else { + itemIds.append(item.itemId) + } + } + + @objc + public func remove(item: ImageEditorItem) { + remove(itemId: item.itemId) + } + + @objc + public func remove(itemId: String) { + if itemMap[itemId] == nil { + owsFail("Missing item in item map: \(itemId)") + } else { + itemMap.removeValue(forKey: itemId) + } + + if !itemIds.contains(itemId) { + owsFail("Missing item in item list: \(itemId)") + } else { + itemIds = itemIds.filter { $0 != itemId } + } + } +} + @objc public class ImageEditorModel: NSObject { - private let srcImagePath: String - private let srcImageSize: CGSize + @objc + public let srcImagePath: String + + @objc + public let srcImageSize: CGSize + + private var contents = ImageEditorContents() @objc public required init(srcImagePath: String) throws {