Skip to content

Commit

Permalink
[Feat] Stamp 34기 대응 : missionDate를 같이 올릴수 있도록, 라우팅 영역 변경, 닉네임 변경 제한 (#…
Browse files Browse the repository at this point in the history
…366)

* [Feat] ListDetailModel, S3 URL, PresignedUrl 등 ServiceLayer에 반영

* [Feat] Repository와 Usecase에 반영

* [Feat] ListDetailViewController와 ViewModel에 이벤트 연결

* [Feat] Listview에서 username containerClick event로 detail page로 이동할수 있도록 변경

* [Fix] List DetailViewController focus 동작 수정

* [Feat] 마이페이지에서 솝탬프 닉네임 변경 제거

* [Fix] 민재 리뷰 반영: 미사용 Extension 제거
  • Loading branch information
elesahich authored Apr 10, 2024
1 parent 9dea61a commit 41891a2
Show file tree
Hide file tree
Showing 35 changed files with 1,779 additions and 1,117 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
//
// Publisher+UIBarButton.swift
// Core
//
// Created by Ian on 4/4/24.
// Copyright © 2024 SOPT-iOS. All rights reserved.
//

import Combine
import UIKit

public extension UIBarButtonItem {
final class Subscription<SubscriberType: Subscriber, Input: UIBarButtonItem>: Combine.Subscription where SubscriberType.Input == Input {
private var subscriber: SubscriberType?
private let input: Input

// MARK: - Initialization

public init(subscriber: SubscriberType, input: Input) {
self.subscriber = subscriber
self.input = input

input.target = self
input.action = #selector(eventHandler)
}

// MARK: - Subscriber

// Do nothing as we only want to send events when they occur
public func request(_ demand: Subscribers.Demand) {}

// MARK: - Cancellable

public func cancel() {
subscriber = nil
}

// MARK: - Internal Functions

@objc private func eventHandler() {
_ = subscriber?.receive(input)
}
}

// MARK: -

struct Publisher<Output: UIBarButtonItem>: Combine.Publisher {
public typealias Output = Output
public typealias Failure = Never

let output: Output

// MARK: - Initialization

public init(output: Output) {
self.output = output
}

// MARK: - Publisher

public func receive<S>(subscriber: S) where S : Subscriber, Never == S.Failure, Output == S.Input {
let subscription: Subscription = Subscription(subscriber: subscriber, input: output)
subscriber.receive(subscription: subscription)
}
}
}

// MARK: - CombineCompatible

extension UIBarButtonItem: CombineCompatible { }

extension CombineCompatible where Self: UIBarButtonItem {
public var tapPublisher: UIBarButtonItem.Publisher<Self> {
return UIBarButtonItem.Publisher(output: self)
}
}
3 changes: 3 additions & 0 deletions SOPT-iOS/Projects/Core/Sources/Literals/StringLiterals.swift
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ public struct I18N {
public static let editComplete = "수정 완료"
public static let editCompletedToast = "수정 완료되었습니다."
public static let deleteTitle = "달성한 미션을 삭제하시겠습니까?"
public static let missionDatePlaceHolder = "날짜를 입력해주세요"
public static let datePickerDoneButtonTitle = "완료"
public static let datePickerCancelButtonTitle = "취소"
}

public struct Setting {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,41 +14,61 @@ import Domain
import Networks

public class ListDetailRepository {

private let stampService: StampService
private let cancelBag = CancelBag()

public init(service: StampService) {
self.stampService = service
}

private let stampService: StampService
private let s3Service: S3Service
private let mediaService: MediaService

private let cancelBag = CancelBag()

public init(
stampService: StampService,
s3Service: S3Service,
mediaService: MediaService
) {
self.stampService = stampService
self.s3Service = s3Service
self.mediaService = mediaService
}
}

extension ListDetailRepository: ListDetailRepositoryInterface {
public func fetchListDetail(missionId: Int, username: String?) -> AnyPublisher<ListDetailModel, Error> {
let username = username ?? UserDefaultKeyList.User.soptampName
guard let username else {
return Fail(error: NSError()).eraseToAnyPublisher()
}
return stampService.fetchStampListDetail(missionId: missionId, username: username)
.map { $0.toDomain() }
.eraseToAnyPublisher()
}

public func postStamp(missionId: Int, stampData: [Any]) -> AnyPublisher<ListDetailModel, Error> {
return stampService.postStamp(missionId: missionId, requestModel: stampData)
.map { $0.toDomain() }
.eraseToAnyPublisher()
}

public func putStamp(missionId: Int, stampData: [Any]) -> Driver<Int> {
return stampService.putStamp(missionId: missionId, requestModel: stampData)
.map { $0.toDomain() }
.asDriver()
}

public func deleteStamp(stampId: Int) -> Driver<Bool> {
return stampService.deleteStamp(stampId: stampId)
.map { $0 == 200 }
.asDriver()
public func fetchListDetail(missionId: Int, username: String?) -> AnyPublisher<ListDetailModel, Error> {
let username = username ?? UserDefaultKeyList.User.soptampName
guard let username else {
return Fail(error: NSError()).eraseToAnyPublisher()
}
return stampService.fetchStampListDetail(missionId: missionId, username: username)
.map { $0.toDomain() }
.eraseToAnyPublisher()
}

public func getPresignedURL() -> AnyPublisher<PresignedUrlModel, Error> {
return s3Service.getPresignedUrl()
.map { $0.toDomain() }
.eraseToAnyPublisher()
}

public func uploadMedia(imageData: Data, presignedUrl: String) -> AnyPublisher<Void, Error> {
return mediaService.uploadMedia(imageData: imageData, to: presignedUrl)
.eraseToAnyPublisher()
}

public func postStamp(stampData: ListDetailRequestModel) -> AnyPublisher<ListDetailModel, Error> {
return stampService.postStamp(requestModel: stampData)
.map { $0.toDomain() }
.eraseToAnyPublisher()
}

public func putStamp(stampData: ListDetailRequestModel) -> Driver<Int> {
return stampService.putStamp(requestModel: stampData)
.map { $0.toDomain() }
.asDriver()
}

public func deleteStamp(stampId: Int) -> Driver<Bool> {
return stampService.deleteStamp(stampId: stampId)
.map { $0 == 200 }
.asDriver()
}
}
30 changes: 16 additions & 14 deletions SOPT-iOS/Projects/Data/Sources/Transform/ListDetailTransform.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,23 @@ import Domain
import Networks

extension ListDetailEntity {
public func toDomain() -> ListDetailModel {

return ListDetailModel.init(image: self.images.first ?? "",
content: self.contents,
date: changeDateformat(self.updatedAt ?? self.createdAt),
stampId: self.id)
}

private func changeDateformat(_ date: String) -> String {
return date.split(separator: "-").joined(separator: ".")
}
public func toDomain() -> ListDetailModel {
return ListDetailModel(
image: self.images.first ?? "",
content: self.contents,
date: changeDateformat(self.updatedAt ?? self.createdAt),
stampId: self.id,
activityDate: self.activityDate
)
}

private func changeDateformat(_ date: String) -> String {
return date.split(separator: "-").joined(separator: ".")
}
}

extension StampEntity {
public func toDomain() -> Int {
return self.stampId
}
public func toDomain() -> Int {
return self.stampId
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//
// PresignedUrlTransform.swift
// Data
//
// Created by Ian on 4/7/24.
// Copyright © 2024 SOPT-iOS. All rights reserved.
//

import Domain
import Networks

extension PreSignedUrlEntity {
func toDomain() -> PresignedUrlModel {
return PresignedUrlModel(
preSignedURL: self.preSignedURL,
imageURL: self.imageURL
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,9 @@ extension AppDelegate {
interface: ListDetailRepositoryInterface.self,
implement: {
ListDetailRepository(
service: DefaultStampService()
stampService: DefaultStampService(),
s3Service: DefaultS3Service(),
mediaService: DefaultMediaService()
)
}
)
Expand Down
29 changes: 19 additions & 10 deletions SOPT-iOS/Projects/Domain/Sources/Model/ListDetailModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,23 @@
import Foundation

public struct ListDetailModel {

public let image, content, date: String
public let stampId: Int

public init(image: String, content: String, date: String, stampId: Int) {
self.image = image
self.content = content
self.date = date
self.stampId = stampId
}
public let image: String
public let content: String
public let date: String
public let stampId: Int
public let activityDate: String

public init(
image: String,
content: String,
date: String,
stampId: Int,
activityDate: String
) {
self.image = image
self.content = content
self.date = date
self.stampId = stampId
self.activityDate = activityDate
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,27 @@
import UIKit

public struct ListDetailRequestModel {
public let imgURL: Data?
public let content: String
public let missionId: Int
public let content: String
public let activityDate: String

public var imgURL: String?

public init(
missionId: Int,
content: String,
activityDate: String
) {
self.missionId = missionId
self.content = content
self.activityDate = activityDate
}
}

extension ListDetailRequestModel {
public mutating func updateImgUrl(to imageUrl: String) -> Self {
self.imgURL = imageUrl

public init(imgURL: Data, content: String) {
self.imgURL = imgURL
self.content = content
}
return self
}
}
22 changes: 22 additions & 0 deletions SOPT-iOS/Projects/Domain/Sources/Model/PresignedUrlModel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//
// PresignedUrlModel.swift
// Domain
//
// Created by Ian on 4/7/24.
// Copyright © 2024 SOPT-iOS. All rights reserved.
//

import Foundation

public struct PresignedUrlModel {
public let preSignedURL: String
public let imageURL: String

public init(
preSignedURL: String,
imageURL: String
) {
self.preSignedURL = preSignedURL
self.imageURL = imageURL
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@
import Core

import Combine
import Foundation

public protocol ListDetailRepositoryInterface {
func fetchListDetail(missionId: Int, username: String?) -> AnyPublisher<ListDetailModel, Error>
func postStamp(missionId: Int, stampData: [Any]) -> AnyPublisher<ListDetailModel, Error>
func putStamp(missionId: Int, stampData: [Any]) -> Driver<Int>
func deleteStamp(stampId: Int) -> Driver<Bool>
func fetchListDetail(missionId: Int, username: String?) -> AnyPublisher<ListDetailModel, Error>
func getPresignedURL() -> AnyPublisher<PresignedUrlModel, Error>
func uploadMedia(imageData: Data, presignedUrl: String) -> AnyPublisher<Void, Error>
func postStamp(stampData: ListDetailRequestModel) -> AnyPublisher<ListDetailModel, Error>
func putStamp(stampData: ListDetailRequestModel) -> Driver<Int>
func deleteStamp(stampId: Int) -> Driver<Bool>
}
Loading

0 comments on commit 41891a2

Please sign in to comment.