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: 밈 등록하기 디자인 및 api 연결 #77

Merged
merged 16 commits into from
Sep 30, 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
2 changes: 2 additions & 0 deletions Projects/App/Project.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ let project = Project.configure(
"CFBundleVersion": "1",
"UILaunchStoryboardName": "launch",
"NSUserTrackingUsageDescription": "이 앱은 사용자 맞춤형 광고 제공 및 분석을 위해 사용자 추적 정보를 수집합니다.",
"NSPhotoLibraryUsageDescription": "밈 이미지 등록을 위해 앨범 접근 권한이 필요합니다.",
"UIUserInterfaceStyle": "Light", // 다크모드 방지
"NSAllowArbitraryLoads": true,
"NSAppTransportSecurity": [
Expand Down Expand Up @@ -75,6 +76,7 @@ let project = Project.configure(
"UILaunchStoryboardName": "launch",
"NSUserTrackingUsageDescription": "이 앱은 사용자 맞춤형 광고 제공 및 분석을 위해 사용자 추적 정보를 수집합니다.",
"UIUserInterfaceStyle": "Light", // 다크모드 방지
"NSPhotoLibraryUsageDescription": "밈 이미지 등록을 위해 앨범 접근 권한이 필요합니다.",
"NSAppTransportSecurity": [
"NSAllowsArbitraryLoads": true
]
Expand Down
27 changes: 27 additions & 0 deletions Projects/Core/DesignSystem/Sources/Extension/View+Extension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,31 @@ public extension View {
) -> some View {
clipShape(RoundedCorners(radius: radius, corners: corners))
}

// MARK: - Keyboard
func endTextEditing() {
UIApplication.shared.sendAction(
#selector(UIResponder.resignFirstResponder),
to: nil,
from: nil,
for: nil
)
}

func onKeyboardChange(_ action: @escaping (Bool) -> Void) -> some View {
self.onAppear {
NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillShowNotification, object: nil, queue: .main) { _ in
action(true)
}
NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillHideNotification, object: nil, queue: .main) { _ in
action(false)
}
}
.onDisappear {
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
}
}
}

public extension View {
Expand All @@ -29,3 +54,5 @@ public extension View {
)
}
}


93 changes: 0 additions & 93 deletions Projects/Core/DesignSystem/Sources/KeywordsTagView.swift

This file was deleted.

75 changes: 75 additions & 0 deletions Projects/Core/DesignSystem/Sources/View/FarmemeAlertView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
//
// FarmemeAlertView.swift
// DesignSystem
//
// Created by 장혜령 on 9/29/24.
//

import SwiftUI

import ResourceKit

public struct FarmemeAlertView: View {
private let title: String
private let description: String
private var dismiss: (() -> Void)

public init(title: String,
description: String,
dismiss: @escaping (() -> Void)
) {
self.title = title
self.description = description
self.dismiss = dismiss
}

public var body: some View {
VStack(spacing: 0) {
titleView

descriptionView
.padding(.top, 8)

confirmButton
.padding(.top, 14)
}
.padding(.horizontal, 30)
.padding(.vertical, 20)
.background(Color.Background.white)
.cornerRadius(20)
}


private var titleView: some View {
HStack {
Text(title)
.font(Font.Heading.Medium.semiBold)
.foregroundColor(Color.Text.primary)
.foregroundColor(.black)
Spacer()
}
}

private var descriptionView: some View {
HStack {
Text(description)
.font(Font.Body.Large.medium)
.foregroundColor(Color.Text.secondary)
.multilineTextAlignment(.leading)
Spacer()
}
}

private var confirmButton: some View {
HStack{
Spacer()
Button {
dismiss()
} label: {
Text("확인")
.font(Font.Body.Large.medium)
.foregroundColor(Color.Text.brand)
}
}
}
}
20 changes: 20 additions & 0 deletions Projects/Core/DesignSystem/Sources/View/Keyword/KeywordTag.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// KeywordTag.swift
// DesignSystem
//
// Created by 장혜령 on 9/24/24.
//

import Foundation

public struct KeywordTag: Hashable, Identifiable {
public let id: String
public let name: String
public let isSelected: Bool

public init(id: String, name: String, isSelected: Bool = false) {
self.id = id
self.name = name
self.isSelected = isSelected
}
}
141 changes: 141 additions & 0 deletions Projects/Core/DesignSystem/Sources/View/Keyword/KeywordsTagView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
//
// KeywordsTagView.swift
// DesignSystem
//
// Created by 리나 on 2024/06/29.
//

import SwiftUI
import ResourceKit

// thanks to NamS
public struct KeywordsTagView: View {
let keywordTags: [KeywordTag]
var onTapHandler: ((String) -> ())?

public init(keywordTags: [KeywordTag], onTapHandler: ((String) -> ())?) {
self.keywordTags = keywordTags
self.onTapHandler = onTapHandler
}

public var body: some View {
ScrollView {
FlowLayout(spacing: 8, lineSpacing: 8) {
ForEach(keywordTags, id: \.self) { keywordTag in
Text(keywordTag.name)
.font(Font.Body.Medium.medium)
.foregroundColor(
keywordTag.isSelected
? Color.Text.brand
: Color.Text.primary
)
.padding(.horizontal, 16)
.padding(.vertical, 9.5)
.background(
Capsule().foregroundStyle(
keywordTag.isSelected
? Color.Background.brandassistive
: Color.Background.assistive
)
)
.onTapGesture {
onTapHandler?(keywordTag.name)
}
}
}
}
}
}

struct FlowLayout: Layout {
var spacing: CGFloat?
var lineSpacing: CGFloat

init(spacing: CGFloat? = nil, lineSpacing: CGFloat) {
self.spacing = spacing
self.lineSpacing = lineSpacing
}

struct Cache {
var sizes: [CGSize] = []
var spacing: [CGFloat] = []
}

func makeCache(subviews: Subviews) -> Cache {
let sizes = subviews.map { $0.sizeThatFits(.unspecified) }
let spacing: [CGFloat] = subviews.indices.map { index in
guard index != subviews.count - 1 else {
return 0
}

return subviews[index].spacing.distance(
to: subviews[index+1].spacing,
along: .horizontal
)
}

return Cache(sizes: sizes, spacing: spacing)
}

func sizeThatFits(
proposal: ProposedViewSize,
subviews: Subviews,
cache: inout Cache
) -> CGSize {
var totalHeight = 0.0
var totalWidth = 0.0

var lineWidth = 0.0
var lineHeight = 0.0

for index in subviews.indices {
if lineWidth + cache.sizes[index].width > proposal.width ?? 0 {
totalHeight += lineHeight + lineSpacing // 줄 간격 추가
lineWidth = cache.sizes[index].width
lineHeight = cache.sizes[index].height
} else {
lineWidth += cache.sizes[index].width + (spacing ?? cache.spacing[index])
lineHeight = max(lineHeight, cache.sizes[index].height)
}

totalWidth = max(totalWidth, lineWidth)
}

totalHeight += lineHeight

return .init(width: totalWidth, height: totalHeight)
}

func placeSubviews(
in bounds: CGRect,
proposal: ProposedViewSize,
subviews: Subviews,
cache: inout Cache
) {
var lineX = bounds.minX
var lineY = bounds.minY
var lineHeight: CGFloat = 0

for index in subviews.indices {
if lineX + cache.sizes[index].width > (proposal.width ?? 0) {
lineY += lineHeight + lineSpacing // 줄 간격 추가
lineHeight = 0
lineX = bounds.minX
}

let position = CGPoint(
x: lineX + cache.sizes[index].width / 2,
y: lineY + cache.sizes[index].height / 2
)

lineHeight = max(lineHeight, cache.sizes[index].height)
lineX += cache.sizes[index].width + (spacing ?? cache.spacing[index])

subviews[index].place(
at: position,
anchor: .center,
proposal: ProposedViewSize(cache.sizes[index])
)
}
}
}
Loading
Loading