Skip to content
Merged
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Foundation
import PhotoGetherDomainInterface

public struct StickerDTO: Decodable {
public struct EmojiDTO: Decodable {
let code: String
let character: String
let image: String
Expand All @@ -10,8 +10,8 @@ public struct StickerDTO: Decodable {
let subgroup: String
}

extension StickerDTO {
func toEntity() -> StickerEntity {
extension EmojiDTO {
func toEntity() -> EmojiEntity {
return .init(
image: self.image,
name: self.name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import Foundation
import PhotoGetherDomainInterface

public final class LocalShapeDataSourceImpl: ShapeDataSource {
public func fetchStickerData() -> AnyPublisher<[StickerDTO], Error> {
public func fetchEmojiData() -> AnyPublisher<[EmojiDTO], Error> {
return Empty().eraseToAnyPublisher()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ import PhotoGetherNetwork

public final class RemoteShapeDataSourceImpl: ShapeDataSource {
// TODO: 페이징 적용 필요
public func fetchStickerData() -> AnyPublisher<[StickerDTO], Error> {
return Request.requestJSON(StickerEndPoint())
public func fetchEmojiData() -> AnyPublisher<[EmojiDTO], Error> {
return Request.requestJSON(EmojiEndPoint())
}

public init() { }
}

private struct StickerEndPoint: EndPoint {
private struct EmojiEndPoint: EndPoint {
var baseURL: URL { URL(string: "https://api.api-ninjas.com")! }
var path: String { "v1/emoji" }
var method: HTTPMethod { .get }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ import Combine
import Foundation

public protocol ShapeDataSource {
func fetchStickerData() -> AnyPublisher<[StickerDTO], Error>
func fetchEmojiData() -> AnyPublisher<[EmojiDTO], Error>
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import PhotoGetherDomainInterface
final public class ShapeRepositoryImpl: ShapeRepository {
// TODO: local 먼저 확인 -> remote 데이터 확인하도록 수정
// MARK: JSON 데이터 내부의 URL을 어느 시점에 다운로드 할것인가...?
public func fetchStickerList() -> AnyPublisher<[StickerEntity], Never> {
return remoteDataSource.fetchStickerData()
public func fetchEmojiList() -> AnyPublisher<[EmojiEntity], Never> {
return remoteDataSource.fetchEmojiData()
.map { $0.map { $0.toEntity() } }
.replaceError(with: [])
.eraseToAnyPublisher()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import PhotoGetherDomainTesting
import PhotoGetherDomainInterface
import PhotoGetherDomain

final class FetchStickerListUseCaseTests: XCTestCase {
var sut: FetchStickerListUseCase!
final class FetchEmojiListUseCaseTests: XCTestCase {
var sut: FetchEmojiListUseCase!
var shapeRepositoryMock: ShapeRepositoryMock!

func test_이미지데이터_리스트를_번들에서_잘_가져오는지() {
Expand All @@ -26,15 +26,15 @@ final class FetchStickerListUseCaseTests: XCTestCase {
]
let shapeRepositoryMock = ShapeRepositoryMock(imageNameList: imageNameList)

sut = FetchStickerListUseCaseImpl(shapeRepository: shapeRepositoryMock)
sut = FetchEmojiListUseCaseImpl(shapeRepository: shapeRepositoryMock)

var targetEntityList: [StickerEntity] = []
var targetEntityList: [EmojiEntity] = []
let beforeEntityListCount = 0

//Act 실행 단계: SUT 메소드를 호출하면서 의존성을 전달해서 결과를 저장하기
let cancellable = sut.execute()
.sink { stickerEntities in
targetEntityList.append(contentsOf: stickerEntities)
.sink { emojiEntities in
targetEntityList.append(contentsOf: emojiEntities)
expectation.fulfill()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import Combine
import Foundation
import PhotoGetherDomainInterface

public final class FetchStickerListUseCaseImpl: FetchStickerListUseCase {
public func execute() -> AnyPublisher<[StickerEntity], Never> {
return shapeRepository.fetchStickerList()
public final class FetchEmojiListUseCaseImpl: FetchEmojiListUseCase {
public func execute() -> AnyPublisher<[EmojiEntity], Never> {
return shapeRepository.fetchEmojiList()
}

private let shapeRepository: ShapeRepository
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

public struct StickerEntity: Decodable {
public struct EmojiEntity: Decodable {
public let image: String
public let name: String

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ import Combine
import Foundation

public protocol ShapeRepository {
func fetchStickerList() -> AnyPublisher<[StickerEntity], Never>
func fetchEmojiList() -> AnyPublisher<[EmojiEntity], Never>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import Combine
import Foundation

public protocol FetchEmojiListUseCase {
func execute() -> AnyPublisher<[EmojiEntity], Never>
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Combine
import Foundation
import PhotoGetherDomainInterface

public final class FetchStickerListUseCaseMock: FetchStickerListUseCase {
public final class FetchEmojiListUseCaseMock: FetchEmojiListUseCase {
private let repository: ShapeRepository = ShapeRepositoryMock(imageNameList: [
"blackHeart", "bug", "cat",
"crown", "dog", "lips",
Expand All @@ -12,7 +12,7 @@ public final class FetchStickerListUseCaseMock: FetchStickerListUseCase {

public init() { }

public func execute() -> AnyPublisher<[StickerEntity], Never> {
return repository.fetchStickerList()
public func execute() -> AnyPublisher<[EmojiEntity], Never> {
return repository.fetchEmojiList()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ public final class ShapeRepositoryMock: ShapeRepository {
self.imageNameList = imageNameList
}

public func fetchStickerList() -> AnyPublisher<[StickerEntity], Never> {
let stickerEntities: [StickerEntity] = imageNameList.map {
public func fetchEmojiList() -> AnyPublisher<[EmojiEntity], Never> {
let emojiEntities: [EmojiEntity] = imageNameList.map {
.init(
image: imagePath(named: $0), // 이미지 주소(or 경로)
name: $0
)
}

return Just(stickerEntities).eraseToAnyPublisher()
return Just(emojiEntities).eraseToAnyPublisher()
}

private func imagePath(named: String) -> String {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@
050F6E132CEE19A2002F5473 /* PhotoGetherData.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 050F6E112CEE19A2002F5473 /* PhotoGetherData.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
053DC8532CE32AE900DC9F35 /* DesignSystem.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 053DC8522CE32AE900DC9F35 /* DesignSystem.framework */; };
053DC8542CE32AE900DC9F35 /* DesignSystem.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 053DC8522CE32AE900DC9F35 /* DesignSystem.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
05DBEF502CEEF86C0075329B /* PhotoGetherDomain.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 05DBEF4F2CEEF86C0075329B /* PhotoGetherDomain.framework */; };
05DBEF512CEEF86C0075329B /* PhotoGetherDomain.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 05DBEF4F2CEEF86C0075329B /* PhotoGetherDomain.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
05DBEF532CEEF8720075329B /* PhotoGetherDomainInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 05DBEF522CEEF8720075329B /* PhotoGetherDomainInterface.framework */; };
05DBEF542CEEF8720075329B /* PhotoGetherDomainInterface.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 05DBEF522CEEF8720075329B /* PhotoGetherDomainInterface.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
05DBEF562CEEF8870075329B /* PhotoGetherDomainTesting.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 05DBEF552CEEF8870075329B /* PhotoGetherDomainTesting.framework */; };
05DBEF572CEEF8870075329B /* PhotoGetherDomainTesting.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 05DBEF552CEEF8870075329B /* PhotoGetherDomainTesting.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
60CB82A82CDB522900873DD6 /* EditPhotoRoomFeature.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60CB82612CDB4FC500873DD6 /* EditPhotoRoomFeature.framework */; };
60CB82A92CDB522900873DD6 /* EditPhotoRoomFeature.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 60CB82612CDB4FC500873DD6 /* EditPhotoRoomFeature.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
7B59510C2CDB598600B89C85 /* FeatureTesting.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B59510B2CDB598600B89C85 /* FeatureTesting.framework */; };
Expand Down Expand Up @@ -38,8 +44,11 @@
dstPath = "";
dstSubfolderSpec = 10;
files = (
05DBEF512CEEF86C0075329B /* PhotoGetherDomain.framework in Embed Frameworks */,
050F6E132CEE19A2002F5473 /* PhotoGetherData.framework in Embed Frameworks */,
7B59510D2CDB598600B89C85 /* FeatureTesting.framework in Embed Frameworks */,
05DBEF572CEEF8870075329B /* PhotoGetherDomainTesting.framework in Embed Frameworks */,
05DBEF542CEEF8720075329B /* PhotoGetherDomainInterface.framework in Embed Frameworks */,
60CB82A92CDB522900873DD6 /* EditPhotoRoomFeature.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
Expand All @@ -63,6 +72,9 @@
/* Begin PBXFileReference section */
050F6E112CEE19A2002F5473 /* PhotoGetherData.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = PhotoGetherData.framework; sourceTree = BUILT_PRODUCTS_DIR; };
053DC8522CE32AE900DC9F35 /* DesignSystem.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DesignSystem.framework; sourceTree = BUILT_PRODUCTS_DIR; };
05DBEF4F2CEEF86C0075329B /* PhotoGetherDomain.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = PhotoGetherDomain.framework; sourceTree = BUILT_PRODUCTS_DIR; };
05DBEF522CEEF8720075329B /* PhotoGetherDomainInterface.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = PhotoGetherDomainInterface.framework; sourceTree = BUILT_PRODUCTS_DIR; };
05DBEF552CEEF8870075329B /* PhotoGetherDomainTesting.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = PhotoGetherDomainTesting.framework; sourceTree = BUILT_PRODUCTS_DIR; };
60CB82612CDB4FC500873DD6 /* EditPhotoRoomFeature.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = EditPhotoRoomFeature.framework; sourceTree = BUILT_PRODUCTS_DIR; };
60CB827C2CDB508C00873DD6 /* EditPhotoRoomFeatureDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = EditPhotoRoomFeatureDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };
7B59510B2CDB598600B89C85 /* FeatureTesting.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = FeatureTesting.framework; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -112,8 +124,11 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
05DBEF502CEEF86C0075329B /* PhotoGetherDomain.framework in Frameworks */,
050F6E122CEE19A2002F5473 /* PhotoGetherData.framework in Frameworks */,
7B59510C2CDB598600B89C85 /* FeatureTesting.framework in Frameworks */,
05DBEF562CEEF8870075329B /* PhotoGetherDomainTesting.framework in Frameworks */,
05DBEF532CEEF8720075329B /* PhotoGetherDomainInterface.framework in Frameworks */,
60CB82A82CDB522900873DD6 /* EditPhotoRoomFeature.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -143,14 +158,10 @@
60CB82A72CDB522900873DD6 /* Frameworks */ = {
isa = PBXGroup;
children = (
05DBEF552CEEF8870075329B /* PhotoGetherDomainTesting.framework */,
05DBEF522CEEF8720075329B /* PhotoGetherDomainInterface.framework */,
05DBEF4F2CEEF86C0075329B /* PhotoGetherDomain.framework */,
050F6E112CEE19A2002F5473 /* PhotoGetherData.framework */,
055AF9A62CEC739C0060E408 /* FeatureTesting.framework */,
055AF99E2CEC6F4A0060E408 /* PhotoGetherDomainInterface.framework */,
055AF98D2CEC6F0E0060E408 /* PhotoGetherDomainInterface.framework */,
055AF9892CEC6F0B0060E408 /* PhotoGetherDomain.framework */,
055AF9782CEC6E840060E408 /* PhotoGetherDomainTesting.framework */,
055AF9752CEC6E7F0060E408 /* PhotoGetherDomainInterface.framework */,
055AF9722CEC6E7A0060E408 /* PhotoGetherDomain.framework */,
053DC8522CE32AE900DC9F35 /* DesignSystem.framework */,
7B5951CE2CDB658400B89C85 /* PhotoGetherDomainInterface.framework */,
7B5951772CDB62A200B89C85 /* PresentationUtility.framework */,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import UIKit
import PhotoGetherDomainInterface
import Combine
import BaseFeature
import DesignSystem
Expand Down Expand Up @@ -91,8 +92,8 @@ public class EditPhotoRoomGuestViewController: BaseViewController, ViewControlle
.receive(on: RunLoop.main)
.sink { [weak self] event in
switch event {
case .stickerImageData(let sticker):
self?.createStickerObject(by: sticker)
case .emojiEntity(let emojiEntity):
self?.createStickerObject(by: emojiEntity)
case .stickerObjectList(let stickerList):
self?.updateCanvas(with: stickerList)
}
Expand Down Expand Up @@ -133,15 +134,22 @@ public class EditPhotoRoomGuestViewController: BaseViewController, ViewControlle
}

// MARK: 원래는 Data가 아니라 imageURL 및 Image의 MetaData가 와야함.
private func createStickerObject(by sticker: Data) {
private func createStickerObject(by entity: EmojiEntity) {
let imageSize: CGFloat = 64
let rect = calculateCenterPosition(imageSize: imageSize)
let newStickerObject = StickerObject(
id: UUID(),
image: sticker,
rect: rect
)
input.send(.stickerObjectData(newStickerObject))

guard let url = URL(string: entity.image) else { return }
Task {
guard let (data, response) = try? await URLSession.shared.data(from: url)
else { return }

let newStickerObject = StickerObject(
id: UUID(),
image: data,
rect: rect
)
input.send(.stickerObjectData(newStickerObject))
}
}

private func calculateCenterPosition(imageSize: CGFloat) -> CGRect {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,30 @@ public final class EditPhotoRoomGuestViewModel {
}

enum Output {
case stickerImageData(data: Data)
case emojiEntity(entity: EmojiEntity)
case stickerObjectList([StickerObject])
}

private let fetchStickerListUseCase: FetchStickerListUseCase
private let fetchEmojiListUseCase: FetchEmojiListUseCase
private let connectionClient: ConnectionClient

private var stickerImageList: [Data] = []
private var emojiList: [EmojiEntity] = []
private var stickerObjectListSubject = CurrentValueSubject<[StickerObject], Never>([])

private var cancellables = Set<AnyCancellable>()
private var output = PassthroughSubject<Output, Never>()

public init(
fetchStickerListUseCase: FetchStickerListUseCase,
fetchStickerListUseCase: FetchEmojiListUseCase,
connectionClient: ConnectionClient
) {
self.fetchStickerListUseCase = fetchStickerListUseCase
self.fetchEmojiListUseCase = fetchStickerListUseCase
self.connectionClient = connectionClient
bind()
}

private func bind() {
fetchStickerList()
fetchEmojiList()

stickerObjectListSubject
.sink { [weak self] list in
Expand All @@ -45,7 +45,7 @@ public final class EditPhotoRoomGuestViewModel {
input.sink { [weak self] event in
switch event {
case .stickerButtonDidTap:
self?.sendStickerImage()
self?.sendEmoji()
case .stickerObjectData(let sticker):
self?.appendSticker(with: sticker)
}
Expand All @@ -61,16 +61,16 @@ public final class EditPhotoRoomGuestViewModel {
stickerObjectListSubject.send(currentStickerObjectList)
}

private func fetchStickerList() {
fetchStickerListUseCase.execute()
.sink { [weak self] datas in
self?.stickerImageList = datas
private func fetchEmojiList() {
fetchEmojiListUseCase.execute()
.sink { [weak self] emojiEntities in
self?.emojiList = emojiEntities
}
.store(in: &cancellables)
}

private func sendStickerImage() {
output.send(.stickerImageData(data: stickerImageList.randomElement()!))
private func sendEmoji() {
output.send(.emojiEntity(entity: emojiList.randomElement()!))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public class EditPhotoRoomHostViewController: BaseViewController, ViewController
.receive(on: RunLoop.main)
.sink { [weak self] in
switch $0 {
case .sticker(let entity):
case .emojiEntity(let entity):
self?.renderSticker(entity: entity)
}
}
Expand All @@ -97,14 +97,14 @@ public class EditPhotoRoomHostViewController: BaseViewController, ViewController
canvasScrollView.backgroundColor = .red
}

private func renderSticker(entity: StickerEntity) {
private func renderSticker(entity: EmojiEntity) {
let imageSize: CGFloat = 64
let rect = calculateCenterPosition(imageSize: imageSize)
let stickerImageView = UIImageView(frame: rect)
guard let url = URL(string: entity.image) else { return }

Task {
guard let (data, response) = try? await URLSession.shared.data(from: url)
guard let (data, _) = try? await URLSession.shared.data(from: url)
else { return }

let stickerImage = UIImage(data: data)
Expand Down
Loading
Loading