Skip to content

Commit

Permalink
편의점 바텀시트 구현 (#49)
Browse files Browse the repository at this point in the history
* ✨ Implement convenience store selection bottom sheet view

* ✨ Implement convenience store selection modal

- Added a bottom sheet view to display the convenience store selection modal.

* 🎨 Refactor hardcoded constants to Metrics enum

* 🎨 Refactor `isPresented` state to subview

- Moved isPresented state variable to HomeProductDetailSelectionView for better state management.
- Renamed isPresented variable to convenienceStoreModalPresented for improved clarity and readability.

* ♻️ Refactor modal presentation using `@Environment(\.dismiss)`

- Replaced `@Binding` with `@Environment(\.dismiss)` for modal presentation management.
  • Loading branch information
WhiteHyun authored Feb 24, 2024
1 parent 56849bc commit d615750
Show file tree
Hide file tree
Showing 7 changed files with 256 additions and 28 deletions.
2 changes: 1 addition & 1 deletion Entity/Sources/Entity/ConvenienceStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import Foundation
import SwiftUI

public enum ConvenienceStore: String, Codable {
public enum ConvenienceStore: String, Codable, CaseIterable {
case cu = "CU"
case gs25 = "GS25"
case _7Eleven = "7-ELEVEn"
Expand Down
12 changes: 12 additions & 0 deletions PyeonHaeng-iOS.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
BA28F1A42B61572A0052855E /* Pretendard-ExtraBold.otf in Resources */ = {isa = PBXBuildFile; fileRef = BA28F19A2B61572A0052855E /* Pretendard-ExtraBold.otf */; };
BA28F1A52B61572A0052855E /* Pretendard-Light.otf in Resources */ = {isa = PBXBuildFile; fileRef = BA28F19B2B61572A0052855E /* Pretendard-Light.otf */; };
BA28F1A62B61572A0052855E /* Pretendard-Black.otf in Resources */ = {isa = PBXBuildFile; fileRef = BA28F19C2B61572A0052855E /* Pretendard-Black.otf */; };
BA402F7E2B85E31800E86AAD /* ConvenienceSelectBottomSheetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA402F7D2B85E31800E86AAD /* ConvenienceSelectBottomSheetView.swift */; };
BA4EA3602B6A37E10003DCE7 /* Entity in Frameworks */ = {isa = PBXBuildFile; productRef = BA4EA35F2B6A37E10003DCE7 /* Entity */; };
BAA4D9AD2B5A1795005999F8 /* PyeonHaengApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = BAA4D9AC2B5A1795005999F8 /* PyeonHaengApp.swift */; };
BAA4D9AF2B5A1795005999F8 /* SplashView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BAA4D9AE2B5A1795005999F8 /* SplashView.swift */; };
Expand Down Expand Up @@ -87,6 +88,7 @@
BA28F19B2B61572A0052855E /* Pretendard-Light.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Pretendard-Light.otf"; sourceTree = "<group>"; };
BA28F19C2B61572A0052855E /* Pretendard-Black.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Pretendard-Black.otf"; sourceTree = "<group>"; };
BA28F1A72B6157E90052855E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
BA402F7D2B85E31800E86AAD /* ConvenienceSelectBottomSheetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConvenienceSelectBottomSheetView.swift; sourceTree = "<group>"; };
BA4EA35A2B6A00F70003DCE7 /* Entity */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = Entity; sourceTree = "<group>"; };
BAA4D9A92B5A1795005999F8 /* PyeonHaeng-iOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "PyeonHaeng-iOS.app"; sourceTree = BUILT_PRODUCTS_DIR; };
BAA4D9AC2B5A1795005999F8 /* PyeonHaengApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PyeonHaengApp.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -218,6 +220,7 @@
BA28F1862B61558C0052855E /* HomeScene */ = {
isa = PBXGroup;
children = (
BA402F7C2B85E2DE00E86AAD /* BottomSheet */,
BA28F1872B6155910052855E /* HomeView.swift */,
BAB5CF262B6B7CF3008B24BF /* HomeViewModel.swift */,
BAE159D72B65FA6F002DCF94 /* HomeProductDetailSelectionView.swift */,
Expand Down Expand Up @@ -271,6 +274,14 @@
path = Fonts;
sourceTree = "<group>";
};
BA402F7C2B85E2DE00E86AAD /* BottomSheet */ = {
isa = PBXGroup;
children = (
BA402F7D2B85E31800E86AAD /* ConvenienceSelectBottomSheetView.swift */,
);
path = BottomSheet;
sourceTree = "<group>";
};
BAA4D9A02B5A1795005999F8 = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -505,6 +516,7 @@
files = (
BAE159DA2B65FC35002DCF94 /* HomeProductListView.swift in Sources */,
E5F2EC402B637D4A00EE0838 /* ProductInfoHeader.swift in Sources */,
BA402F7E2B85E31800E86AAD /* ConvenienceSelectBottomSheetView.swift in Sources */,
BA28F1852B6155810052855E /* OnboardingView.swift in Sources */,
BAB5CF272B6B7CF3008B24BF /* HomeViewModel.swift in Sources */,
BA28F1882B6155910052855E /* HomeView.swift in Sources */,
Expand Down
120 changes: 111 additions & 9 deletions PyeonHaeng-iOS/Resources/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,86 @@
}
}
},
"7-Eleven" : {
"localizations" : {
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "7-Eleven"
}
},
"ko" : {
"stringUnit" : {
"state" : "translated",
"value" : "세븐일레븐"
}
}
}
},
"CU" : {
"localizations" : {
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "CU"
}
},
"ko" : {
"stringUnit" : {
"state" : "translated",
"value" : "씨유"
}
}
}
},
"Emart 24" : {
"localizations" : {
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "Emart 24"
}
},
"ko" : {
"stringUnit" : {
"state" : "translated",
"value" : "이마트 24"
}
}
}
},
"GS25" : {
"localizations" : {
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "GS25"
}
},
"ko" : {
"stringUnit" : {
"state" : "translated",
"value" : "지에스 25"
}
}
}
},
"Ministop" : {
"localizations" : {
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "Ministop"
}
},
"ko" : {
"stringUnit" : {
"state" : "translated",
"value" : "미니스톱"
}
}
}
},
"개당" : {
"extractionState" : "manual",
"localizations" : {
Expand Down Expand Up @@ -306,47 +386,47 @@
}
}
},
"이전 행사 정보" : {
"오름차순 정렬" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Previous Promotions"
"value" : "Ascending Sorting"
}
},
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "過去のプロモーション"
"value" : "昇順並び替え"
}
},
"ko" : {
"stringUnit" : {
"state" : "translated",
"value" : "이전 행사 정보"
"value" : "오름차순 정렬"
}
}
}
},
"오름차순 정렬" : {
"extractionState" : "manual",
"이전 행사 정보" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Ascending Sorting"
"value" : "Previous Promotions"
}
},
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "昇順並び替え"
"value" : "過去のプロモーション"
}
},
"ko" : {
"stringUnit" : {
"state" : "translated",
"value" : "오름차순 정렬"
"value" : "이전 행사 정보"
}
}
}
Expand Down Expand Up @@ -420,6 +500,28 @@
}
}
},
"편의점 브랜드 선택" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Choose Store Brand"
}
},
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "コンビニのブランドを選ぶ"
}
},
"ko" : {
"stringUnit" : {
"state" : "translated",
"value" : "편의점 브랜드 선택"
}
}
}
},
"행사 진행 편의점" : {
"extractionState" : "manual",
"localizations" : {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
//
// ConvenienceSelectBottomSheetView.swift
// PyeonHaeng-iOS
//
// Created by 홍승현 on 2/21/24.
//

import Entity
import SwiftUI

// MARK: - ConvenienceSelectBottomSheetView

struct ConvenienceSelectBottomSheetView<ViewModel>: View where ViewModel: HomeViewModelRepresentable {
@EnvironmentObject private var viewModel: ViewModel
@Environment(\.dismiss) private var dismiss

var body: some View {
VStack(spacing: Metrics.itemSpacing) {
Text("편의점 브랜드 선택")
.font(.h3)
.frame(maxWidth: .infinity, alignment: .leading)
.padding(.horizontal, Metrics.horizontalPadding)

ForEach(ConvenienceStore.allCases, id: \.self) { store in
Button {
viewModel.trigger(.changeConvenienceStore(store))
dismiss()
} label: {
ConvenienceSelectItem(convenience: store)
.frame(maxWidth: .infinity, minHeight: Metrics.itemHeight, alignment: .leading)
}
}
.padding(.horizontal, Metrics.itemHorizontalPadding)
}
.padding(.top, Metrics.topPadding)
.padding(.bottom, Metrics.bottomPadding)
}
}

// MARK: - ConvenienceSelectItem

private struct ConvenienceSelectItem: View {
private let convenience: ConvenienceStore

init(convenience: ConvenienceStore) {
self.convenience = convenience
}

var body: some View {
HStack(spacing: Metrics.itemHorizontalSpacing) {
convenienceImageView()
convenienceText()
}
}

private func convenienceImageView() -> Image {
switch convenience {
case .cu:
.cu
case .gs25:
.gs25
case ._7Eleven:
._7Eleven
case .emart24:
.emart24
case .ministop:
.ministop
}
}

private func convenienceText() -> Text {
switch convenience {
case .cu:
Text("CU")
case .gs25:
Text("GS25")
case ._7Eleven:
Text("7-Eleven")
case .emart24:
Text("Emart 24")
case .ministop:
Text("Ministop")
}
}
}

// MARK: - Metrics

private enum Metrics {
static let topPadding: CGFloat = 12
static let bottomPadding: CGFloat = 4
static let horizontalPadding: CGFloat = 20

// MARK: Item

static let itemHorizontalPadding: CGFloat = 24
static let itemHorizontalSpacing: CGFloat = 12
static let itemSpacing: CGFloat = 4
static let itemHeight: CGFloat = 44
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,15 @@ import SwiftUI

// MARK: - HomeProductDetailSelectionView

struct HomeProductDetailSelectionView: View {
struct HomeProductDetailSelectionView<ViewModel>: View where ViewModel: HomeViewModelRepresentable {
@EnvironmentObject private var viewModel: ViewModel
@State private var convenienceStoreModalPresented: Bool = false

var body: some View {
HStack {
Button {} label: {
Button {
convenienceStoreModalPresented = true
} label: {
Group {
Image.gs25
.resizable()
Expand All @@ -25,6 +30,12 @@ struct HomeProductDetailSelectionView: View {
}
}
.accessibilityHint("더블 탭하여 편의점을 선택하세요")
.sheet(isPresented: $convenienceStoreModalPresented) {
ConvenienceSelectBottomSheetView<ViewModel>()
.presentationDetents([.height(Metrics.bottomSheetHeight)])
.presentationCornerRadius(20)
.presentationBackground(.regularMaterial)
}

Spacer()

Expand Down Expand Up @@ -57,22 +68,21 @@ struct HomeProductDetailSelectionView: View {
}
}

// MARK: HomeProductDetailSelectionView.Metrics
// MARK: - Metrics

private extension HomeProductDetailSelectionView {
enum Metrics {
static let buttonSpacing: CGFloat = 2
static let textHeight: CGFloat = 24
static let horizontal: CGFloat = 20
static let iconWidth: CGFloat = 8
static let iconHeight: CGFloat = 4
private enum Metrics {
static let buttonSpacing: CGFloat = 2
static let textHeight: CGFloat = 24
static let horizontal: CGFloat = 20
static let iconWidth: CGFloat = 8
static let iconHeight: CGFloat = 4

static let promotionButtonPaddingTop: CGFloat = 4
static let promotionButtonPaddingLeading: CGFloat = 16
static let promotionButtonPaddingBottom: CGFloat = 4
static let promotionButtonPaddingTrailing: CGFloat = 10
static let promotionButtonCornerRadius: CGFloat = 16
static let promotionButtonPaddingTop: CGFloat = 4
static let promotionButtonPaddingLeading: CGFloat = 16
static let promotionButtonPaddingBottom: CGFloat = 4
static let promotionButtonPaddingTrailing: CGFloat = 10
static let promotionButtonCornerRadius: CGFloat = 16

static let height: CGFloat = 56
}
static let height: CGFloat = 56
static let bottomSheetHeight: CGFloat = 334
}
Loading

0 comments on commit d615750

Please sign in to comment.