Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 검색 화면 구현 #33

Merged
merged 3 commits into from
Jun 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions Projects/Core/DesignSystem/Sources/BasicModal.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
//
// BasicModal.swift
// DesignSystem
//
// Created by 리나 on 2024/06/30.
//

import SwiftUI
import ResourceKit

// Thanks to 균
public struct BasicModal<Content: View>: View {
@Binding var isPresented: Bool
private let content: () -> Content
private var opacity: Double

public init(
isPresented: Binding<Bool>,
opacity: Double,
content: @escaping () -> Content
) {
self._isPresented = isPresented
self.opacity = opacity
self.content = content
}

public var body: some View {
GeometryReader { geometry in
ZStack {
if isPresented {
Color.black.opacity(opacity)
.onTapGesture {
self.isPresented.toggle()
}
.transition(.opacity)

content()
.padding(.horizontal, 40)
}
}
.edgesIgnoringSafeArea(.all)
}
}
}

extension View {
public func basicModal<Content: View>(
isPresented: Binding<Bool>,
opacity: Double,
@ViewBuilder content: @escaping () -> Content
) -> some View {
modifier(
BasicModalModifier(
content: {
BasicModal(
isPresented: isPresented,
opacity: opacity,
content: content
)
}
)
)
}
}

fileprivate struct BasicModalModifier<SheetContent>: ViewModifier where SheetContent: View {
var content: () -> BasicModal<SheetContent>

func body(content: Content) -> some View {
ZStack {
content
self.content()
}
}
}
87 changes: 87 additions & 0 deletions Projects/Core/DesignSystem/Sources/CategoryTagView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
//
// CategoryTagView.swift
// DesignSystem
//
// Created by 리나 on 2024/06/29.
//

import SwiftUI
import ResourceKit

// thanks to NamS
public struct CategoryTagView: View {
@State public var categories: [String]

public init(categories: [String]) {
self.categories = categories
}

public var body: some View {
ScrollView {
CategoryTagLayout(verticalSpacing: 8, horizontalSpacing: 8) {
ForEach(categories, id: \.self) { category in
Text(category)
.font(Font.Body.Medium.medium)
.foregroundColor(Color.Text.primary)
.padding(.horizontal, 16)
.padding(.vertical, 9.5)
.background(
Capsule().foregroundStyle(Color.Background.assistive)
)
}
}
}
.onAppear {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
let cacheValue = categories
categories = []
categories = cacheValue
}
}
}
}

struct CategoryTagLayout: Layout {
var verticalSpacing: CGFloat = 0
var horizontalSpacing: CGFloat = 0

func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout Cache) -> CGSize {
CGSize(width: proposal.width ?? 0, height: cache.height)
}

func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout Cache) {
var sumX: CGFloat = bounds.minX
var sumY: CGFloat = bounds.minY

for index in subviews.indices {
let view = subviews[index]
let viewSize = view.sizeThatFits(.unspecified)
guard let proposalWidth = proposal.width else { continue }

if (sumX + viewSize.width > proposalWidth) {
sumX = bounds.minX
sumY += viewSize.height
sumY += verticalSpacing
}

let point = CGPoint(x: sumX, y: sumY)
view.place(at: point, anchor: .topLeading, proposal: proposal)
sumX += viewSize.width
sumX += horizontalSpacing
}

if let firstViewSize = subviews.first?.sizeThatFits(.unspecified) {
cache.height = sumY + firstViewSize.height
}
}

struct Cache {
var height: CGFloat
}

func makeCache(subviews: Subviews) -> Cache {
return Cache(height: 0)
}

func updateCache(_ cache: inout Cache, subviews: Subviews) { }
}
38 changes: 38 additions & 0 deletions Projects/Core/DesignSystem/Sources/HorizontalMimScrollView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//
// HorizontalMimScrollView.swift
// DesignSystem
//
// Created by 리나 on 2024/06/29.
//

import SwiftUI
import ResourceKit

public protocol HorizontalMimItemProtocol: Hashable { }

public protocol HorizontalMimItemViewProtocol: View {
associatedtype Item: HorizontalMimItemProtocol
init(item: Item)
}

public struct HorizontalMimScrollView<Item: HorizontalMimItemProtocol, ItemView: HorizontalMimItemViewProtocol>: View where ItemView.Item == Item {
@Binding public var items: [Item]

public init(items: Binding<[Item]>) {
self._items = items
}

public var body: some View {
ScrollView(.horizontal) {
LazyHStack(spacing: 10) {
ForEach(items, id: \.self) { item in
ItemView(item: item)
}
.listStyle(.plain)
}
}
.contentMargins(20)
.scrollIndicators(.hidden)
.frame(height: 90)
}
}
38 changes: 38 additions & 0 deletions Projects/Core/DesignSystem/Sources/MimCategoryView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//
// MimCategoryView.swift
// DesignSystem
//
// Created by 리나 on 2024/06/30.
//

import SwiftUI
import ResourceKit

public struct MimCategoryView: View {
public let title: String
public let categories: [String]

public init(title: String, categories: [String]) {
self.title = title
self.categories = categories
}

public var body: some View {
VStack(spacing: 0) {
HStack {
Text(title)
.font(Font.Body.Small.semiBold)
.foregroundColor(Color.Text.tertiary)

Spacer()
}
.padding(.top, 4)
.padding(.bottom, 16)
.padding(.horizontal, 20)

CategoryTagView(categories: categories)
.padding(.horizontal, 20)
.padding(.bottom, 20)
}
}
}
48 changes: 48 additions & 0 deletions Projects/Core/PPACModels/Sources/Search/HotKeyword.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//
// HotKeyword.swift
// PPACModels
//
// Created by 리나 on 2024/06/29.
//

import Foundation

public struct HotKeyword: Hashable {

// MARK: - Properties

public let title: String
public let imageUrlString: String

// MARK: - Initializers

public init(
title: String,
imageUrlString: String
) {
self.title = title
self.imageUrlString = imageUrlString
}
}

public extension HotKeyword {
static let mock1 = HotKeyword(
title: "띠용오오우어어우어엉?",
imageUrlString: "https://www.blockmedia.co.kr/wp-content/uploads/2024/05/%EB%8F%84%EC%A7%80%EC%BD%94%EC%9D%B8Doge-%EC%B9%B4%EB%B6%80%EC%88%98.png"
)

static let mock2 = HotKeyword(
title: "짜란다짜란다",
imageUrlString: "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcR_xO_sgszdvyVBp8xz4B82kHmyyO0SNZO-4A&s"
)

static let mock3 = HotKeyword(
title: "후회",
imageUrlString: "https://s3.ap-northeast-2.amazonaws.com/univ-careet/FileData/Picture/202310/3e7e0445-3812-4c06-bc75-a1bed40a3332_770x426.png"
)

static let mock4 = HotKeyword(
title: "무한도전",
imageUrlString: "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQBnKb96Uc-894Fhgt_5xLsCvY0pSkCl0B4TA&s"
)
}
33 changes: 33 additions & 0 deletions Projects/Core/PPACModels/Sources/Search/MimCategory.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//
// MimCategory.swift
// PPACModels
//
// Created by 리나 on 2024/06/29.
//

import Foundation

public struct MimCategory: Hashable {
public let title: String
public let categories: [String]

public init(title: String, categories: [String]) {
self.title = title
self.categories = categories
}
}

public extension MimCategory {
static let mock1 = MimCategory(
title: "감정",
categories: ["행복", "슬픈", "무념무상", "분노", "웃긴", "피곤", "절망", "현타", "당황"]
)
static let mock2 = MimCategory(
title: "상황",
categories: ["회사", "대학", "공부", "연애", "긁", "다이어트", "주식", "고민", "축하", "칭찬"]
)
static let mock3 = MimCategory(
title: "컨텐츠",
categories: ["동물", "무한도전", "캐릭터", "짱구", "문상훈", "검정고무신", "그 외"]
)
}
6 changes: 5 additions & 1 deletion Projects/Features/Search/Project.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@ let project = Project(
sources: "Sources/**",
resources: "Resources/**",
dependencies: [

.ResourceKit,
.Core.DesignSystem,
.Core.PPACModels,
.ThirdParty.Dependency,
.ThirdParty.Kingfisher,
]
)
]
Expand Down
40 changes: 40 additions & 0 deletions Projects/Features/Search/Sources/View/FakeSearchBar.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//
// FakeSearchBar.swift
// DesignSystem
//
// Created by 리나 on 2024/06/29.
//

import SwiftUI
import ResourceKit

struct FakeSearchBar: View {
let placeHolder: String

init(placeHolder: String) {
self.placeHolder = placeHolder
}

var body: some View {
fakeTextField
.frame(maxWidth: .infinity)
.frame(height: 44)
.background(Color.Background.assistive)
.clipShape(RoundedRectangle(cornerRadius: 10))
.padding(.horizontal, 20)
.padding(.vertical, 16)
}

private var fakeTextField: some View {
HStack(spacing: 12) {
ResourceKitAsset.Icon.search.swiftUIImage

Text(placeHolder)
.font(Font.Body.Large.medium)
.foregroundColor(Color.Text.tertiary)

Spacer()
}
.padding(.horizontal, 16)
}
}
Loading
Loading