diff --git a/FoodDiary/App/Project.swift b/FoodDiary/App/Project.swift
index 8a9d2c1b..4423953e 100644
--- a/FoodDiary/App/Project.swift
+++ b/FoodDiary/App/Project.swift
@@ -55,7 +55,8 @@ let project = Project(
],
settings: .settings(
base: [
- "MARKETING_VERSION": "1.0.0",
+ "MARKETING_VERSION": "1.1.0",
+ "CURRENT_PROJECT_VERSION": "26050725",
"BASE_URL": "$(BASE_URL)",
"SENTRY_DSN": "$(SENTRY_DSN)",
"TARGETED_DEVICE_FAMILY": "1"
diff --git a/FoodDiary/App/Resources/LaunchScreen.storyboard b/FoodDiary/App/Resources/LaunchScreen.storyboard
index 9656dcbc..e427cd28 100644
--- a/FoodDiary/App/Resources/LaunchScreen.storyboard
+++ b/FoodDiary/App/Resources/LaunchScreen.storyboard
@@ -27,7 +27,7 @@
-
+
diff --git a/FoodDiary/DesignSystem/Resources/Assets.xcassets/Colors/gray040.colorset/Contents.json b/FoodDiary/DesignSystem/Resources/Assets.xcassets/Colors/gray040.colorset/Contents.json
new file mode 100644
index 00000000..6056dafb
--- /dev/null
+++ b/FoodDiary/DesignSystem/Resources/Assets.xcassets/Colors/gray040.colorset/Contents.json
@@ -0,0 +1,20 @@
+{
+ "colors" : [
+ {
+ "color" : {
+ "color-space" : "srgb",
+ "components" : {
+ "alpha" : "1.000",
+ "blue" : "0xF9",
+ "green" : "0xF6",
+ "red" : "0xF3"
+ }
+ },
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/FoodDiary/DesignSystem/Resources/Assets.xcassets/Colors/gray150.colorset/Contents.json b/FoodDiary/DesignSystem/Resources/Assets.xcassets/Colors/gray150.colorset/Contents.json
new file mode 100644
index 00000000..e7d0cebf
--- /dev/null
+++ b/FoodDiary/DesignSystem/Resources/Assets.xcassets/Colors/gray150.colorset/Contents.json
@@ -0,0 +1,20 @@
+{
+ "colors" : [
+ {
+ "color" : {
+ "color-space" : "srgb",
+ "components" : {
+ "alpha" : "1.000",
+ "blue" : "0xE0",
+ "green" : "0xE0",
+ "red" : "0xE0"
+ }
+ },
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/FoodDiary/DesignSystem/Resources/Assets.xcassets/Colors/gray850.colorset/Contents.json b/FoodDiary/DesignSystem/Resources/Assets.xcassets/Colors/gray850.colorset/Contents.json
new file mode 100644
index 00000000..44d234cd
--- /dev/null
+++ b/FoodDiary/DesignSystem/Resources/Assets.xcassets/Colors/gray850.colorset/Contents.json
@@ -0,0 +1,20 @@
+{
+ "colors" : [
+ {
+ "color" : {
+ "color-space" : "srgb",
+ "components" : {
+ "alpha" : "1.000",
+ "blue" : "0x2C",
+ "green" : "0x2C",
+ "red" : "0x2C"
+ }
+ },
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/FoodDiary/DesignSystem/Resources/Assets.xcassets/onboard-1.imageset/onboard-1.png b/FoodDiary/DesignSystem/Resources/Assets.xcassets/onboard-1.imageset/onboard-1.png
index 0d981431..d9a0a281 100644
Binary files a/FoodDiary/DesignSystem/Resources/Assets.xcassets/onboard-1.imageset/onboard-1.png and b/FoodDiary/DesignSystem/Resources/Assets.xcassets/onboard-1.imageset/onboard-1.png differ
diff --git a/FoodDiary/DesignSystem/Resources/Assets.xcassets/onboard-1.imageset/onboard-1@2x.png b/FoodDiary/DesignSystem/Resources/Assets.xcassets/onboard-1.imageset/onboard-1@2x.png
index 2bdba671..d9a0a281 100644
Binary files a/FoodDiary/DesignSystem/Resources/Assets.xcassets/onboard-1.imageset/onboard-1@2x.png and b/FoodDiary/DesignSystem/Resources/Assets.xcassets/onboard-1.imageset/onboard-1@2x.png differ
diff --git a/FoodDiary/DesignSystem/Resources/Assets.xcassets/onboard-1.imageset/onboard-1@3x.png b/FoodDiary/DesignSystem/Resources/Assets.xcassets/onboard-1.imageset/onboard-1@3x.png
index 7b6e27d3..d9a0a281 100644
Binary files a/FoodDiary/DesignSystem/Resources/Assets.xcassets/onboard-1.imageset/onboard-1@3x.png and b/FoodDiary/DesignSystem/Resources/Assets.xcassets/onboard-1.imageset/onboard-1@3x.png differ
diff --git a/FoodDiary/DesignSystem/Sources/Components/SearchTextField.swift b/FoodDiary/DesignSystem/Sources/Components/SearchTextField.swift
index 161f5411..9f4f95e1 100644
--- a/FoodDiary/DesignSystem/Sources/Components/SearchTextField.swift
+++ b/FoodDiary/DesignSystem/Sources/Components/SearchTextField.swift
@@ -82,6 +82,34 @@ public final class SearchTextField: UITextField {
}
}
+ public func applyColors(
+ backgroundColor: UIColor,
+ textColor: UIColor,
+ placeholderColor: UIColor,
+ iconColor: UIColor,
+ borderColor: UIColor? = nil,
+ borderWidth: CGFloat = 0
+ ) {
+ self.backgroundColor = backgroundColor
+ self.textColor = textColor
+ layer.borderColor = borderColor?.cgColor
+ layer.borderWidth = borderWidth
+
+ if let placeholder = attributedPlaceholder?.string {
+ attributedPlaceholder = NSAttributedString(
+ string: placeholder,
+ attributes: [
+ .font: DesignSystemFontFamily.Pretendard.regular.font(size: 14),
+ .foregroundColor: placeholderColor
+ ]
+ )
+ }
+
+ if let iconButton = rightView as? UIButton {
+ iconButton.tintColor = iconColor
+ }
+ }
+
@objc private func searchIconTapped() {
onSearchIconTapped?()
}
diff --git a/FoodDiary/Presentation/Sources/AddressSearch/AddressSearchViewController.swift b/FoodDiary/Presentation/Sources/AddressSearch/AddressSearchViewController.swift
index 69ef0060..9a2f3262 100644
--- a/FoodDiary/Presentation/Sources/AddressSearch/AddressSearchViewController.swift
+++ b/FoodDiary/Presentation/Sources/AddressSearch/AddressSearchViewController.swift
@@ -54,7 +54,7 @@ public final class AddressSearchViewController: UIViewController, UITextFieldDel
private lazy var closeButton: UIButton = {
let button = UIButton(type: .system)
button.setImage(UIImage(systemName: "xmark"), for: .normal)
- button.tintColor = .white
+ button.tintColor = .gray850
button.addTarget(self, action: #selector(closeButtonTapped), for: .touchUpInside)
return button
}()
@@ -68,17 +68,14 @@ public final class AddressSearchViewController: UIViewController, UITextFieldDel
private let guideLabel: UILabel = {
let label = UILabel()
- label.setText("이 식당을 찾고 계신가요?", style: .hd16)
+ label.setText("이 식당을 찾고 계신가요?", style: .hd16, color: .gray850)
return label
}()
private let resultsContainerView: UIView = {
let view = UIView()
- view.backgroundColor = .clear
- view.layer.borderColor = UIColor.sd800.cgColor
- view.layer.borderWidth = 1
-
- view.layer.cornerRadius = 12
+ view.backgroundColor = .gray040
+ view.layer.cornerRadius = 10
view.clipsToBounds = true
view.isHidden = true
return view
@@ -86,7 +83,7 @@ public final class AddressSearchViewController: UIViewController, UITextFieldDel
private let emptyResultLabel: UILabel = {
let label = UILabel()
- label.setText("검색 결과가 없습니다.", style: .p14, color: .gray400)
+ label.setText("검색 결과가 없습니다.", style: .p14, color: .gray500)
label.textAlignment = .center
label.isHidden = true
return label
@@ -95,8 +92,8 @@ public final class AddressSearchViewController: UIViewController, UITextFieldDel
private lazy var resultsTableView: UITableView = {
let tv = UITableView()
tv.backgroundColor = .clear
- tv.separatorColor = .sd600
- tv.separatorInset = UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 16)
+ tv.separatorColor = .gray150
+ tv.separatorInset = UIEdgeInsets(top: 0, left: 20, bottom: 0, right: 20)
tv.delegate = tableViewHandler
tv.dataSource = tableViewHandler
tv.register(
@@ -157,7 +154,13 @@ public final class AddressSearchViewController: UIViewController, UITextFieldDel
// MARK: - Setup
private func setupUI() {
- view.backgroundColor = .sdBase
+ view.backgroundColor = .white
+ searchTextField.applyColors(
+ backgroundColor: .gray040,
+ textColor: .gray850,
+ placeholderColor: .gray600,
+ iconColor: .gray850
+ )
view.addSubview(closeButton)
view.addSubview(searchTextField)
@@ -236,10 +239,10 @@ public final class AddressSearchViewController: UIViewController, UITextFieldDel
switch state.mode {
case .suggestions:
- guideLabel.setText("이 식당을 찾고 계신가요?", style: .hd16)
+ guideLabel.setText("이 식당을 찾고 계신가요?", style: .hd16, color: .gray850)
displayResults = state.suggestions
case .searchResults:
- guideLabel.setText("검색 결과", style: .hd16)
+ guideLabel.setText("검색 결과", style: .hd16, color: .gray850)
displayResults = state.searchResults
}
@@ -250,13 +253,23 @@ public final class AddressSearchViewController: UIViewController, UITextFieldDel
if displayResults.isEmpty {
switch state.mode {
case .suggestions:
- emptyResultLabel.setText("추천 목록이 없습니다.", style: .p14, color: .gray400)
+ emptyResultLabel.setText("추천 목록이 없습니다.", style: .p14, color: .gray500)
case .searchResults:
- emptyResultLabel.setText("검색 결과가 없습니다.", style: .p14, color: .gray400)
+ emptyResultLabel.setText("검색 결과가 없습니다.", style: .p14, color: .gray500)
}
}
emptyResultLabel.isHidden = !displayResults.isEmpty
+ let isSearching = !(state.searchKeyword.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty)
+ searchTextField.applyColors(
+ backgroundColor: .gray040,
+ textColor: .gray850,
+ placeholderColor: .gray600,
+ iconColor: .gray850,
+ borderColor: isSearching ? .primary : nil,
+ borderWidth: isSearching ? 1 : 0
+ )
+
Task { @MainActor [weak self] in
guard let self else { return }
self.containerHeightConstraint?.update(offset: self.view.bounds.height)
diff --git a/FoodDiary/Presentation/Sources/AddressSearch/Components/AddressSearchResultCell.swift b/FoodDiary/Presentation/Sources/AddressSearch/Components/AddressSearchResultCell.swift
index 6a456b8a..4fbd7c77 100644
--- a/FoodDiary/Presentation/Sources/AddressSearch/Components/AddressSearchResultCell.swift
+++ b/FoodDiary/Presentation/Sources/AddressSearch/Components/AddressSearchResultCell.swift
@@ -43,7 +43,7 @@ final class AddressSearchResultCell: UITableViewCell {
let button = UIButton(type: .system)
var config = UIButton.Configuration.plain()
config.attributedTitle = {
- var attributed = AttributedString(Typography.p14.styled("선택", color: .white))
+ var attributed = AttributedString(Typography.p12.styled("선택", color: .gray850))
attributed.underlineStyle = .single
return attributed
}()
@@ -104,8 +104,8 @@ final class AddressSearchResultCell: UITableViewCell {
// MARK: - Configure
func configure(with result: AddressSearchResult) {
- placeNameLabel.setText(result.placeName, style: .hd16)
- roadAddressLabel.setText(result.roadAddress, style: .p14, color: .gray400)
+ placeNameLabel.setText(result.placeName, style: .hd16, color: .gray850)
+ roadAddressLabel.setText(result.roadAddress, style: .p14, color: .gray800)
}
}
diff --git a/FoodDiary/Presentation/Sources/Core/UIColor+DesignSystem.swift b/FoodDiary/Presentation/Sources/Core/UIColor+DesignSystem.swift
index 0deb0932..26b2e2d0 100644
--- a/FoodDiary/Presentation/Sources/Core/UIColor+DesignSystem.swift
+++ b/FoodDiary/Presentation/Sources/Core/UIColor+DesignSystem.swift
@@ -59,6 +59,9 @@ public extension UIColor {
static let gray300 = DesignSystemAsset.gray300.color
static let gray200 = DesignSystemAsset.gray200.color
static let gray100 = DesignSystemAsset.gray100.color
+ static let gray040 = DesignSystemAsset.gray040.color
+ static let gray150 = DesignSystemAsset.gray150.color
static let gray050 = DesignSystemAsset.gray050.color
static let gray020 = DesignSystemAsset.gray020.color
+ static let gray850 = DesignSystemAsset.gray850.color
}
diff --git a/FoodDiary/Presentation/Sources/Detail/DetailViewController.swift b/FoodDiary/Presentation/Sources/Detail/DetailViewController.swift
index de1e5955..aac598ff 100644
--- a/FoodDiary/Presentation/Sources/Detail/DetailViewController.swift
+++ b/FoodDiary/Presentation/Sources/Detail/DetailViewController.swift
@@ -478,7 +478,7 @@ public final class DetailViewController: UIViewController {
}
private func formatRecordForShare(_ name: String, _ url: String) -> String {
- return "\(name) 맛을 기억하시나요?\n\n\(url)"
+ return "\(name) 맛을 기억하시나요?\n뭐먹었지에서 확인해보세요.\n\(url)\n\n 나도 시작하기\nhttps://mumuk.ai.kr/"
}
private func presentShareSheet(items: [Any]) {
diff --git a/FoodDiary/Presentation/Sources/ImagePicker/ImagePickerSectionHeaderView.swift b/FoodDiary/Presentation/Sources/ImagePicker/ImagePickerSectionHeaderView.swift
index 96bd8771..91466a90 100644
--- a/FoodDiary/Presentation/Sources/ImagePicker/ImagePickerSectionHeaderView.swift
+++ b/FoodDiary/Presentation/Sources/ImagePicker/ImagePickerSectionHeaderView.swift
@@ -37,10 +37,10 @@ final class ImagePickerSectionHeaderView: UICollectionReusableView {
}
func configure(title: String, guideText: String? = nil) {
- titleLabel.setText(title, style: .hd16, color: .white)
+ titleLabel.setText(title, style: .hd16, color: .gray900)
if let guideText {
- guideLabel.setText(guideText, style: .p14, color: .gray400)
+ guideLabel.setText(guideText, style: .p14, color: .gray500)
guideLabel.isHidden = false
} else {
guideLabel.isHidden = true
diff --git a/FoodDiary/Presentation/Sources/ImagePicker/ImagePickerViewController.swift b/FoodDiary/Presentation/Sources/ImagePicker/ImagePickerViewController.swift
index b103f8f3..46e833ce 100644
--- a/FoodDiary/Presentation/Sources/ImagePicker/ImagePickerViewController.swift
+++ b/FoodDiary/Presentation/Sources/ImagePicker/ImagePickerViewController.swift
@@ -134,7 +134,7 @@ public final class ImagePickerViewController:
}
let label = UILabel()
- label.setText("오늘은 촬영된 사진이 없어요", style: .p12, color: .gray050)
+ label.setText("오늘은 촬영된 사진이 없어요", style: .p12, color: .gray500)
label.textAlignment = .center
let stackView = UIStackView(arrangedSubviews: [imageView, label])
@@ -178,6 +178,7 @@ public final class ImagePickerViewController:
setupUI()
setupConstraints()
loadPhotos()
+ navigationController?.navigationBar.tintColor = .gray900
resultPublisher
.compactMap { if case .selected(let a) = $0 { return a } else { return nil } }
@@ -240,12 +241,12 @@ public final class ImagePickerViewController:
target: self,
action: #selector(selectAllButtonTapped)
)
- selectAllButton.tintColor = .white
+ selectAllButton.tintColor = .gray900
navigationItem.rightBarButtonItem = selectAllButton
}
private func setupUI() {
- view.backgroundColor = DesignSystemAsset.sdBase.color
+ view.backgroundColor = .white
view.addSubview(collectionView)
view.addSubview(emptyView)
diff --git a/FoodDiary/Presentation/Sources/MyPage/Components/ProfileHeaderView.swift b/FoodDiary/Presentation/Sources/MyPage/Components/ProfileHeaderView.swift
index 510ac06c..5e2b315b 100644
--- a/FoodDiary/Presentation/Sources/MyPage/Components/ProfileHeaderView.swift
+++ b/FoodDiary/Presentation/Sources/MyPage/Components/ProfileHeaderView.swift
@@ -18,21 +18,21 @@ final class ProfileHeaderView: UIView {
iv.layer.cornerRadius = 36
iv.clipsToBounds = true
iv.layer.borderWidth = 3
- iv.layer.borderColor = UIColor.sd800.cgColor
+ iv.layer.borderColor = UIColor.white.cgColor
return iv
}()
private let greetingLabel: UILabel = {
let label = UILabel()
- label.setText("안녕하세요,", style: .p12, color: .gray050)
+ label.setText("안녕하세요,", style: .p12, color: .gray500)
label.textAlignment = .center
return label
}()
private let nameLabel: UILabel = {
let label = UILabel()
- label.setText("홍길동님", style: .hd18, color: .white)
+ label.setText("홍길동님", style: .hd18, color: .gray900)
label.textAlignment = .center
return label
}()
@@ -55,12 +55,12 @@ final class ProfileHeaderView: UIView {
private let separatorView: UIView = {
let view = UIView()
- view.backgroundColor = .sd800
+ view.backgroundColor = .gray150
return view
}()
func configure(nickname: String) {
- nameLabel.setText("\(nickname)님", style: .hd18, color: .white)
+ nameLabel.setText("\(nickname)님", style: .hd18, color: .gray900)
}
override init(frame: CGRect) {
@@ -75,13 +75,13 @@ final class ProfileHeaderView: UIView {
}
private func setupUI() {
- backgroundColor = .sd700
+ backgroundColor = .gray040
[contentStackView, separatorView].forEach { addSubview($0) }
}
private func setupConstraints() {
self.snp.makeConstraints {
- $0.height.equalTo(280)
+ $0.height.equalTo(248)
}
characterImageView.snp.makeConstraints {
@@ -89,7 +89,7 @@ final class ProfileHeaderView: UIView {
}
contentStackView.snp.makeConstraints {
- $0.centerY.equalToSuperview().offset(40)
+ $0.centerY.equalToSuperview()
$0.centerX.equalToSuperview()
}
diff --git a/FoodDiary/Presentation/Sources/MyPage/Components/WithdrawalFooterView.swift b/FoodDiary/Presentation/Sources/MyPage/Components/WithdrawalFooterView.swift
index 8fa09a32..a3040cf8 100644
--- a/FoodDiary/Presentation/Sources/MyPage/Components/WithdrawalFooterView.swift
+++ b/FoodDiary/Presentation/Sources/MyPage/Components/WithdrawalFooterView.swift
@@ -13,7 +13,7 @@ final class WithdrawalFooterView: UIView {
private let withdrawalLabel: UILabel = {
let label = UILabel()
- let base = Typography.p12.styled("탈퇴", color: .gray050)
+ let base = Typography.p12.styled("탈퇴", color: .gray900)
let mutable = NSMutableAttributedString(attributedString: base)
mutable.addAttribute(.underlineStyle, value: NSUnderlineStyle.single.rawValue, range: NSRange(location: 0, length: mutable.length))
label.attributedText = mutable
@@ -27,7 +27,7 @@ final class WithdrawalFooterView: UIView {
addSubview(withdrawalLabel)
withdrawalLabel.snp.makeConstraints {
- $0.trailing.equalToSuperview().offset(-28)
+ $0.trailing.equalToSuperview().offset(-16)
$0.centerY.equalToSuperview()
}
diff --git a/FoodDiary/Presentation/Sources/MyPage/MyPageViewController.swift b/FoodDiary/Presentation/Sources/MyPage/MyPageViewController.swift
index 90df47dd..b7a3107d 100644
--- a/FoodDiary/Presentation/Sources/MyPage/MyPageViewController.swift
+++ b/FoodDiary/Presentation/Sources/MyPage/MyPageViewController.swift
@@ -22,8 +22,8 @@ public final class MyPageViewController: UIViewController {
var headerIcon: UIImage? {
switch self {
- case .notifications: return DesignSystemAsset.iconAlert.image
- case .management: return DesignSystemAsset.iconSetting.image
+ case .notifications: return DesignSystemAsset.iconAlert.image.withRenderingMode(.alwaysTemplate)
+ case .management: return DesignSystemAsset.iconSetting.image.withRenderingMode(.alwaysTemplate)
case .logout: return nil
}
}
@@ -69,12 +69,13 @@ public final class MyPageViewController: UIViewController {
// MARK: - State
private var cancellables = Set()
+ private var withdrawalFooterView: WithdrawalFooterView?
// MARK: - UI Components
private lazy var scrollView: UIScrollView = {
let sv = UIScrollView()
- sv.backgroundColor = .sdBase
+ sv.backgroundColor = .white
sv.showsVerticalScrollIndicator = false
return sv
}()
@@ -86,7 +87,7 @@ public final class MyPageViewController: UIViewController {
private lazy var tableView: UITableView = {
let tv = UITableView(frame: .zero, style: .insetGrouped)
- tv.backgroundColor = .sdBase
+ tv.backgroundColor = .white
tv.showsVerticalScrollIndicator = false
tv.separatorColor = .clear
tv.isScrollEnabled = false
@@ -136,17 +137,36 @@ public final class MyPageViewController: UIViewController {
public override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
updateTableViewHeight()
+ updateTableFooterWidthIfNeeded()
}
// MARK: - Setup
private func setupNavigation() {
- title = "마이페이지"
navigationController?.navigationBar.prefersLargeTitles = false
+ navigationController?.navigationBar.tintColor = .gray900
+
+ let appearance = UINavigationBarAppearance()
+ appearance.configureWithOpaqueBackground()
+ appearance.backgroundColor = .white
+ appearance.shadowColor = .gray150
+ navigationController?.navigationBar.standardAppearance = appearance
+ navigationController?.navigationBar.scrollEdgeAppearance = appearance
+ navigationController?.navigationBar.compactAppearance = appearance
+
+ navigationItem.leftBarButtonItem = UIBarButtonItem(
+ image: UIImage(systemName: "chevron.left"),
+ style: .plain,
+ target: self,
+ action: #selector(backButtonTapped)
+ )
+ navigationItem.rightBarButtonItem = UIBarButtonItem(
+ customView: makeProfileIconView()
+ )
}
private func setupUI() {
- view.backgroundColor = .sdBase
+ view.backgroundColor = .white
view.addSubview(scrollView)
scrollView.addSubview(profileHeaderView)
scrollView.addSubview(tableView)
@@ -154,16 +174,16 @@ public final class MyPageViewController: UIViewController {
private func setupConstraints() {
scrollView.snp.makeConstraints {
- $0.edges.equalToSuperview()
+ $0.edges.equalTo(view.safeAreaLayoutGuide)
}
profileHeaderView.snp.makeConstraints {
- $0.top.equalTo(view.snp.top)
+ $0.top.equalTo(scrollView.contentLayoutGuide)
$0.leading.trailing.equalTo(scrollView.frameLayoutGuide)
}
tableView.snp.makeConstraints {
- $0.top.equalTo(profileHeaderView.snp.bottom).offset(30)
+ $0.top.equalTo(profileHeaderView.snp.bottom).offset(24)
$0.leading.trailing.equalTo(scrollView.frameLayoutGuide)
$0.bottom.equalTo(scrollView.contentLayoutGuide)
tableViewHeightConstraint = $0.height.equalTo(0).constraint
@@ -178,11 +198,21 @@ public final class MyPageViewController: UIViewController {
private func setupTableFooter() {
let footer = WithdrawalFooterView()
- footer.frame = CGRect(x: 0, y: 0, width: tableView.frame.width, height: 44)
+ footer.frame = CGRect(x: 0, y: 0, width: view.bounds.width, height: 44)
footer.onTap = { [weak self] in
self?.showWithdrawalAlert()
}
tableView.tableFooterView = footer
+ withdrawalFooterView = footer
+ }
+
+ private func updateTableFooterWidthIfNeeded() {
+ guard let footer = withdrawalFooterView else { return }
+ let width = tableView.bounds.width
+ guard width > 0, abs(footer.frame.width - width) > .ulpOfOne else { return }
+
+ footer.frame = CGRect(x: 0, y: 0, width: width, height: footer.frame.height)
+ tableView.tableFooterView = footer
}
private func showWithdrawalAlert() {
@@ -221,7 +251,7 @@ public final class MyPageViewController: UIViewController {
if let cell = tableView.cellForRow(at: indexPath),
let badge = cell.contentView.viewWithTag(999) as? UILabel {
badge.text = isEnabled ? "ON" : "OFF"
- badge.backgroundColor = isEnabled ? DesignSystemAsset.primary.color : DesignSystemAsset.gray600.color
+ badge.backgroundColor = isEnabled ? DesignSystemAsset.primary.color : DesignSystemAsset.sd800.color
} else {
tableView.reloadRows(at: [indexPath], with: .none)
}
@@ -258,14 +288,14 @@ public final class MyPageViewController: UIViewController {
private func configureCell(_ cell: UITableViewCell, for row: Row, at indexPath: IndexPath) {
var backgroundConfig = UIBackgroundConfiguration.listCell()
- backgroundConfig.backgroundColor = .sd700
+ backgroundConfig.backgroundColor = .gray040
cell.backgroundConfiguration = backgroundConfig
cell.selectionStyle = .none
cell.contentConfiguration = nil
switch row {
case .notificationSetting:
- cell.textLabel?.setText("알림설정", style: .p14, color: .gray050)
+ cell.textLabel?.setText("알림설정", style: .p14, color: .gray900)
cell.accessoryView = makeChevronAccessory()
// 기존 배지 제거 (재사용 대비)
@@ -279,7 +309,7 @@ public final class MyPageViewController: UIViewController {
// 알림 권한 상태에 따라 배지 텍스트/색상 결정
let isEnabled = viewModel.state.isNotificationEnabled
let badgeText = isEnabled ? "ON" : "OFF"
- let badgeColor = isEnabled ? DesignSystemAsset.primary.color : DesignSystemAsset.gray600.color
+ let badgeColor = isEnabled ? DesignSystemAsset.primary.color : DesignSystemAsset.sd800.color
let badge = makeBadgeLabel(text: badgeText, backgroundColor: badgeColor)
badge.tag = 999
@@ -294,19 +324,19 @@ public final class MyPageViewController: UIViewController {
])
case .appVersion:
- cell.textLabel?.setText("앱 버전", style: .p14, color: .gray050)
+ cell.textLabel?.setText("앱 버전", style: .p14, color: .gray900)
cell.accessoryView = makeVersionLabel(text: viewModel.state.appVersion)
case .privacy:
- cell.textLabel?.setText("개인정보 처리방침", style: .p14, color: .gray050)
+ cell.textLabel?.setText("개인정보 처리방침", style: .p14, color: .gray900)
cell.accessoryView = makeChevronAccessory()
case .customerInquiry:
- cell.textLabel?.setText("문의하기", style: .p14, color: .gray050)
+ cell.textLabel?.setText("문의하기", style: .p14, color: .gray900)
cell.accessoryView = makeChevronAccessory()
case .logout:
- cell.textLabel?.setText("로그아웃", style: .p14, color: .gray050)
+ cell.textLabel?.setText("로그아웃", style: .p14, color: .gray900)
cell.accessoryView = makeLogoutIconAccessory()
}
}
@@ -315,18 +345,22 @@ public final class MyPageViewController: UIViewController {
private func makeVersionLabel(text: String) -> UILabel {
let label = UILabel()
- label.setText(text, style: .p14, color: .gray700)
+ label.setText(text, style: .p14, color: .gray600)
label.sizeToFit()
return label
}
private func makeChevronAccessory() -> UIImageView {
- let iv = UIImageView(image: DesignSystemAsset.iconNext.image)
+ let iv = UIImageView(image: DesignSystemAsset.iconArrow.image.withRenderingMode(.alwaysTemplate))
+ iv.tintColor = .gray850
+ iv.frame = CGRect(x: 0, y: 0, width: 18, height: 18)
+ iv.contentMode = .scaleAspectFit
return iv
}
private func makeLogoutIconAccessory() -> UIImageView {
- let iv = UIImageView(image: DesignSystemAsset.iconLogout.image)
+ let iv = UIImageView(image: DesignSystemAsset.iconLogout.image.withRenderingMode(.alwaysTemplate))
+ iv.tintColor = .gray850
return iv
}
@@ -341,6 +375,20 @@ public final class MyPageViewController: UIViewController {
label.textAlignment = .center
return label
}
+
+ private func makeProfileIconView() -> UIImageView {
+ let imageView = UIImageView(
+ image: DesignSystemAsset.iconMypage.image.withRenderingMode(.alwaysTemplate)
+ )
+ imageView.contentMode = .scaleAspectFit
+ imageView.tintColor = .gray850
+ imageView.frame = CGRect(x: 0, y: 0, width: 24, height: 24)
+ return imageView
+ }
+
+ @objc private func backButtonTapped() {
+ navigationController?.popViewController(animated: true)
+ }
}
// MARK: - UITableViewDataSource
@@ -383,7 +431,7 @@ extension MyPageViewController: UITableViewDelegate {
if let icon = sec.headerIcon {
let iconImageView = UIImageView(image: icon)
iconImageView.contentMode = .scaleAspectFit
- iconImageView.tintColor = .gray400
+ iconImageView.tintColor = .gray850
iconImageView.snp.makeConstraints {
$0.size.equalTo(18)
}
@@ -391,7 +439,7 @@ extension MyPageViewController: UITableViewDelegate {
}
let label = UILabel()
- label.setText(title, style: .p12, color: .gray050)
+ label.setText(title, style: .p12, color: .gray900)
stackView.addArrangedSubview(label)
headerView.addSubview(stackView)
@@ -469,4 +517,3 @@ extension MyPageViewController: UITableViewDelegate {
UIApplication.shared.open(url)
}
}
-
diff --git a/FoodDiary/Presentation/Sources/Onboarding/OnboardPageContentViewController.swift b/FoodDiary/Presentation/Sources/Onboarding/OnboardPageContentViewController.swift
index 59f929a9..19ac48b8 100644
--- a/FoodDiary/Presentation/Sources/Onboarding/OnboardPageContentViewController.swift
+++ b/FoodDiary/Presentation/Sources/Onboarding/OnboardPageContentViewController.swift
@@ -8,11 +8,19 @@ import SnapKit
import DesignSystem
final class OnboardPageContentViewController: UIViewController {
+ private enum Constants {
+ static let imageSize: CGFloat = 180
+ static let imageTopOffset: CGFloat = 104
+ static let textTopSpacing: CGFloat = 36
+ static let textHorizontalInset: CGFloat = 20
+ }
+
let pageIndex: Int
private let imageView: UIImageView = {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFit
+ imageView.clipsToBounds = true
return imageView
}()
@@ -23,19 +31,16 @@ final class OnboardPageContentViewController: UIViewController {
return label
}()
- private lazy var stackView: UIStackView = {
- let stackView = UIStackView(arrangedSubviews: [imageView, textLabel])
- stackView.axis = .vertical
- stackView.spacing = 40
- stackView.alignment = .center
- return stackView
- }()
-
init(pageIndex: Int, image: UIImage?, text: String) {
self.pageIndex = pageIndex
super.init(nibName: nil, bundle: nil)
imageView.image = image
- textLabel.setText(text, style: .p15)
+ textLabel.attributedText = Typography.p15.styled(
+ text,
+ color: .gray850,
+ alignment: .center,
+ lineSpacing: 3.75
+ )
textLabel.textAlignment = .center
}
@@ -51,18 +56,19 @@ final class OnboardPageContentViewController: UIViewController {
private extension OnboardPageContentViewController {
func setupUI() {
- view.backgroundColor = DesignSystemAsset.sdBase.color
- view.addSubview(stackView)
+ view.backgroundColor = .white
+ view.addSubview(imageView)
+ view.addSubview(textLabel)
- stackView.snp.makeConstraints {
- $0.top.equalToSuperview().offset(130)
- $0.leading.trailing.equalToSuperview().inset(65)
+ imageView.snp.makeConstraints {
$0.centerX.equalToSuperview()
+ $0.top.equalToSuperview().offset(Constants.imageTopOffset)
+ $0.size.equalTo(Constants.imageSize)
}
- imageView.snp.makeConstraints {
- $0.height.equalTo(220)
- $0.width.equalTo(imageView.snp.height)
+ textLabel.snp.makeConstraints {
+ $0.top.equalTo(imageView.snp.bottom).offset(Constants.textTopSpacing)
+ $0.leading.trailing.equalToSuperview().inset(Constants.textHorizontalInset)
$0.centerX.equalToSuperview()
}
}
diff --git a/FoodDiary/Presentation/Sources/Onboarding/OnboardingViewController.swift b/FoodDiary/Presentation/Sources/Onboarding/OnboardingViewController.swift
index d879afec..40812fa4 100644
--- a/FoodDiary/Presentation/Sources/Onboarding/OnboardingViewController.swift
+++ b/FoodDiary/Presentation/Sources/Onboarding/OnboardingViewController.swift
@@ -17,13 +17,15 @@ public final class OnboardingViewController: UIViewController {
didCompleteSubject.eraseToAnyPublisher()
}
- @Published private var currentPage: Int = 0
-
- private var cancellables = Set()
+ private var currentPage: Int = 0 {
+ didSet {
+ updateCurrentPageAppearance()
+ }
+ }
private let pages: [(image: UIImage?, text: String)] = [
- (DesignSystemAsset.onboard1.image, "여기저기 흩어진 음식 기록을,\n간편히 정리해 드릴게요"),
- (DesignSystemAsset.onboard2.image, "음식 기록은 간편하게 시작하고\n활용은 자유롭게 이어가세요."),
+ (DesignSystemAsset.onboard1.image, "여기저기 흩어진 음식 기록들,\n간편히 정리해 드릴게요"),
+ (DesignSystemAsset.onboard2.image, "음식 기록은 간편하게 시작하고,\n활용은 자유롭게 이어가세요."),
(DesignSystemAsset.onboard3.image, "음식 사진을 올리면 식당, 메뉴,\n방문 정보를 자동으로 정리해줘요."),
(DesignSystemAsset.onboard4.image, "정리된 기록을 블로그나 SNS에\n바로 활용할 수 있어요."),
(DesignSystemAsset.onboard5.image, "기록이 쌓일수록 무엇을, 언제,\n얼마나 먹는지 한눈에 보여요.")
@@ -42,21 +44,59 @@ public final class OnboardingViewController: UIViewController {
return pageVC
}()
- private let pageControl: UIPageControl = {
- let pageControl = UIPageControl()
- pageControl.currentPageIndicatorTintColor = DesignSystemAsset.primary.color
- pageControl.pageIndicatorTintColor = DesignSystemAsset.sd800.color
- pageControl.isUserInteractionEnabled = false
- return pageControl
+ private lazy var pageIndicatorDots: [UIView] = {
+ pages.indices.map { index in
+ let dot = UIView()
+ dot.backgroundColor = index == 0 ? .primary : .sd800
+ dot.layer.cornerRadius = 3
+ dot.clipsToBounds = true
+ dot.snp.makeConstraints {
+ $0.size.equalTo(6)
+ }
+ return dot
+ }
+ }()
+
+ private lazy var pageIndicatorStackView: UIStackView = {
+ let stackView = UIStackView(arrangedSubviews: pageIndicatorDots)
+ stackView.axis = .horizontal
+ stackView.alignment = .center
+ stackView.distribution = .equalSpacing
+ stackView.spacing = 4
+ return stackView
+ }()
+
+ private let headerView: UIView = {
+ let view = UIView()
+ view.backgroundColor = .white
+ return view
+ }()
+
+ private let headerSeparatorView: UIView = {
+ let view = UIView()
+ view.backgroundColor = .gray150
+ return view
+ }()
+
+ private lazy var skipButton: UIButton = {
+ let button = UIButton(type: .system)
+ button.setAttributedTitle(
+ Typography.p15.styled("건너뛰기", color: .black, alignment: .right),
+ for: .normal
+ )
+ button.addTarget(self, action: #selector(skipButtonTapped), for: .touchUpInside)
+ return button
}()
private lazy var nextButton: UIButton = {
let button = UIButton(type: .system)
- button.titleLabel?.font = .systemFont(ofSize: 17, weight: .semibold)
- button.setTitle("다음", for: .normal)
+ button.setAttributedTitle(
+ Typography.hd15.styled("다음", color: .sdBase, alignment: .center),
+ for: .normal
+ )
button.backgroundColor = DesignSystemAsset.primary.color
- button.setTitleColor(DesignSystemAsset.sdBase.color, for: .normal)
button.clipsToBounds = true
+ button.addTarget(self, action: #selector(nextButtonTapped), for: .touchUpInside)
return button
}()
@@ -71,13 +111,20 @@ public final class OnboardingViewController: UIViewController {
public override func viewDidLoad() {
super.viewDidLoad()
configureUI()
- configureNavigationBar()
- setupActions()
- setupBindings()
- pageControl.numberOfPages = pages.count
+ updateCurrentPageAppearance()
pageViewController.setViewControllers([pageViewControllers[0]], direction: .forward, animated: false)
}
+ public override func viewWillAppear(_ animated: Bool) {
+ super.viewWillAppear(animated)
+ navigationController?.setNavigationBarHidden(true, animated: animated)
+ }
+
+ public override func viewWillDisappear(_ animated: Bool) {
+ super.viewWillDisappear(animated)
+ navigationController?.setNavigationBarHidden(false, animated: animated)
+ }
+
public override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
nextButton.layer.cornerRadius = nextButton.frame.height / 2
@@ -86,61 +133,67 @@ public final class OnboardingViewController: UIViewController {
private extension OnboardingViewController {
func configureUI() {
- view.backgroundColor = DesignSystemAsset.sdBase.color
+ view.backgroundColor = .white
+
+ view.addSubview(headerView)
+ headerView.addSubview(skipButton)
+ view.addSubview(headerSeparatorView)
addChild(pageViewController)
view.addSubview(pageViewController.view)
pageViewController.didMove(toParent: self)
- view.addSubview(pageControl)
+ view.addSubview(pageIndicatorStackView)
view.addSubview(nextButton)
- pageViewController.view.snp.makeConstraints {
+ headerView.snp.makeConstraints {
$0.top.equalTo(view.safeAreaLayoutGuide.snp.top)
$0.leading.trailing.equalToSuperview()
- $0.bottom.equalTo(pageControl.snp.top).offset(-10)
+ $0.height.equalTo(60)
}
- pageControl.snp.makeConstraints {
- $0.centerX.equalToSuperview()
- $0.bottom.equalTo(nextButton.snp.top).offset(-100)
+ skipButton.snp.makeConstraints {
+ $0.trailing.equalToSuperview().inset(20)
+ $0.centerY.equalToSuperview()
}
- nextButton.snp.makeConstraints {
- $0.leading.trailing.equalToSuperview().inset(16)
- $0.height.equalTo(55)
- $0.bottom.equalTo(view.safeAreaLayoutGuide).inset(18)
+ headerSeparatorView.snp.makeConstraints {
+ $0.top.equalTo(headerView.snp.bottom)
+ $0.leading.trailing.equalToSuperview()
+ $0.height.equalTo(1)
}
- }
- func configureNavigationBar() {
- let skipButton = UIBarButtonItem(
- title: "건너뛰기",
- style: .plain,
- target: self,
- action: #selector(skipButtonTapped)
- )
+ pageIndicatorStackView.snp.makeConstraints {
+ $0.centerX.equalToSuperview()
+ $0.bottom.equalTo(nextButton.snp.top).offset(-136)
+ }
- navigationItem.rightBarButtonItem = skipButton
- }
+ pageViewController.view.snp.makeConstraints {
+ $0.top.equalTo(headerSeparatorView.snp.bottom)
+ $0.leading.trailing.equalToSuperview()
+ $0.bottom.equalTo(pageIndicatorStackView.snp.top)
+ }
- func setupActions() {
- nextButton.addTarget(self, action: #selector(nextButtonTapped), for: .touchUpInside)
+ nextButton.snp.makeConstraints {
+ $0.leading.trailing.equalToSuperview().inset(16)
+ $0.height.equalTo(50)
+ $0.bottom.equalToSuperview().inset(36)
+ }
}
- func setupBindings() {
- $currentPage
- .receive(on: DispatchQueue.main)
- .sink { [weak self] page in
- guard let self = self else { return }
- self.pageControl.currentPage = page
- self.updateNextButton()
- }
- .store(in: &cancellables)
+ func updateCurrentPageAppearance() {
+ updateNextButtonTitle()
+ pageIndicatorDots.enumerated().forEach { index, dot in
+ dot.backgroundColor = index == currentPage ? .primary : .sd800
+ }
}
- func updateNextButton() {
- nextButton.setTitle(currentPage == pages.count - 1 ? "시작하기" : "다음", for: .normal)
+ func updateNextButtonTitle() {
+ let title = currentPage == pages.count - 1 ? "시작하기" : "다음"
+ nextButton.setAttributedTitle(
+ Typography.hd15.styled(title, color: .sdBase, alignment: .center),
+ for: .normal
+ )
}
@objc func skipButtonTapped() {