Skip to content

Commit

Permalink
Feature/밈상세화면 구현 #23 (#27)
Browse files Browse the repository at this point in the history
* feat: memeDetail 모듈 추가

* feat: kingfisher 추가

* design: ㅋ, 개웃겨 리소스 추가

* feat: MemeDetail 모델 구현

* feat: MemeDetail UI 구현

* chore: 코드리뷰 봇 무시

* refactor: 재사용 가능한 뷰 분리

* move: 파일 경로 변경

* feat: util 관련 router, viewmodeltype 구현

* fix: farmemedetail에 id 필드 추가

* feat: 상세에서 필요한 usecase 정의

* feat: memedetailviewmodel 구현
  • Loading branch information
chansooo authored Jun 29, 2024
1 parent 842cbba commit 3e691e0
Show file tree
Hide file tree
Showing 15 changed files with 539 additions and 2 deletions.
5 changes: 4 additions & 1 deletion Projects/Core/PPACModels/Sources/Meme/MemeDetail.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import Foundation
public struct MemeDetail {

// MARK: - Properties

public let id: String
public let title: String
public let keywords: [String]
public let imageUrlString: String
Expand All @@ -21,13 +21,15 @@ public struct MemeDetail {
// MARK: - Initializers

public init(
id: String,
title: String,
keywords: [String],
imageUrlString: String,
source: String,
isTodayMeme: Bool,
reaction: Int
) {
self.id = id
self.title = title
self.keywords = keywords
self.imageUrlString = imageUrlString
Expand All @@ -39,6 +41,7 @@ public struct MemeDetail {

public extension MemeDetail {
static let mock = MemeDetail(
id: "1",
title: "나는 공부를 찢어",
keywords: ["공부", "학생", "시험기간"],
imageUrlString: "https://avatars.githubusercontent.com/u/26344479?s=64&v=4",
Expand Down
59 changes: 59 additions & 0 deletions Projects/Core/PPACUtil/Sources/Router.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
//
// Router.swift
// PPACUtil
//
// Created by kimchansoo on 6/29/24.
//

import UIKit
import SwiftUI

public protocol RouterDelegate: AnyObject {

func didFinish(childRouter: Router)
}

public protocol Router: AnyObject {

var delegate: RouterDelegate? { get set }
var navigationController: UINavigationController { get set }
var childRouters: [Router] { get set }

func start()
func finish()
func popView()
func dismissView()
}

public extension Router {

func finish() {
childRouters.removeAll()
delegate?.didFinish(childRouter: self)
}

func popView() {
self.navigationController.popViewController(animated: true)
}

func dismissView() {
navigationController.dismiss(animated: true)
}

func pushView<V: View>(_ view: V, animated: Bool = true) {
let viewController = UIHostingController(rootView: view)
navigationController.pushViewController(viewController, animated: animated)
}

func presentModallyView<V: View>(_ view: V, animated: Bool = true) {
let viewController = UIHostingController(rootView: view)
viewController.modalPresentationStyle = .formSheet
navigationController.present(viewController, animated: animated)
}

func presentFullscreenView<V: View>(_ view: V, animated: Bool = true) {
let viewController = UIHostingController(rootView: view)
viewController.modalPresentationStyle = .fullScreen
navigationController.present(viewController, animated: animated)
}
}
17 changes: 17 additions & 0 deletions Projects/Core/PPACUtil/Sources/ViewModelType.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//
// ViewModelType.swift
// PPACUtil
//
// Created by kimchansoo on 6/29/24.
//

import Foundation

public protocol ViewModelType {
associatedtype Action
associatedtype State

var state: State { get }

func dispatch(type: Action)
}
2 changes: 1 addition & 1 deletion Projects/Core/PPACUtil/Sources/dummy.swift
Original file line number Diff line number Diff line change
@@ -1 +1 @@
더미임미다
//더미임미다
1 change: 1 addition & 0 deletions Projects/Features/MemeDetail/Project.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ let project = Project(
.ResourceKit,
.Core.DesignSystem,
.Core.PPACModels,
.Core.PPACUtil,
]
)
]
Expand Down
38 changes: 38 additions & 0 deletions Projects/Features/MemeDetail/Sources/Domain/CopyImageUseCase.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//
// CopyImageUseCase.swift
// MemeDetail
//
// Created by kimchansoo on 6/29/24.
//

import Foundation
import UniformTypeIdentifiers
import UIKit
import Dependencies

public protocol CopyImageUseCase {
func execute(data: Data)
}

public final class CopyImageUseCaseImpl: CopyImageUseCase {


// MARK: - Properties

// MARK: - Initializers

// MARK: - Methods

public func execute(data: Data) {
let pasteboard = [
[UTType.png.identifier : data],
]
UIPasteboard.general.setItems(pasteboard)
}
}
//
//public enum CopyImageUseCaseKey: DependencyKey, TestDependencyKey {
// public static let liveValue: any CopyImageUseCase = CopyImageUseCaseImpl()
// public static let testValue: any CopyImageUseCase = CopyImageUseCaseImpl()
// public static let previewValue: any CopyImageUseCase = CopyImageUseCaseImpl()
//}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//
// PostFarmemeUseCase.swift
// MemeDetail
//
// Created by kimchansoo on 6/29/24.
//

import Foundation

import Dependencies

public protocol PostFarmemeUseCase {
func execute(id: String) async -> Bool
}

public final class PostFarmemeUseCaseImpl: PostFarmemeUseCase {

// MARK: - Properties

// MARK: - Initializers

// MARK: - Methods

public func execute(id: String) async -> Bool {
return false
}
}

public final class MockPostFarmemeUseCase: PostFarmemeUseCase {
public func execute(id: String) async -> Bool {
return false
}
}

public enum PostFarmemeUseCaseKey: DependencyKey {
public static let liveValue: any PostFarmemeUseCase = MockPostFarmemeUseCase()
public static let testValue: any PostFarmemeUseCase = MockPostFarmemeUseCase()
public static let previewValue: any PostFarmemeUseCase = MockPostFarmemeUseCase()
}
41 changes: 41 additions & 0 deletions Projects/Features/MemeDetail/Sources/Domain/PostLikeUseCase.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//
// PostLikeUseCase.swift
// MemeDetail
//
// Created by kimchansoo on 6/29/24.
//

import Foundation

import Dependencies

public protocol PostLikeUseCase {

func execute(id: String) async -> Bool
}

public final class PostLikeUseCaseImpl: PostLikeUseCase {

// MARK: - Properties

// MARK: - Initializers

// MARK: - Methods

public func execute(id: String) async -> Bool {
// TODO: - api 나오면 연결
return true
}
}

public final class MockPostLikeUseCase: PostLikeUseCase {
public func execute(id: String) async -> Bool {
return true
}
}

public enum PostLikeUseCaseKey: DependencyKey {
public static let liveValue: any PostLikeUseCase = MockPostLikeUseCase()
public static let testValue: any PostLikeUseCase = MockPostLikeUseCase()
public static let previewValue: any PostLikeUseCase = MockPostLikeUseCase()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
//
// MemeDetailCardView.swift
// MemeDetail
//
// Created by kimchansoo on 6/29/24.
//

import SwiftUI

import PPACModels
import Kingfisher
import ResourceKit

struct MemeDetailCardView: View {

// MARK: - Properties

let meme: MemeDetail

// MARK: - UI

var body: some View {
VStack(alignment: .center, spacing: 0) {

MemeImageView(imageUrlString: meme.imageUrlString)
.padding(.bottom, 25)

titleLabel
.padding(.bottom, 5)

HashTagView(keywords: meme.keywords)
.padding(.bottom, 11)

subtitleLabel
.padding(.bottom, 20)

LikeButton()
.padding(.bottom, 20)
}
.padding(10)
.background(.white)
.cornerRadius(20)
.overlay(
RoundedRectangle(cornerRadius: 20)
.inset(by: 1)
.stroke(.black, lineWidth: 2)
)
.padding(.horizontal, 24)
}

// MARK: - Methods

var titleLabel: some View {
Text(meme.title)
.font(Font.Heading.large.weight(.semibold))
.multilineTextAlignment(.center)
.foregroundColor(Color.Text.primary)
.frame(maxWidth: .infinity, alignment: .center)
}

var subtitleLabel: some View {
Text("출처: \(self.meme.source)")
.font(Font.Body.xsmall)
.multilineTextAlignment(.center)
.foregroundColor(Color.Icon.assistive)
}
}

#Preview {
MemeDetailCardView(meme: .mock)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//
// MemeDetailRouter.swift
// MemeDetail
//
// Created by kimchansoo on 6/29/24.
//

import UIKit
import SwiftUI

import PPACUtil
import PPACModels

final class MemeDetailRouter: Router {


// MARK: - Properties

var delegate: (any RouterDelegate)?

var navigationController: UINavigationController

var childRouters: [any Router] = []

let meme: MemeDetail

// MARK: - Initializers

init(_ navigationController: UINavigationController, meme: MemeDetail) {
navigationController.isNavigationBarHidden = true
self.meme = meme
self.navigationController = navigationController
}

// MARK: - UI

// MARK: - Override

// MARK: - Methods

func start() {
self.pushView(MemeDetailView(meme: meme))
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//
// MemeDetailView.swift
// MemeDetail
//
// Created by kimchansoo on 6/28/24.
//

import SwiftUI

import PPACModels

struct MemeDetailView: View {

// MARK: - Properties
private let meme: MemeDetail

// MARK: - Initializers

init(meme: MemeDetail) {
self.meme = meme
}

// MARK: - UI

var body: some View {
MemeDetailCardView(meme: meme)
}
}

#Preview {
MemeDetailView(meme: .mock)
}
Loading

0 comments on commit 3e691e0

Please sign in to comment.