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
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
source "https://rubygems.org"

gem "fastlane"
gem "multi_json"
18 changes: 16 additions & 2 deletions Projects/Feature/GoalDetail/Sources/Detail/GoalDetailView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,22 @@ private extension GoalDetailView {
cardOffset = repeatedCardOffset(for: width)
isCrossingDuringDrag = shouldCrossCards(for: width)
}
.onEnded { _ in
.onEnded { value in
guard !store.isEditing else { return }

let translation = value.translation
let width = resistedDragWidth(
for: translation.width,
velocity: value.velocity.width
)

guard abs(width) >= abs(translation.height) else {
withAnimation(.spring(response: 0.2, dampingFraction: 0.94)) {
resetDragState()
}
return
}

withAnimation(.spring(response: 0.2, dampingFraction: 0.94)) {
resetDragState()
store.send(.view(.cardSwiped))
Expand Down Expand Up @@ -431,7 +445,7 @@ private extension GoalDetailView {
.padding(.bottom, 26)
.frame(width: rectFrame.width, height: rectFrame.height, alignment: .bottom)
.rotationEffect(frontCardRotation)
.offset(x: posX, y: posY - keyboardInset)
.offset(x: posX + cardOffset, y: posY - keyboardInset)
.animation(.easeOut(duration: 0.25), value: keyboardInset)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ public struct HomeReducer {
/// 홈 화면에서 외부로 전달하는 이벤트입니다.
public enum Delegate {
case goToGoalDetail(id: Int64, owner: GoalDetail.Owner, verificationDate: String)
case goToStatsDetail(id: Int64)
case goToStatsDetail(id: Int64, calendarDate: TXCalendarDate)
case goToMakeGoal(GoalCategory)
case goToEditGoalList(date: TXCalendarDate)
case goToSettings
Expand Down
51 changes: 21 additions & 30 deletions Projects/Feature/Home/Sources/Home/HomeEmptyContentSection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,42 +10,34 @@ import FeatureHomeInterface
import SharedDesignSystem

/// `hadFirstGoal`을 읽는 빈 상태 영역입니다.
/// `emptyScrollHeight`는 로컬 `@State`로 관리해 다른 콘텐츠 section 재렌더링에 의해
/// 초기화되지 않게 합니다.
/// `goalEmptyView`의 center anchor를 기기 화면 기준 y축 중앙에 배치합니다.
struct HomeEmptyContentSection: View {
let store: StoreOf<HomeReducer>

@State private var emptyScrollHeight: CGFloat = 0

var body: some View {
VStack(spacing: 0) {
HomeHeaderRow(store: store)
.padding(.horizontal, 20)
.padding(.top, 16)
GeometryReader { geo in
let frame = geo.frame(in: .global)
let deviceHeight = UIScreen.main.bounds.height
let deviceCenterYInSection = max(0, deviceHeight / 2 - frame.minY)

ScrollView {
goalEmptyView
// 실제 가시 영역 기준으로 중앙 정렬되도록 탭바 높이만큼 차감
.frame(maxWidth: .infinity, minHeight: max(0, emptyScrollHeight - 58))
.padding(.bottom, 58)
}
.scrollIndicators(.hidden)
.refreshable {
store.send(.view(.refreshPulled))
}
.overlay(alignment: .bottomTrailing) {
emptyArrow
}
.frame(maxHeight: .infinity)
.background {
GeometryReader { geo in
Color.clear
.onAppear { emptyScrollHeight = geo.size.height }
.onChange(of: geo.size.height) { _, newValue in
emptyScrollHeight = newValue
}
ScrollView {
goalEmptyView
.frame(width: geo.size.width)
.position(x: geo.size.width / 2, y: deviceCenterYInSection)
}
.scrollIndicators(.hidden)
.refreshable {
store.send(.view(.refreshPulled))
}
.overlay(alignment: .bottomTrailing) {
if store.hadFirstGoal == false {
emptyArrow
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
.frame(maxHeight: .infinity)
}
}

Expand Down Expand Up @@ -79,12 +71,11 @@ struct HomeEmptyContentSection: View {
}
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}

var emptyArrow: some View {
Image.Illustration.arrow
.padding(.bottom, 71 + 58)
.padding(.bottom, 71 + TXTabBarLayout.height)
.padding(.trailing, 86)
.ignoresSafeArea()
}
Expand Down
2 changes: 1 addition & 1 deletion Projects/Feature/Home/Sources/Home/HomeReducer+Impl.swift
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ extension HomeReducer {
return .send(.delegate(.goToGoalDetail(id: card.id, owner: .mySelf, verificationDate: verificationDate)))

case let .view(.headerTapped(card)):
return .send(.delegate(.goToStatsDetail(id: card.id)))
return .send(.delegate(.goToStatsDetail(id: card.id, calendarDate: state.calendarDate)))

case .view(.floatingButtonTapped):
state.isAddGoalPresented = true
Expand Down
4 changes: 2 additions & 2 deletions Projects/Feature/Home/Sources/Root/HomeCoordinator+Impl.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@ extension HomeCoordinator {
state.notification = .init()
return .none

case let .home(.delegate(.goToStatsDetail(id))):
case let .home(.delegate(.goToStatsDetail(id, date))):
state.routes.append(.statsDetail)
state.statsDetail = .init(goalId: id)
state.statsDetail = .init(goalId: id, initialMonth: date)
return .none

case .statsDetail(.delegate(.navigateBack)):
Expand Down
19 changes: 14 additions & 5 deletions Projects/Feature/MakeGoal/Sources/MakeGoalView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,9 @@ private extension MakeGoalView {
Spacer()

if store.showPeriodCount {
dropDownButton { store.send(.view(.periodSelected)) }
dropDownButton(text: store.periodCountText) {
store.send(.view(.periodSelected))
}
}
}
}
Expand All @@ -190,7 +192,9 @@ private extension MakeGoalView {

Spacer()

dropDownButton { store.send(.view(.startDateTapped)) }
dropDownButton(text: store.startDateText) {
store.send(.view(.startDateTapped))
}
}
.frame(height: 32)
.padding(.vertical, 16)
Expand All @@ -214,7 +218,9 @@ private extension MakeGoalView {

Spacer()

dropDownButton { store.send(.view(.endDateTapped)) }
dropDownButton(text: store.endDateText) {
store.send(.view(.endDateTapped))
}
}
.padding(.vertical, 21.5)
}
Expand All @@ -236,9 +242,12 @@ private extension MakeGoalView {
.padding(.vertical, -1)
}

func dropDownButton(_ action: @escaping () -> Void) -> some View {
func dropDownButton(
text: String,
action: @escaping () -> Void
) -> some View {
HStack(spacing: 0) {
Text(store.startDateText)
Text(text)
.typography(.b2_14r)
.foregroundStyle(Color.Gray.gray500)
Image.Icon.Symbol.arrow2Down
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ import SharedDesignSystem
/// ## 사용 예시
/// ```swift
/// let store = Store(
/// initialState: StatsDetailReducer.State()
/// initialState: StatsDetailReducer.State(
/// goalId: 1,
/// initialMonth: TXCalendarDate()
/// )
/// ) {
/// StatsDetailReducer(reducer: Reduce { _, _ in .none })
/// }
Expand Down Expand Up @@ -78,15 +81,17 @@ public struct StatsDetailReducer {
///
/// ## 사용 예시
/// ```swift
/// let state = StatsDetailReducer.State(goalId: 1)
/// let state = StatsDetailReducer.State(
/// goalId: 1,
/// initialMonth: TXCalendarDate()
/// )
/// ```
public init(goalId: Int64) {
public init(goalId: Int64, initialMonth: TXCalendarDate) {
self.goalId = goalId

let currentMonth = TXCalendarDate()
self.currentMonth = currentMonth

self.currentMonth = initialMonth
self.monthlyData = TXCalendarDataGenerator.generateMonthData(
for: currentMonth,
for: initialMonth,
hideAdjacentDates: true
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ public struct StatsReducer {

/// StatsReducer가 상위 Coordinator로 전달하는 이벤트입니다.
public enum Delegate {
case goToStatsDetail(goalId: Int64)
case goToStatsDetail(goalId: Int64, calendarDate: TXCalendarDate)
}

case view(View)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ extension StatsCoordinator {
let reducer = Reduce<State, Action> { state, action in
switch action {
// MARK: - Child Action
case let .stats(.delegate(.goToStatsDetail(goalId))):
case let .stats(.delegate(.goToStatsDetail(goalId, calendarDate))):
state.routes.append(.statsDetail)
state.statsDetail = .init(goalId: goalId)
state.statsDetail = .init(goalId: goalId, initialMonth: calendarDate)
return .none

case let .statsDetail(.delegate(.goToGoalDetail(goalId, isCompletedPartner, date))):
Expand Down
13 changes: 6 additions & 7 deletions Projects/Feature/Stats/Sources/Detail/StatsDetailView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,7 @@ private extension StatsDetailView {
summaryTitle(for: summary.title)
summartyContent(content: summary.content, isCompletedCount: summary.isCompletedCount)
.layoutPriority(1)

Spacer()
.frame(maxWidth: .infinity, alignment: .leading)
}
}
}
Expand Down Expand Up @@ -188,7 +187,6 @@ private extension StatsDetailView {
Text(content[0])
.typography(.b4_12b)
.foregroundStyle(Color.Gray.gray500)
.lineLimit(1)

if isCompletedCount {
Text("|")
Expand All @@ -199,11 +197,9 @@ private extension StatsDetailView {
Text(content[1])
.typography(.b4_12b)
.foregroundStyle(Color.Gray.gray500)
.lineLimit(1)
}
}
.lineLimit(1)
.fixedSize(horizontal: true, vertical: false)
.frame(maxWidth: .infinity, alignment: .leading)
}

@ViewBuilder
Expand Down Expand Up @@ -266,7 +262,10 @@ private extension StatsDetailView {
#Preview {
StatsDetailView(
store: Store(
initialState: StatsDetailReducer.State(goalId: 1),
initialState: StatsDetailReducer.State(
goalId: 1,
initialMonth: TXCalendarDate()
),
reducer: { StatsDetailReducer() }
)
)
Expand Down
3 changes: 2 additions & 1 deletion Projects/Feature/Stats/Sources/Stats/StatsReducer+Impl.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ extension StatsReducer {
return .send(.internal(.fetchStats))

case let .view(.statsCardTapped(goalId)):
return .send(.delegate(.goToStatsDetail(goalId: goalId)))
let date = state.isOngoing ? state.currentMonth : TXCalendarDate()
return .send(.delegate(.goToStatsDetail(goalId: goalId, calendarDate: date)))

// MARK: - Update State
case let .presentation(.showToast(toast)):
Expand Down
2 changes: 1 addition & 1 deletion Projects/Feature/Stats/Sources/Stats/StatsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ private extension StatsView {
if store.isOngoing {
VStack(spacing: 8) {
Image.Illustration.scare
Text("아직 목표가 없어요!")
Text("이 달은 목표가 없어요!")
.typography(.t2_16b)
.foregroundStyle(Color.Gray.gray400)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,27 @@ import SwiftUI

struct TXRoundButton: View {
let shape: TXButtonShape
let allowsActionWhenDisabled: Bool
let onTap: () -> Void

public var body: some View {
if case let .round(style, size, state) = shape {
Button {
onTap()
switch state {
case .disabled:
if allowsActionWhenDisabled {
onTap()
}
case .standard:
onTap()
}
} label: {
ZStack {
ZStack(alignment: .top) {
Capsule()
.fill(style.backgroundColor(state: state))
.frame(maxWidth: size.frameWidth)
.frame(height: size.backgroundHeight(state: state))
.padding(.top, size.bottomYOffset(state: state))
.frame(height: size.backgroundHeight)
.padding(.top, size.backgroundYOffset)

Text(style.text)
.typography(size.typography)
Expand All @@ -34,8 +42,8 @@ struct TXRoundButton: View {
lineWidth: size.borderWidth
)
.background(style.foregroundColor(state: state), in: .capsule)
.padding(.top, size.foregroundYOffset(state: state))
}
.padding(.top, size.topYOffset(state: state))
}
.buttonStyle(.plain)
} else {
Expand Down Expand Up @@ -112,29 +120,19 @@ private extension TXButtonShape.TXRoundSize {
}
}

func backgroundHeight(state: TXButtonShape.TXRoundState) -> CGFloat {
var backgroundHeight: CGFloat {
switch self {
case .l, .m: 70

case .s:
switch state {
case .standard: 31
case .disabled: 28
}
case .s: 28
}
}

func bottomYOffset(state: TXButtonShape.TXRoundState) -> CGFloat {
switch self {
case .s, .l, .m:
switch state {
case .standard: 4
case .disabled: 1
}
}
var backgroundYOffset: CGFloat {
4
}

func topYOffset(state: TXButtonShape.TXRoundState) -> CGFloat {
func foregroundYOffset(state: TXButtonShape.TXRoundState) -> CGFloat {
switch self {
case .s, .l, .m:
switch state {
Expand Down
Loading
Loading