diff --git a/Projects/App/Sources/MainTab/MainTabFeatureView.swift b/Projects/App/Sources/MainTab/MainTabFeatureView.swift index 800285b6..0fbfd373 100644 --- a/Projects/App/Sources/MainTab/MainTabFeatureView.swift +++ b/Projects/App/Sources/MainTab/MainTabFeatureView.swift @@ -272,50 +272,53 @@ private extension MainTabView { var action: (TabAddSheetType) -> Void var body: some View { - HStack(spacing: 20) { - Spacer() - - ForEach(TabAddSheetType.allCases, id: \.self) { type in - Button(action: { action(type) }) { - VStack(spacing: 4) { - Spacer() - - type.icon - .renderingMode(.template) - .resizable() - .aspectRatio(contentMode: .fit) - .frame(width: 28, height: 28) - .foregroundStyle(.pokit(.icon(.inverseWh))) - - Text(type.title) - .pokitFont(.b3(.m)) - .foregroundStyle(.pokit(.text(.inverseWh))) - - Spacer() - } - .padding(.horizontal, 24) - .background { - RoundedRectangle(cornerRadius: 12, style: .continuous) - .foregroundStyle(.pokit(.bg(.brand))) + GeometryReader { proxy in + let bottomSafeArea = proxy.safeAreaInsets.bottom + HStack(spacing: 20) { + Spacer() + + ForEach(TabAddSheetType.allCases, id: \.self) { type in + Button(action: { action(type) }) { + VStack(spacing: 4) { + Spacer() + + type.icon + .renderingMode(.template) + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 28, height: 28) + .foregroundStyle(.pokit(.icon(.inverseWh))) + + Text(type.title) + .pokitFont(.b3(.m)) + .foregroundStyle(.pokit(.text(.inverseWh))) + + Spacer() + } + .padding(.horizontal, 24) + .background { + RoundedRectangle(cornerRadius: 12, style: .continuous) + .foregroundStyle(.pokit(.bg(.brand))) + } + .frame(height: 96) } - .frame(height: 96) } + + Spacer() } - - Spacer() - } - .padding(.top, 36) - .padding(.bottom, 48) - .pokitPresentationCornerRadius() - .pokitPresentationBackground() - .presentationDragIndicator(.visible) - .readHeight() - .onPreferenceChange(HeightPreferenceKey.self) { height in - if let height { - self.height = height + .padding(.bottom, 48 - bottomSafeArea) + .padding(.top, 36) + .pokitPresentationCornerRadius() + .pokitPresentationBackground() + .presentationDragIndicator(.visible) + .readHeight() + .onPreferenceChange(HeightPreferenceKey.self) { height in + if let height { + self.height = height + } } + .presentationDetents([.height(self.height)]) } - .presentationDetents([.height(self.height)]) } } } diff --git a/Projects/CoreKit/Sources/Data/Client/Keyboard/KeyboardClient+LiveKey.swift b/Projects/CoreKit/Sources/Data/Client/Keyboard/KeyboardClient+LiveKey.swift new file mode 100644 index 00000000..70cb7cd4 --- /dev/null +++ b/Projects/CoreKit/Sources/Data/Client/Keyboard/KeyboardClient+LiveKey.swift @@ -0,0 +1,39 @@ +// +// KeyboardClient+LiveKey.swift +// CoreKit +// +// Created by 김민호 on 3/31/25. +// + +import UIKit +import Combine +import Dependencies + +extension KeyboardClient: DependencyKey { + public static let liveValue: Self = { + .init( + isVisible: { + AsyncStream { continuation in + let notificationCenter = NotificationCenter.default + + let showObserver = notificationCenter + .publisher(for: UIResponder.keyboardWillShowNotification) + .map { _ in true } + + let hideObserver = notificationCenter + .publisher(for: UIResponder.keyboardWillHideNotification) + .map { _ in false } + + let cancellable = Publishers.Merge(showObserver, hideObserver) + .removeDuplicates() + .sink { isVisible in + continuation.yield(isVisible) + } + + continuation.onTermination = { _ in cancellable.cancel() } + } + } + ) + }() +} + diff --git a/Projects/CoreKit/Sources/Data/Client/Keyboard/KeyboardClient+TestKey.swift b/Projects/CoreKit/Sources/Data/Client/Keyboard/KeyboardClient+TestKey.swift new file mode 100644 index 00000000..ecca5175 --- /dev/null +++ b/Projects/CoreKit/Sources/Data/Client/Keyboard/KeyboardClient+TestKey.swift @@ -0,0 +1,20 @@ +// +// KeyboardClient+TestKey.swift +// CoreKit +// +// Created by 김민호 on 3/31/25. +// + +import Foundation + +import Dependencies + +extension KeyboardClient: TestDependencyKey { + public static let previewValue = Self.noop +} + +extension KeyboardClient { + public static let noop = Self( + isVisible: { .finished } + ) +} diff --git a/Projects/CoreKit/Sources/Data/Client/Keyboard/KeyboardClient.swift b/Projects/CoreKit/Sources/Data/Client/Keyboard/KeyboardClient.swift new file mode 100644 index 00000000..c17cccd6 --- /dev/null +++ b/Projects/CoreKit/Sources/Data/Client/Keyboard/KeyboardClient.swift @@ -0,0 +1,15 @@ +// +// KeyboardClient.swift +// CoreKit +// +// Created by 김민호 on 3/31/25. +// + +import Foundation + +import DependenciesMacros + +@DependencyClient +public struct KeyboardClient: Sendable { + public var isVisible: @Sendable () async -> AsyncStream = { .finished } +} diff --git a/Projects/DSKit/Sources/Components/PokitAlert.swift b/Projects/DSKit/Sources/Components/PokitAlert.swift index ea3c7896..2153bc1e 100644 --- a/Projects/DSKit/Sources/Components/PokitAlert.swift +++ b/Projects/DSKit/Sources/Components/PokitAlert.swift @@ -31,54 +31,58 @@ public struct PokitAlert: View { } public var body: some View { - VStack(spacing: 0) { - VStack(spacing: 8) { - title + GeometryReader { proxy in + let bottomSafeArea = proxy.safeAreaInsets.bottom + VStack(spacing: 0) { + VStack(spacing: 8) { + title + + if message != nil { + messageLabel + } + } + .padding(.top, 36) + .padding(.bottom, 20) - if message != nil { - messageLabel + PokitBottomSwitchRadio { + PokitPartSwitchRadio( + labelText: "취소", + selection: .constant(false), + to: true, + style: .stroke + ) { + cancelAction?() + dismiss() + } + .background() + + PokitPartSwitchRadio( + labelText: confirmText, + selection: .constant(true), + to: true, + style: .filled, + action: action + ) + .background() } + .pokitMaxWidth() } - .padding(.top, 36) - .padding(.bottom, 20) - - PokitBottomSwitchRadio { - PokitPartSwitchRadio( - labelText: "취소", - selection: .constant(false), - to: true, - style: .stroke - ) { - cancelAction?() - dismiss() + .pokitPresentationBackground() + .pokitPresentationCornerRadius() + .presentationDragIndicator(.visible) + .padding(.bottom, 36 - bottomSafeArea) + .readHeight() + .onPreferenceChange(HeightPreferenceKey.self) { height in + if let height { + self.height = height } - .background() - - PokitPartSwitchRadio( - labelText: confirmText, - selection: .constant(true), - to: true, - style: .filled, - action: action - ) - .background() } - .pokitMaxWidth() - } - .pokitPresentationBackground() - .pokitPresentationCornerRadius() - .presentationDragIndicator(.visible) - .readHeight() - .onPreferenceChange(HeightPreferenceKey.self) { height in - if let height { - self.height = height + .presentationDetents([.height(self.height)]) + .onAppear { + UINotificationFeedbackGenerator() + .notificationOccurred(.warning) } } - .presentationDetents([.height(self.height)]) - .onAppear { - UINotificationFeedbackGenerator() - .notificationOccurred(.warning) - } } private var title: some View { diff --git a/Projects/DSKit/Sources/Components/PokitBottomButton.swift b/Projects/DSKit/Sources/Components/PokitBottomButton.swift index 229c08af..1d4f9abd 100644 --- a/Projects/DSKit/Sources/Components/PokitBottomButton.swift +++ b/Projects/DSKit/Sources/Components/PokitBottomButton.swift @@ -37,7 +37,7 @@ public struct PokitBottomButton: View { } .disabled(state == .disable) .padding(.top, 16) - .padding(.bottom, 36) +// .padding(.bottom, 36) } private var label: some View { diff --git a/Projects/DSKit/Sources/Components/PokitBottomSwitchRadio.swift b/Projects/DSKit/Sources/Components/PokitBottomSwitchRadio.swift index 07a54ce5..ad65071d 100644 --- a/Projects/DSKit/Sources/Components/PokitBottomSwitchRadio.swift +++ b/Projects/DSKit/Sources/Components/PokitBottomSwitchRadio.swift @@ -20,7 +20,7 @@ public struct PokitBottomSwitchRadio: View { } .padding(.horizontal, 20) .padding(.top, 16) - .padding(.bottom, 28) +// .padding(.bottom, 28) .background(.pokit(.bg(.base))) } } diff --git a/Projects/DSKit/Sources/Components/PokitDeleteBottomSheet.swift b/Projects/DSKit/Sources/Components/PokitDeleteBottomSheet.swift index c8ccf28c..0a7f368d 100644 --- a/Projects/DSKit/Sources/Components/PokitDeleteBottomSheet.swift +++ b/Projects/DSKit/Sources/Components/PokitDeleteBottomSheet.swift @@ -22,51 +22,56 @@ public struct PokitDeleteBottomSheet: View { } public var body: some View { - VStack(spacing: 0) { - /// - 텍스트 영역 - VStack(spacing: 8) { - Text(type.sheetTitle) - .foregroundStyle(.pokit(.text(.primary))) - .pokitFont(.title2) - Text(type.sheetContents) - .fixedSize(horizontal: false, vertical: true) - .multilineTextAlignment(.center) - .foregroundStyle(.pokit(.text(.secondary))) - .pokitFont(.b2(.m)) + GeometryReader { proxy in + let bottomSafeArea = proxy.safeAreaInsets.bottom + + VStack(spacing: 0) { + /// - 텍스트 영역 + VStack(spacing: 8) { + Text(type.sheetTitle) + .foregroundStyle(.pokit(.text(.primary))) + .pokitFont(.title2) + Text(type.sheetContents) + .fixedSize(horizontal: false, vertical: true) + .multilineTextAlignment(.center) + .foregroundStyle(.pokit(.text(.secondary))) + .pokitFont(.b2(.m)) + } + .padding(.top, 36) + .padding(.bottom, 20) + /// - 취소 / 삭제 버튼 영역 + HStack(spacing: 8) { + PokitBottomButton( + "취소", + state: .default(.primary), + action: { delegateSend?(.cancelButtonTapped) } + ) + + PokitBottomButton( + "삭제", + state: .filled(.primary), + action: { delegateSend?(.deleteButtonTapped) } + ) + } } - .padding(.top, 36) - .padding(.bottom, 20) - /// - 취소 / 삭제 버튼 영역 - HStack(spacing: 8) { - PokitBottomButton( - "취소", - state: .default(.primary), - action: { delegateSend?(.cancelButtonTapped) } - ) - - PokitBottomButton( - "삭제", - state: .filled(.primary), - action: { delegateSend?(.deleteButtonTapped) } - ) + .padding(.horizontal, 20) + .padding(.bottom, 36 - bottomSafeArea) + .background(.white) + .pokitPresentationCornerRadius() + .pokitPresentationBackground() + .presentationDragIndicator(.visible) + .readHeight() + .onPreferenceChange(HeightPreferenceKey.self) { height in + if let height { + self.height = height + } } - } - .padding(.horizontal, 20) - .background(.white) - .pokitPresentationCornerRadius() - .pokitPresentationBackground() - .presentationDragIndicator(.visible) - .readHeight() - .onPreferenceChange(HeightPreferenceKey.self) { height in - if let height { - self.height = height + .presentationDetents([.height(self.height)]) + .onAppear { + UINotificationFeedbackGenerator() + .notificationOccurred(.warning) } } - .presentationDetents([.height(self.height)]) - .onAppear { - UINotificationFeedbackGenerator() - .notificationOccurred(.warning) - } } } //MARK: - Delegate diff --git a/Projects/DSKit/Sources/Components/PokitSelect.swift b/Projects/DSKit/Sources/Components/PokitSelect.swift index 8da611e8..cfddb5c0 100644 --- a/Projects/DSKit/Sources/Components/PokitSelect.swift +++ b/Projects/DSKit/Sources/Components/PokitSelect.swift @@ -14,8 +14,8 @@ public struct PokitSelect: View { private var selectedItem: Item? @State private var state: PokitSelect.SelectState - @State - private var showSheet: Bool = false + @Binding + private var isPresented: Bool private let label: String private let list: [Item]? @@ -24,6 +24,7 @@ public struct PokitSelect: View { public init( selectedItem: Binding = .constant(nil), + isPresented: Binding, state: PokitSelect.SelectState = .default, label: String, list: [Item]?, @@ -31,6 +32,7 @@ public struct PokitSelect: View { addAction: (() -> Void)? ) { self._selectedItem = selectedItem + self._isPresented = isPresented if selectedItem.wrappedValue != nil { self.state = .input } else { @@ -49,7 +51,7 @@ public struct PokitSelect: View { partSelectButton } .onChange(of: selectedItem) { onChangedSeletedItem($0) } - .sheet(isPresented: $showSheet) { + .sheet(isPresented: $isPresented) { PokitSelectSheet( list: list, itemSelected: { item in @@ -104,14 +106,14 @@ public struct PokitSelect: View { } private func partSelectButtonTapped() { - showSheet = true + isPresented = true } private func listCellTapped(_ item: Item) { withAnimation(.pokitDissolve) { self.selectedItem = item } - showSheet = false + isPresented = false } private func onChangedSeletedItem(_ newValue: Item?) { @@ -119,7 +121,7 @@ public struct PokitSelect: View { } private func listDismiss() { - showSheet = false + isPresented = false } } diff --git a/Projects/DSKit/Sources/Foundation/PokitButtonStyle.swift b/Projects/DSKit/Sources/Foundation/PokitButtonStyle.swift index e20e0fc8..05bc4c89 100644 --- a/Projects/DSKit/Sources/Foundation/PokitButtonStyle.swift +++ b/Projects/DSKit/Sources/Foundation/PokitButtonStyle.swift @@ -69,7 +69,7 @@ extension PokitButtonStyle.State { var iconColor: Color { switch self { - case .default: return .pokit(.icon(.disable)) + case .default: return .pokit(.icon(.tertiary)) case .stroke(_): return .pokit(.icon(.primary)) case .filled(_), .opacity: return .pokit(.icon(.inverseWh)) case .disable: return .pokit(.icon(.disable)) diff --git a/Projects/DSKit/Sources/Modifiers/ScrollOffsetKey.swift b/Projects/DSKit/Sources/Modifiers/ScrollOffsetKey.swift new file mode 100644 index 00000000..f6bf0341 --- /dev/null +++ b/Projects/DSKit/Sources/Modifiers/ScrollOffsetKey.swift @@ -0,0 +1,15 @@ +// +// ScrollOffsetKey.swift +// DSKit +// +// Created by 김민호 on 5/18/25. +// + +import SwiftUI + +public struct ScrollOffsetKey: PreferenceKey { + public static var defaultValue: CGFloat = 0 + public static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) { + value += nextValue() + } +} diff --git a/Projects/Feature/FeatureCategoryDetail/Sources/CategoryDetailView.swift b/Projects/Feature/FeatureCategoryDetail/Sources/CategoryDetailView.swift index 733c3676..42ad93ed 100644 --- a/Projects/Feature/FeatureCategoryDetail/Sources/CategoryDetailView.swift +++ b/Projects/Feature/FeatureCategoryDetail/Sources/CategoryDetailView.swift @@ -18,7 +18,9 @@ public struct CategoryDetailView: View { /// - Properties @Perception.Bindable public var store: StoreOf - + @State private var currentOffset: CGFloat = 0 + @State private var targetOffset: CGFloat = 0 + @State private var isSticky: Bool = false /// - Initializer public init(store: StoreOf) { self.store = store @@ -28,12 +30,36 @@ public struct CategoryDetailView: View { public extension CategoryDetailView { var body: some View { WithPerceptionTracking { - VStack(spacing: 24) { - header - PokitDivider().padding(.horizontal, -20) - filterHeader - contentScrollView + ScrollView { + VStack(spacing: 24) { + header + scrollObservableView + LazyVStack(spacing: 0, pinnedViews: [.sectionHeaders]) { + Section { + contentScrollView + } header: { + VStack(spacing: 24) { + PokitDivider().padding(.horizontal, -20) + filterHeader + } + .padding(.bottom, 16) + .background(.white) + } + } + } + } + .onPreferenceChange(ScrollOffsetKey.self) { + if $0 != targetOffset { + currentOffset = $0 + } } + .onChange(of: currentOffset, perform: { newOffSet in + if newOffSet != targetOffset && newOffSet + targetOffset < 10 { + isSticky = true + } else { + isSticky = false + } + }) .padding(.horizontal, 20) .padding(.top, 12) .pokitNavigationBar { navigationBar } @@ -89,7 +115,7 @@ public extension CategoryDetailView { //MARK: - Configure View private extension CategoryDetailView { var navigationBar: some View { - PokitHeader { + PokitHeader(title: isSticky ? store.category.categoryName : "") { PokitHeaderItems(placement: .leading) { PokitToolbarButton( .icon(.arrowLeft), @@ -164,10 +190,12 @@ private extension CategoryDetailView { .foregroundStyle(textColor) .pokitFont(.b2(.m)) } - Text("#\(store.category.keywordType.title)") - .foregroundStyle(textColor) - .pokitFont(.b2(.m)) - .padding(.leading, 4.5) + if store.category.keywordType != .default { + Text("#\(store.category.keywordType.title)") + .foregroundStyle(textColor) + .pokitFont(.b2(.m)) + .padding(.leading, 4.5) + } } .padding(.bottom, 16) PokitIconLButton( @@ -240,31 +268,29 @@ private extension CategoryDetailView { Spacer() } } else { - ScrollView(showsIndicators: false) { - LazyVStack(spacing: 0) { - ForEach( - Array(store.scope(state: \.contents, action: \.contents)) - ) { store in - let isFirst = store.state.id == self.store.contents.first?.id - let isLast = store.state.id == self.store.contents.last?.id - - ContentCardView( - store: store, - type: .linkList, - isFirst: isFirst, - isLast: isLast - ) - } - - if store.hasNext { - PokitLoading() - .task { await send(.pagenation).finish() } - } + LazyVStack(spacing: 0) { + ForEach( + Array(store.scope(state: \.contents, action: \.contents)) + ) { store in + let isFirst = store.state.id == self.store.contents.first?.id + let isLast = store.state.id == self.store.contents.last?.id - Spacer() + ContentCardView( + store: store, + type: .linkList, + isFirst: isFirst, + isLast: isLast + ) } - .padding(.bottom, 36) + + if store.hasNext { + PokitLoading() + .task { await send(.pagenation).finish() } + } + + Spacer() } + .padding(.bottom, 36) } } else { PokitLoading() @@ -296,6 +322,18 @@ private extension CategoryDetailView { ) } } + private var scrollObservableView: some View { + GeometryReader { proxy in + let offsetY = proxy.frame(in: .global).origin.y + Color.clear + .preference( + key: ScrollOffsetKey.self, + value: offsetY + ) + .onAppear { targetOffset = offsetY } + } + .frame(height: 0) + } } //MARK: - Preview #Preview { @@ -322,5 +360,3 @@ private extension CategoryDetailView { ) } } - - diff --git a/Projects/Feature/FeatureCategoryDetail/Sources/Sheet/CategoryFilterSheet.swift b/Projects/Feature/FeatureCategoryDetail/Sources/Sheet/CategoryFilterSheet.swift index 110c63e8..d751a5ce 100644 --- a/Projects/Feature/FeatureCategoryDetail/Sources/Sheet/CategoryFilterSheet.swift +++ b/Projects/Feature/FeatureCategoryDetail/Sources/Sheet/CategoryFilterSheet.swift @@ -113,6 +113,7 @@ private extension CategoryFilterSheet { ) } ) + .padding(.bottom, 36) } .padding(.horizontal, 20) } diff --git a/Projects/Feature/FeatureCategorySetting/Sources/PokitCategorySettingFeature.swift b/Projects/Feature/FeatureCategorySetting/Sources/PokitCategorySettingFeature.swift index 979025fe..25acbb43 100644 --- a/Projects/Feature/FeatureCategorySetting/Sources/PokitCategorySettingFeature.swift +++ b/Projects/Feature/FeatureCategorySetting/Sources/PokitCategorySettingFeature.swift @@ -23,6 +23,8 @@ public struct PokitCategorySettingFeature { var categoryClient @Dependency(UserClient.self) var userClient + @Dependency(KeyboardClient.self) + var keyboardClient /// - State @ObservableState public struct State: Equatable { @@ -55,6 +57,7 @@ public struct PokitCategorySettingFeature { var isProfileSheetPresented: Bool = false var isKeywordSheetPresented: Bool = false var pokitNameTextInpuState: PokitInputStyle.State = .default + var isKeyboardVisible: Bool = false @Shared(.inMemory("SelectCategory")) var categoryId: Int? /// - 포킷 수정 API / 추가 API /// categoryName @@ -100,11 +103,13 @@ public struct PokitCategorySettingFeature { case 프로필_목록_조회_API_반영(images: [BaseCategoryImage]) case 포킷_오류_핸들링(BaseError) case 카테고리_인메모리_저장(BaseCategoryItem) + case 키보드_감지_반영(Bool) } public enum AsyncAction: Equatable { case 프로필_목록_조회_API case 클립보드_감지 + case 키보드_감지 } public enum ScopeAction { @@ -251,7 +256,8 @@ private extension PokitCategorySettingFeature { /// 단순 조회API들의 나열이라 merge사용 return .merge( .send(.async(.프로필_목록_조회_API)), - .send(.async(.클립보드_감지)) + .send(.async(.클립보드_감지)), + .send(.async(.키보드_감지)) ) case .포킷명지우기_버튼_눌렀을때: state.domain.categoryName = "" @@ -290,6 +296,10 @@ private extension PokitCategorySettingFeature { case let .카테고리_인메모리_저장(response): state.categoryId = response.id return .none + + case let .키보드_감지_반영(isVisible): + state.isKeyboardVisible = isVisible + return .none } } @@ -310,6 +320,13 @@ private extension PokitCategorySettingFeature { await send(.delegate(.linkCopyDetected(url)), animation: .pokitSpring) } } + + case .키보드_감지: + return .run { send in + for await detect in await keyboardClient.isVisible() { + await send(.inner(.키보드_감지_반영(detect)), animation: .pokitSpring) + } + } } } diff --git a/Projects/Feature/FeatureCategorySetting/Sources/PokitCategorySettingView.swift b/Projects/Feature/FeatureCategorySetting/Sources/PokitCategorySettingView.swift index bc51bed1..bcfbaf9c 100644 --- a/Projects/Feature/FeatureCategorySetting/Sources/PokitCategorySettingView.swift +++ b/Projects/Feature/FeatureCategorySetting/Sources/PokitCategorySettingView.swift @@ -37,13 +37,17 @@ public extension PokitCategorySettingView { openTypeSettingSection keywordSection Spacer() + } + .padding(.top, 16) + .overlay(alignment: .bottom) { saveButton + .padding(.bottom, store.isKeyboardVisible ? -26 : 0) + .padding(.bottom, 36) } .padding(.horizontal, 20) .padding(.top, 16) - .pokitMaxWidth() +// .pokitMaxWidth() .pokitNavigationBar { navigationBar } - .ignoresSafeArea(edges: isFocused ? [] : .bottom) .sheet(isPresented: $store.isProfileSheetPresented) { PokitProfileBottomSheet( selectedImage: store.selectedProfile, @@ -81,7 +85,7 @@ private extension PokitCategorySettingView { transaction: .init(animation: .spring) ) { phase in if let image = phase.image { - Circle().foregroundStyle(.pokit(.color(.grayScale(._100)))) + Circle().foregroundStyle(.pokit(.bg(.primary))) .overlay { image .resizable() @@ -91,15 +95,14 @@ private extension PokitCategorySettingView { } else { WithPerceptionTracking { ZStack { - Color.pokit(.bg(.disable)) - + Color.pokit(.bg(.primary)) if store.selectedProfile?.imageURL != nil { PokitSpinner() .foregroundStyle(.pokit(.icon(.brand))) .frame(width: 48, height: 48) } } - .clipShape(RoundedRectangle(cornerRadius: 12)) + .clipShape(.circle) } } } diff --git a/Projects/Feature/FeatureCategorySetting/Sources/Sheet/PokitKeywordBottomSheet.swift b/Projects/Feature/FeatureCategorySetting/Sources/Sheet/PokitKeywordBottomSheet.swift index 5d2d5a6d..9e738142 100644 --- a/Projects/Feature/FeatureCategorySetting/Sources/Sheet/PokitKeywordBottomSheet.swift +++ b/Projects/Feature/FeatureCategorySetting/Sources/Sheet/PokitKeywordBottomSheet.swift @@ -31,58 +31,63 @@ public struct PokitKeywordBottomSheet: View { } public var body: some View { - VStack(alignment: .leading, spacing: 0) { - Text("포킷의 키워드를 선택해 주세요") - .pokitFont(.title1) - .foregroundStyle(.pokit(.text(.primary))) - Text("키워드 기반으로 다른 사용자에게\n링크가 추천됩니다") - .pokitFont(.title3) - .foregroundStyle(.pokit(.text(.secondary))) - .padding(.top, 12) - PokitFlowLayout(rowSpacing: 12, colSpacing: 10) { - ForEach(BaseInterestType.allCases, id: \.self) { field in - let isSelected = selectedKeywordType != .default - if field != .default { - PokitTextChip( - field.title, - state: isSelected && field == selectedKeywordType - ? .filled(.primary) - : .default(.primary), - size: .medium - ) { - selectedKeywordType = field + GeometryReader { proxy in + let bottomSafeArea = proxy.safeAreaInsets.bottom + VStack(alignment: .leading, spacing: 0) { + Text("포킷의 키워드를 선택해 주세요") + .pokitFont(.title1) + .foregroundStyle(.pokit(.text(.primary))) + Text("키워드 기반으로 다른 사용자에게\n링크가 추천됩니다") + .pokitFont(.title3) + .foregroundStyle(.pokit(.text(.secondary))) + .padding(.top, 12) + .fixedSize(horizontal: false, vertical: true) + PokitFlowLayout(rowSpacing: 16, colSpacing: 12) { + ForEach(BaseInterestType.allCases, id: \.self) { field in + let isSelected = selectedKeywordType != .default + if field != .default { + PokitTextChip( + field.title, + state: isSelected && field == selectedKeywordType + ? .filled(.primary) + : .default(.primary), + size: .medium + ) { + selectedKeywordType = field + } } } + .animation(.pokitDissolve, value: selectedKeywordType) } - .animation(.pokitDissolve, value: selectedKeywordType) + .padding(.top, 36) + .padding(.bottom, 40) + + PokitBottomButton( + "키워드 선택", + state: keywordSheetBottomButtonState, + action: { action(selectedKeywordType) } + ) + .padding(.top, 16) } - .padding(.top, 36) - .padding(.bottom, 40) - - PokitBottomButton( - "키워드 선택", - state: keywordSheetBottomButtonState, - action: { action(selectedKeywordType) } - ) - .padding(.top, 16) - } - .padding(.horizontal, 20) - .padding(.top, 48) - .onChange(of: selectedKeywordType) { _ in - keywordSheetBottomButtonState = .filled(.primary) - } - .background(.pokit(.bg(.base))) - .pokitPresentationCornerRadius() - .pokitPresentationBackground() - .presentationDragIndicator(.visible) - .readHeight() - .onPreferenceChange(HeightPreferenceKey.self) { height in - if let height { - self.height = height + .padding(.horizontal, 20) + .padding(.top, 48) + .padding(.bottom, 36 - bottomSafeArea) + .onChange(of: selectedKeywordType) { _ in + keywordSheetBottomButtonState = .filled(.primary) + } + .background(.pokit(.bg(.base))) + .pokitPresentationCornerRadius() + .pokitPresentationBackground() + .presentationDragIndicator(.visible) + .readHeight() + .onPreferenceChange(HeightPreferenceKey.self) { height in + if let height { + self.height = height + } } + .presentationDetents([.height(height)]) + .ignoresSafeArea(edges: [.bottom, .top]) } - .presentationDetents([.height(height)]) - .ignoresSafeArea(edges: [.bottom, .top]) } } diff --git a/Projects/Feature/FeatureContentSetting/Sources/ContentSetting/ContentSettingFeature.swift b/Projects/Feature/FeatureContentSetting/Sources/ContentSetting/ContentSettingFeature.swift index b4541e77..c58e5db9 100644 --- a/Projects/Feature/FeatureContentSetting/Sources/ContentSetting/ContentSettingFeature.swift +++ b/Projects/Feature/FeatureContentSetting/Sources/ContentSetting/ContentSettingFeature.swift @@ -26,6 +26,8 @@ public struct ContentSettingFeature { private var contentClient @Dependency(CategoryClient.self) private var categoryClient + @Dependency(KeyboardClient.self) + private var keyboardClient /// - State @ObservableState public struct State: Equatable { @@ -70,6 +72,8 @@ public struct ContentSettingFeature { var link: String? var showLinkPreview = false var isShareExtension: Bool + var pokitAddSheetPresented: Bool = false + var isKeyboardVisible: Bool = false } /// - Action @@ -109,6 +113,7 @@ public struct ContentSettingFeature { case 선택한_포킷_인메모리_삭제 case 링크팝업_활성화(PokitLinkPopup.PopupType) case error(Error) + case 키보드_감지_반영(Bool) } public enum AsyncAction: Equatable { @@ -118,6 +123,7 @@ public struct ContentSettingFeature { case 컨텐츠_수정_API case 컨텐츠_추가_API case 클립보드_감지 + case 키보드_감지 } public enum ScopeAction: Equatable { case 없음 } @@ -187,7 +193,8 @@ private extension ContentSettingFeature { var mergeEffect: [Effect] = [ .send(.async(.카테고리_목록_조회_API)), .send(.inner(.URL_유효성_확인)), - .send(.async(.클립보드_감지)) + .send(.async(.클립보드_감지)), + .send(.async(.키보드_감지)) ] if let id = state.domain.contentId { mergeEffect.append(.send(.async(.컨텐츠_상세_조회_API(id: id)))) @@ -209,7 +216,8 @@ private extension ContentSettingFeature { state.linkPopup = .text(title: Constants.포킷_최대_갯수_문구) return .none } - + /// 바텀시트 내리고 `포킷추가하기` depth 추가 + state.pokitAddSheetPresented = false return .send(.delegate(.포킷추가하기)) case .뒤로가기_버튼_눌렀을때: state.categoryId = nil @@ -354,6 +362,9 @@ private extension ContentSettingFeature { .inner(.링크팝업_활성화(.error(title: errorResponse.message))), animation: .pokitSpring ) + case let .키보드_감지_반영(response): + state.isKeyboardVisible = response + return .none } } @@ -443,6 +454,13 @@ private extension ContentSettingFeature { await send(.inner(.linkPopup(url)), animation: .pokitSpring) } } + + case .키보드_감지: + return .run { send in + for await detect in await keyboardClient.isVisible() { + await send(.inner(.키보드_감지_반영(detect)), animation: .pokitSpring) + } + } } } diff --git a/Projects/Feature/FeatureContentSetting/Sources/ContentSetting/ContentSettingView.swift b/Projects/Feature/FeatureContentSetting/Sources/ContentSetting/ContentSettingView.swift index eb67c068..091320a3 100644 --- a/Projects/Feature/FeatureContentSetting/Sources/ContentSetting/ContentSettingView.swift +++ b/Projects/Feature/FeatureContentSetting/Sources/ContentSetting/ContentSettingView.swift @@ -67,6 +67,8 @@ public extension ContentSettingView { ) .padding(.horizontal, 20) .pokitMaxWidth() + .padding(.bottom, store.isKeyboardVisible ? -26 : 0) + .padding(.bottom, 36) } .pokitNavigationBar { navigationBar } .ignoresSafeArea(edges: focusedType == nil ? .bottom : []) @@ -141,6 +143,7 @@ private extension ContentSettingView { var pokitSelectButton: some View { PokitSelect( selectedItem: $store.selectedPokit, + isPresented: $store.pokitAddSheetPresented, label: "포킷", list: store.pokitList, action: { send(.포킷선택_항목_눌렀을때(pokit: $0), animation: .pokitDissolve) }, diff --git a/Projects/Feature/FeatureLogin/Sources/AgreeToTerms/AgreeToTermsView.swift b/Projects/Feature/FeatureLogin/Sources/AgreeToTerms/AgreeToTermsView.swift index 3361dae5..5513406e 100644 --- a/Projects/Feature/FeatureLogin/Sources/AgreeToTerms/AgreeToTermsView.swift +++ b/Projects/Feature/FeatureLogin/Sources/AgreeToTerms/AgreeToTermsView.swift @@ -42,6 +42,7 @@ public extension AgreeToTermsView { state: store.isPersonalAndUsageArgee && store.isServiceAgree ? .filled(.primary) : .disable, action: { send(.다음_버튼_눌렀을때) } ) + .padding(.bottom, 36) } .pokitMaxWidth() .padding(.horizontal, 20) diff --git a/Projects/Feature/FeatureLogin/Sources/RegisterNickname/RegisterNicknameFeature.swift b/Projects/Feature/FeatureLogin/Sources/RegisterNickname/RegisterNicknameFeature.swift index ee5bf4df..772cfd98 100644 --- a/Projects/Feature/FeatureLogin/Sources/RegisterNickname/RegisterNicknameFeature.swift +++ b/Projects/Feature/FeatureLogin/Sources/RegisterNickname/RegisterNicknameFeature.swift @@ -16,6 +16,7 @@ public struct RegisterNicknameFeature { @Dependency(\.dismiss) var dismiss @Dependency(\.mainQueue) var mainQueue @Dependency(UserClient.self) var userClient + @Dependency(KeyboardClient.self) var keyboardClient /// - State @ObservableState public struct State: Equatable { @@ -32,6 +33,7 @@ public struct RegisterNicknameFeature { } var buttonActive: Bool = false var textfieldState: PokitInputStyle.State = .default + var isKeyboardVisible: Bool = false } /// - Action public enum Action: FeatureAction, ViewAction { @@ -47,15 +49,18 @@ public struct RegisterNicknameFeature { /// - Button Tapped case 다음_버튼_눌렀을때 case dismiss + case onAppear } public enum InnerAction: Equatable { case 닉네임_텍스트_변경되었을때 case 닉네임_중복_체크_API_반영(Bool) + case 키보드_감지_반영(Bool) } public enum AsyncAction: Equatable { case 닉네임_중복_체크_API + case 키보드_감지 } public enum ScopeAction: Equatable { case 없음 } public enum DelegateAction: Equatable { @@ -110,6 +115,8 @@ private extension RegisterNicknameFeature { ) case .binding: return .none + case .onAppear: + return .send(.async(.키보드_감지)) } } /// - Inner Effect @@ -146,6 +153,10 @@ private extension RegisterNicknameFeature { state.buttonActive = true } return .none + + case let .키보드_감지_반영(response): + state.isKeyboardVisible = response + return .none } } /// - Async Effect @@ -156,6 +167,13 @@ private extension RegisterNicknameFeature { let result = try await userClient.닉네임_중복_체크(nickName) await send(.inner(.닉네임_중복_체크_API_반영(result.isDuplicate))) } + + case .키보드_감지: + return .run { send in + for await detect in await keyboardClient.isVisible() { + await send(.inner(.키보드_감지_반영(detect)), animation: .pokitSpring) + } + } } } /// - Scope Effect diff --git a/Projects/Feature/FeatureLogin/Sources/RegisterNickname/RegisterNicknameView.swift b/Projects/Feature/FeatureLogin/Sources/RegisterNickname/RegisterNicknameView.swift index 6ce0890f..1649e432 100644 --- a/Projects/Feature/FeatureLogin/Sources/RegisterNickname/RegisterNicknameView.swift +++ b/Projects/Feature/FeatureLogin/Sources/RegisterNickname/RegisterNicknameView.swift @@ -45,7 +45,9 @@ public extension RegisterNicknameView { : .disable, action: { send(.다음_버튼_눌렀을때) } ) - .setKeyboardHeight() + .padding(.bottom, store.isKeyboardVisible ? -26 : 0) + .padding(.bottom, 36) +// .setKeyboardHeight() } .pokitMaxWidth() .padding(.horizontal, 20) @@ -59,6 +61,7 @@ public extension RegisterNicknameView { } } .ignoresSafeArea(edges: .bottom) + .onAppear { send(.onAppear) } } } } diff --git a/Projects/Feature/FeatureLogin/Sources/SelectField/SelectFieldView.swift b/Projects/Feature/FeatureLogin/Sources/SelectField/SelectFieldView.swift index 4e1c2ac8..841af079 100644 --- a/Projects/Feature/FeatureLogin/Sources/SelectField/SelectFieldView.swift +++ b/Projects/Feature/FeatureLogin/Sources/SelectField/SelectFieldView.swift @@ -39,6 +39,7 @@ public extension SelectFieldView { action: { send(.nextButtonTapped) } ) .pokitMaxWidth() + .padding(.bottom, 36) } .padding(.horizontal, 20) .pokitNavigationBar { diff --git a/Projects/Feature/FeatureLogin/Sources/SignUpDone/SignUpDoneView.swift b/Projects/Feature/FeatureLogin/Sources/SignUpDone/SignUpDoneView.swift index 018e4360..2673a6d2 100644 --- a/Projects/Feature/FeatureLogin/Sources/SignUpDone/SignUpDoneView.swift +++ b/Projects/Feature/FeatureLogin/Sources/SignUpDone/SignUpDoneView.swift @@ -45,6 +45,7 @@ public extension SignUpDoneView { ) .pokitMaxWidth() .padding(.horizontal, 20) + .padding(.bottom, 36) .background(.pokit(.bg(.base))) } .ignoresSafeArea(edges: .bottom) diff --git a/Projects/Feature/FeaturePokit/Sources/PokitLinkEditFeature.swift b/Projects/Feature/FeaturePokit/Sources/PokitLinkEditFeature.swift index d96ebf42..bbbff198 100644 --- a/Projects/Feature/FeaturePokit/Sources/PokitLinkEditFeature.swift +++ b/Projects/Feature/FeaturePokit/Sources/PokitLinkEditFeature.swift @@ -32,6 +32,7 @@ public struct PokitLinkEditFeature { var list = IdentifiedArrayOf() /// 선택한 링크 목록 var selectedItems = IdentifiedArrayOf() + var isActive: Bool = false /// 포킷 이동 눌렀을 때 sheet var categorySelectSheetPresetend: Bool = false var linkDeleteSheetPresented: Bool = false @@ -159,6 +160,8 @@ private extension PokitLinkEditFeature { } else { state.selectedItems.append(item) } + + state.isActive = !state.selectedItems.isEmpty return .none case let .카테고리_선택했을때(pokit): @@ -226,8 +229,8 @@ private extension PokitLinkEditFeature { return .send(.delegate(.링크_편집_종료(items: [], type: type))) } /// 4. 링크이동을 했을 때 바텀 메세지 출력 - if case let .링크이동(categoryName) = type { - state.linkPopup = .text(title: "\(categoryName)\n카테고리로 이동되었습니다.") + if case .링크이동 = type { + state.linkPopup = .text(title: "링크 이동이 완료되었습니다.") return .none } @@ -296,7 +299,7 @@ private extension PokitLinkEditFeature { let contentIds = contentIds.map { $0.id } let request = ContentMoveRequest(contentIds: contentIds, categoryId: category.id) try await contentClient.미분류_링크_포킷_이동(request) - await send(.inner(.미분류_API_반영(.링크이동(categoryName: category.categoryName)))) + await send(.inner(.미분류_API_반영(.링크이동))) } catch: { error, send in await send(.inner(.error(error))) } @@ -315,7 +318,7 @@ private extension PokitLinkEditFeature { public extension PokitLinkEditFeature { enum LinkEditType: Equatable { case dismiss - case 링크이동(categoryName: String) + case 링크이동 case 링크삭제 } } diff --git a/Projects/Feature/FeaturePokit/Sources/PokitLinkEditView.swift b/Projects/Feature/FeaturePokit/Sources/PokitLinkEditView.swift index 1472455f..1c6b7e56 100644 --- a/Projects/Feature/FeaturePokit/Sources/PokitLinkEditView.swift +++ b/Projects/Feature/FeaturePokit/Sources/PokitLinkEditView.swift @@ -123,6 +123,7 @@ private extension PokitLinkEditView { var actionFloatButtonView: some View { PokitLinkEditFloatView( + isActive: $store.isActive, delegateSend: { store.send(.scope(.floatButtonAction($0))) } ) } diff --git a/Projects/Feature/FeaturePokit/Sources/PokitRootFeature.swift b/Projects/Feature/FeaturePokit/Sources/PokitRootFeature.swift index d2e119a4..7a754755 100644 --- a/Projects/Feature/FeaturePokit/Sources/PokitRootFeature.swift +++ b/Projects/Feature/FeaturePokit/Sources/PokitRootFeature.swift @@ -28,7 +28,6 @@ public struct PokitRootFeature { @ObservableState public struct State: Equatable { @Presents var linkEdit: PokitLinkEditFeature.State? - var favoriteContentCount: Int? var folderType: PokitRootFilterType = .folder(.포킷) var sortType: PokitRootFilterType = .sort(.최신순) @@ -97,8 +96,6 @@ public struct PokitRootFeature { case 카테고리_조회_API_반영(categoryList: BaseCategoryListInquiry) case 카테고리_페이징_조회_API_반영(contentList: BaseCategoryListInquiry) - case 즐겨찾기_컨텐츠_개수_조회_API_반영(count: Int) - case 페이지네이션_초기화 } @@ -112,8 +109,6 @@ public struct PokitRootFeature { case 미분류_전쳬_링크_조회_API case 미분류_카테고리_페이징_조회_API case 미분류_카테고리_페이징_재조회_API - - case 즐겨찾기_컨텐츠_개수_조회_API } @CasePathable @@ -242,15 +237,9 @@ private extension PokitRootFeature { switch state.folderType { case .folder(.포킷): guard let _ = state.domain.categoryList.data?.count else { - return .merge( - .send(.async(.즐겨찾기_컨텐츠_개수_조회_API)), - .send(.inner(.페이지네이션_초기화)) - ) + return .send(.inner(.페이지네이션_초기화)) } - return .merge( - .send(.async(.즐겨찾기_컨텐츠_개수_조회_API)), - .send(.async(.카테고리_페이징_재조회_API), animation: .pokitSpring) - ) + return .send(.async(.카테고리_페이징_재조회_API), animation: .pokitSpring) case .folder(.미분류): guard let _ = state.domain.unclassifiedContentList.data?.count else { @@ -368,11 +357,6 @@ private extension PokitRootFeature { default: return .none } - - case let .즐겨찾기_컨텐츠_개수_조회_API_반영(count): - /// count가 0보다 작다면 화면에 띄울 필요가 없기에 nil 할당 - state.favoriteContentCount = count > 0 ? count : nil - return .none } } @@ -480,12 +464,6 @@ private extension PokitRootFeature { guard let categoryItems else { return } await send(.inner(.카테고리_조회_API_반영(categoryList: categoryItems)), animation: .pokitSpring) } - - case .즐겨찾기_컨텐츠_개수_조회_API: - return .run { send in - let favoriteContentCount = try await remindClient.즐겨찾기_컨텐츠_개수_조회().count - await send(.inner(.즐겨찾기_컨텐츠_개수_조회_API_반영(count: favoriteContentCount))) - } } } @@ -565,8 +543,8 @@ private extension PokitRootFeature { } state.linkEdit = nil - if case let .링크이동(categoryName) = type { - let text = "\(categoryName)\n카테고리로 이동되었습니다." + if case .링크이동 = type { + let text = "링크 이동이 완료되었습니다." return .send(.delegate(.linkPopup(text: text))) } return .none diff --git a/Projects/Feature/FeaturePokit/Sources/PokitRootView.swift b/Projects/Feature/FeaturePokit/Sources/PokitRootView.swift index 600eb6a2..51e77bdd 100644 --- a/Projects/Feature/FeaturePokit/Sources/PokitRootView.swift +++ b/Projects/Feature/FeaturePokit/Sources/PokitRootView.swift @@ -158,10 +158,9 @@ private extension PokitRootView { LazyVStack(spacing: 0) { LazyVGrid(columns: column, spacing: 12) { ForEach(categories, id: \.id) { item in - if let linkCount = store.favoriteContentCount, - item.isFavorite { + if item.isFavorite { PokitFavoriteCard( - linkCount: linkCount, + linkCount: item.contentCount, action: { send(.카테고리_눌렀을때(item)) } ) } diff --git a/Projects/Feature/FeaturePokit/Sources/Sheet/PokitLinkEditFloatView.swift b/Projects/Feature/FeaturePokit/Sources/Sheet/PokitLinkEditFloatView.swift index 98fc7899..8c472da3 100644 --- a/Projects/Feature/FeaturePokit/Sources/Sheet/PokitLinkEditFloatView.swift +++ b/Projects/Feature/FeaturePokit/Sources/Sheet/PokitLinkEditFloatView.swift @@ -11,17 +11,24 @@ import SwiftUI public struct PokitLinkEditFloatView: View { /// 전체 선택/해제 toggle @State private var isChecked: Bool = false + @Binding private var isActive: Bool private let delegateSend: ((PokitLinkEditFloatView.Delegate) -> Void)? public init( + isActive: Binding, delegateSend: ((PokitLinkEditFloatView.Delegate) -> Void)? ) { + self._isActive = isActive self.delegateSend = delegateSend } public var body: some View { RoundedRectangle(cornerRadius: 16) - .foregroundStyle(.pokit(.bg(.brand))) + .foregroundStyle( + isActive + ? .pokit(.bg(.brand)) + : .pokit(.bg(.disable)) + ) .frame(height: 84) .overlay { HStack(spacing: 0) { @@ -41,6 +48,7 @@ public struct PokitLinkEditFloatView: View { color: Color.black, colorPercent: 10 ) + .animation(.pokitSpring, value: isActive) } } private extension PokitLinkEditFloatView { @@ -61,6 +69,7 @@ private extension PokitLinkEditFloatView { } .buttonStyle(.plain) .foregroundStyle(.white) + .disabled(!isActive) } } public extension PokitLinkEditFloatView { @@ -107,5 +116,8 @@ public extension PokitLinkEditFloatView { } } #Preview { - PokitLinkEditFloatView(delegateSend: {_ in }).padding(20) + PokitLinkEditFloatView( + isActive: .constant(true), + delegateSend: {_ in } + ).padding(20) } diff --git a/Projects/Feature/FeatureSetting/Sources/Setting/NickNameSetting/NickNameSettingFeature.swift b/Projects/Feature/FeatureSetting/Sources/Setting/NickNameSetting/NickNameSettingFeature.swift index 56d22c8d..e67d65a3 100644 --- a/Projects/Feature/FeatureSetting/Sources/Setting/NickNameSetting/NickNameSettingFeature.swift +++ b/Projects/Feature/FeatureSetting/Sources/Setting/NickNameSetting/NickNameSettingFeature.swift @@ -22,6 +22,8 @@ public struct NickNameSettingFeature { var userClient @Dependency(CategoryClient.self) var categoryClient + @Dependency(KeyboardClient.self) + var keyboardClient /// - State @ObservableState public struct State: Equatable { @@ -46,6 +48,7 @@ public struct NickNameSettingFeature { var textfieldState: PokitInputStyle.State = .default var buttonState: PokitButtonStyle.State = .disable var isProfileSheetPresented: Bool = false + var isKeyboardVisible: Bool = false public init(user: BaseUser?) { if let user, @@ -86,12 +89,14 @@ public struct NickNameSettingFeature { case 닉네임_중복_확인_API_반영(Bool) case 닉네임_조회_API_반영(BaseUser) case 프로필_목록_조회_API_반영(images: [BaseProfile]) + case 키보드_감지_반영(Bool) } public enum AsyncAction: Equatable { case 닉네임_중복_확인_API case 닉네임_조회_API case 프로필_목록_조회_API + case 키보드_감지 } public enum ScopeAction { @@ -172,7 +177,8 @@ private extension NickNameSettingFeature { case .뷰가_나타났을때: return .merge( .send(.async(.프로필_목록_조회_API)), - .send(.async(.닉네임_조회_API)) + .send(.async(.닉네임_조회_API)), + .send(.async(.키보드_감지)) ) case .닉네임지우기_버튼_눌렀을때: @@ -251,6 +257,10 @@ private extension NickNameSettingFeature { case let .프로필_목록_조회_API_반영(images): state.domain.imageList = images return .none + + case let .키보드_감지_반영(response): + state.isKeyboardVisible = response + return .none } } @@ -275,6 +285,13 @@ private extension NickNameSettingFeature { let images = response.map { $0.toDomain() } await send(.inner(.프로필_목록_조회_API_반영(images: images))) } + + case .키보드_감지: + return .run { send in + for await detect in await keyboardClient.isVisible() { + await send(.inner(.키보드_감지_반영(detect)), animation: .pokitSpring) + } + } } } diff --git a/Projects/Feature/FeatureSetting/Sources/Setting/NickNameSetting/NickNameSettingView.swift b/Projects/Feature/FeatureSetting/Sources/Setting/NickNameSetting/NickNameSettingView.swift index 38fb52e9..163594d6 100644 --- a/Projects/Feature/FeatureSetting/Sources/Setting/NickNameSetting/NickNameSettingView.swift +++ b/Projects/Feature/FeatureSetting/Sources/Setting/NickNameSetting/NickNameSettingView.swift @@ -44,7 +44,9 @@ public extension NickNameSettingView { state: store.buttonState, action: { send(.저장_버튼_눌렀을때) } ) - .setKeyboardHeight() + .padding(.bottom, store.isKeyboardVisible ? -26 : 0) + .padding(.bottom, 36) +// .setKeyboardHeight() } .padding(.horizontal, 20) .padding(.top, 16) @@ -56,7 +58,7 @@ public extension NickNameSettingView { delegateSend: { store.send(.scope(.profile($0))) } ) } - .ignoresSafeArea(edges: .bottom) + .ignoresSafeArea(.container, edges: .bottom) .task { await send(.뷰가_나타났을때).finish() } } } diff --git a/Projects/Util/Sources/BaseInterestType.swift b/Projects/Util/Sources/BaseInterestType.swift index 5683d7a0..6c942417 100644 --- a/Projects/Util/Sources/BaseInterestType.swift +++ b/Projects/Util/Sources/BaseInterestType.swift @@ -8,26 +8,30 @@ public enum BaseInterestType: String, CaseIterable { case `default` case 스포츠_레저 - case 문구_오피스 - case 패션 + case 기획_마케팅 + case 쇼핑 case 여행 case 경제_시사 case 영화_드라마 - case 맛집 + case 장소 case 인테리어 case IT case 디자인 case 자기계발 case 유머 case 음악 + case 독서 case 취업정보 + case 요리_레시피 + case 반려동물 public var title: String { switch self { - case .경제_시사: return "경제/시사" case .스포츠_레저: return "스포츠/레저" + case .기획_마케팅: return "기획/마케팅" + case .경제_시사: return "경제/시사" case .영화_드라마: return "영화/드라마" - case .문구_오피스: return "문구/오피스" + case .요리_레시피: return "요리/레시피" default: return self.rawValue }