Skip to content
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
126 changes: 80 additions & 46 deletions Projects/Feature/GoalDetail/Sources/Detail/GoalDetailView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,31 +62,23 @@ public struct GoalDetailView: View {
}

public var body: some View {
VStack(spacing: 0) {
navigationBar
.zIndex(1)

if store.item != nil {
cardView
.padding(.horizontal, 27)
.padding(.top, isSEDevice ? 47 : 103)

if store.isCompleted {
completedBottomContent
} else if store.currentCompletedGoal?.status != .completed {
bottomButton
.padding(.top, 105)
.overlay(alignment: .bottomLeading) {
pokeImage
.offset(x: 79, y: -45)
}
GeometryReader { _ in
ZStack {
mainContent

if store.isEditing && store.isCommentFocused {
dimmedView
.ignoresSafeArea()
}

if shouldShowCommentOverlay {
floatingCommentOverlay
}
}

Spacer()
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
}
.ignoresSafeArea(.keyboard)
.background(dimmedView)
.background(Color.Common.white)
.toolbar(.hidden, for: .navigationBar)
.observeKeyboardFrame($keyboardFrame)
.onAppear {
Expand Down Expand Up @@ -121,6 +113,32 @@ public struct GoalDetailView: View {

// MARK: - SubViews
private extension GoalDetailView {
var mainContent: some View {
VStack(spacing: 0) {
navigationBar
.zIndex(1)

if store.item != nil {
cardView
.padding(.horizontal, 27)
.padding(.top, isSEDevice ? 47 : 103)

if store.isCompleted {
completedBottomContent
} else if store.currentCompletedGoal?.status != .completed {
bottomButton
.padding(.top, 105)
.overlay(alignment: .bottomLeading) {
pokeImage
.offset(x: 79, y: -45)
}
}
}

Spacer()
}
}

var navigationBar: some View {
TXNavigationBar(
style: .subContent(
Expand All @@ -135,7 +153,6 @@ private extension GoalDetailView {
store.send(.view(.navigationBarTapped(action)))
}
)
.overlay(dimmedView)
}

var cardView: some View {
Expand All @@ -149,6 +166,7 @@ private extension GoalDetailView {
.gesture(
DragGesture()
.onChanged { value in
guard !store.isEditing else { return }
let translation = value.translation
let width = resistedDragWidth(
for: translation.width,
Expand All @@ -169,6 +187,7 @@ private extension GoalDetailView {
isCrossingDuringDrag = shouldCrossCards(for: width)
}
.onEnded { _ in
guard !store.isEditing else { return }
withAnimation(.spring(response: 0.2, dampingFraction: 0.94)) {
resetDragState()
store.send(.view(.cardSwiped))
Expand All @@ -184,7 +203,6 @@ private extension GoalDetailView {
isCompleted: store.myCardIsCompleted,
imageData: store.pendingEditedImageData,
imageURL: store.myCard?.imageUrl,
comment: store.myCard?.comment ?? "",
showsMyEmoji: effectiveIsFrontMyCard && store.selectedReactionEmoji != nil
)
.offset(x: cardOffset * (effectiveIsFrontMyCard ? 1 : -1))
Expand All @@ -197,7 +215,6 @@ private extension GoalDetailView {
isCompleted: store.partnerCardIsCompleted,
imageData: nil,
imageURL: store.partnerCard?.imageUrl,
comment: store.partnerCard?.comment ?? "",
showsMyEmoji: false
)
.offset(x: cardOffset * (effectiveIsFrontMyCard ? -1 : 1))
Expand Down Expand Up @@ -250,7 +267,6 @@ private extension GoalDetailView {
lineWidth: 1.6
)
.frame(width: 336, height: 336)
.overlay(dimmedView)
.clipShape(shape)
}

Expand All @@ -260,7 +276,6 @@ private extension GoalDetailView {
isCompleted: Bool,
imageData: Data?,
imageURL: String?,
comment: String,
showsMyEmoji: Bool
) -> some View {
ZStack {
Expand All @@ -271,7 +286,6 @@ private extension GoalDetailView {
isCompleted: isCompleted,
imageData: imageData,
imageURL: imageURL,
comment: comment,
showsMyEmoji: showsMyEmoji
)
.opacity(isFront ? 1 : 0)
Expand All @@ -283,14 +297,12 @@ private extension GoalDetailView {
isCompleted: Bool,
imageData: Data?,
imageURL: String?,
comment: String,
showsMyEmoji: Bool
) -> some View {
if isCompleted {
completedImageCard(
imageData: imageData,
imageURL: imageURL,
comment: comment,
showsMyEmoji: showsMyEmoji
)
} else {
Expand Down Expand Up @@ -318,26 +330,28 @@ private extension GoalDetailView {
shape: shape,
lineWidth: 1.6
)
.overlay(dimmedView)
}

@ViewBuilder
func completedImageCard(
imageData: Data?,
imageURL: String?,
comment: String,
showsMyEmoji: Bool
) -> some View {
if let imageData,
let editedImage = UIImage(data: imageData) {
completedImageCardContainer(comment: comment, showsMyEmoji: showsMyEmoji) {
completedImageCardContainer(
showsMyEmoji: showsMyEmoji
) {
Image(uiImage: editedImage)
.resizable()
.scaledToFill()
}
} else if let imageURL,
let url = URL(string: imageURL) {
completedImageCardContainer(comment: comment, showsMyEmoji: showsMyEmoji) {
completedImageCardContainer(
showsMyEmoji: showsMyEmoji
) {
KFImage(url)
.resizable()
.scaledToFill()
Expand Down Expand Up @@ -373,22 +387,46 @@ private extension GoalDetailView {
)
.perfControl(slug: "goal-detail", element: "primary-cta")
}

@ViewBuilder
func commentCircle(comment: String) -> some View {
let keyboardInset = max(0, rectFrame.maxY - keyboardFrame.minY)
TXCommentCircle(
commentText: store.isEditing ? $store.commentText : .constant(comment),
isEditable: store.isEditing,
keyboardInset: keyboardInset,
isFocused: $store.isCommentFocused,
onFocused: { isFocused in
store.send(.view(.focusChanged(isFocused)))
}
)
.animation(.easeOut(duration: 0.25), value: keyboardInset)
}


var shouldShowCommentOverlay: Bool {
guard store.isCompleted, rectFrame != .zero else { return false }
return store.isEditing || !currentFrontComment.isEmpty
}

var currentFrontComment: String {
if effectiveIsFrontMyCard {
return store.myCard?.comment ?? ""
} else {
return store.partnerCard?.comment ?? ""
}
}

var floatingCommentOverlay: some View {
GeometryReader { rootGeo in
let rootFrame = rootGeo.frame(in: .global)
let posX = rectFrame.minX - rootFrame.minX
let posY = rectFrame.minY - rootFrame.minY

commentCircle(comment: currentFrontComment)
.padding(.bottom, 26)
.frame(width: rectFrame.width, height: rectFrame.height, alignment: .bottom)
.offset(x: posX, y: posY - keyboardInset)
.animation(.easeOut(duration: 0.25), value: keyboardInset)
}
}

var dimmedView: some View {
Color.Dimmed.dimmed70
.opacity(store.isEditing && store.isCommentFocused ? 1 : 0)
Expand All @@ -402,7 +440,6 @@ private extension GoalDetailView {
}

func completedImageCardContainer<Content: View>(
comment: String,
showsMyEmoji: Bool,
@ViewBuilder content: @escaping () -> Content
) -> some View {
Expand All @@ -416,14 +453,7 @@ private extension GoalDetailView {
.frame(maxWidth: .infinity, maxHeight: .infinity)
.clipped()
}
.overlay(dimmedView)
.clipShape(shape)
.overlay(alignment: .bottom) {
if !comment.isEmpty {
commentCircle(comment: comment)
.padding(.bottom, 26)
}
}
.insideBorder(
Color.Gray.gray500,
shape: shape,
Expand Down Expand Up @@ -500,6 +530,10 @@ private extension GoalDetailView {
isCrossingDuringDrag ? !store.isFrontMyCard : store.isFrontMyCard
}

var keyboardInset: CGFloat {
max(0, rectFrame.maxY - keyboardFrame.minY)
}

func repeatedCardOffset(for width: CGFloat) -> CGFloat {
let maxOffset = Constants.maxCardOffset
let direction: CGFloat = width >= 0 ? 1 : -1
Expand Down
15 changes: 8 additions & 7 deletions Projects/Feature/MakeGoal/Sources/MakeGoalView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ private extension MakeGoalView {
backgroundColor: Color.Common.white
)
),
onTap: { }
onTap: { store.send(.view(.emojiButtonTapped)) }
)
.insideBorder(
Color.Gray.gray500,
Expand Down Expand Up @@ -177,7 +177,6 @@ private extension MakeGoalView {
Spacer()

if store.showPeriodCount {
valueText(store.periodCountText)
dropDownButton { store.send(.view(.periodSelected)) }
}
}
Expand All @@ -191,7 +190,6 @@ private extension MakeGoalView {

Spacer()

valueText(store.startDateText)
dropDownButton { store.send(.view(.startDateTapped)) }
}
.frame(height: 32)
Expand All @@ -216,7 +214,6 @@ private extension MakeGoalView {

Spacer()

valueText(store.endDateText)
dropDownButton { store.send(.view(.endDateTapped)) }
}
.padding(.vertical, 21.5)
Expand All @@ -240,11 +237,15 @@ private extension MakeGoalView {
}

func dropDownButton(_ action: @escaping () -> Void) -> some View {
Button {
action()
} label: {
HStack(spacing: 0) {
Text(store.startDateText)
.typography(.b2_14r)
.foregroundStyle(Color.Gray.gray500)
Comment on lines +241 to +243

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 dropDownButton이 모든 row에서 재사용되는 걸로 보이는데, 내부 값이 store.startDateText로 하드코딩되면, 반복 주기 row나 종료일 row도 시작일을 표시하게 될거같아.

dropDownButton(text:action:)처럼 텍스트를 인자로 받고, 각 row에서 periodCountText, startDateText, endDateText를 각각 전달하도록 하는건 어때??

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

큰일날뻔 ㄷㄷ 마지막 pr에서 반영할게

Image.Icon.Symbol.arrow2Down
}
.onTapGesture {
action()
}
}

func sectionTitleText(_ text: String) -> some View {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ private extension ProofPhotoView {
}
.padding(.bottom, 28)
.frame(width: rectFrame.width, height: rectFrame.height, alignment: .bottom)
.offset(x: posX, y: posY)
.offset(x: posX, y: posY - keyboardInset)
.animation(.easeOut(duration: 0.25), value: keyboardInset)
}
}
Expand All @@ -362,7 +362,6 @@ private extension ProofPhotoView {
TXCommentCircle(
commentText: $store.commentText,
isEditable: true,
keyboardInset: keyboardInset,
isFocused: $store.isCommentFocused,
onFocused: { isFocused in
store.send(.view(.focusChanged(isFocused)))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@ struct TXRoundButton: View {
public var body: some View {
if case let .round(style, size, state) = shape {
Button {
if state != .disabled {
onTap()
}
onTap()
} label: {
ZStack {
Capsule()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ struct TXTopTabBar<Item: TXItem>: View {
} label: {
tabItem(item: item, isSelected: selectedItem == item)
}
.buttonStyle(.plain)
.frame(maxWidth: .infinity)
}
}
Expand Down
Loading
Loading