diff --git a/FoodDiary/Presentation/Sources/Calendar/WeeklyCalendar/Components/BottomContentView.swift b/FoodDiary/Presentation/Sources/Calendar/WeeklyCalendar/Components/BottomContentView.swift index 06a2858..3b4dabd 100644 --- a/FoodDiary/Presentation/Sources/Calendar/WeeklyCalendar/Components/BottomContentView.swift +++ b/FoodDiary/Presentation/Sources/Calendar/WeeklyCalendar/Components/BottomContentView.swift @@ -129,8 +129,8 @@ final class BottomContentView: UIView { currentState = state switch state { - case .empty: - showEmptyState() + case .empty(let hasPhotos): + showEmptyState(hasPhotos: hasPhotos) case .processing(let records): if let first = records.first { showProcessingState(record: first) @@ -182,7 +182,7 @@ final class BottomContentView: UIView { containerView.layer.borderWidth = show ? Constants.containerBorderWidth : 0 } - private func showEmptyState() { + private func showEmptyState(hasPhotos: Bool) { cardStackStateView.isHidden = true processingStateView.isHidden = true showContainerStyle(false) @@ -192,7 +192,12 @@ final class BottomContentView: UIView { cancellables.removeAll() // 새로 생성 - let newEmptyView = EmptyFoodRecordView(text: "오늘의 음식 사진을 추가해보세요") + let newEmptyView = EmptyFoodRecordView( + text: hasPhotos + ? "오늘의 음식 사진을 추가해보세요" + : "기록 가능한 음식 사진이 없어요", + style: hasPhotos ? .addable : .unavailable + ) containerView.addSubview(newEmptyView) emptyStateView = newEmptyView @@ -200,12 +205,14 @@ final class BottomContentView: UIView { $0.edges.equalToSuperview() } - // Publisher 바인딩 - newEmptyView.addButtonTapPublisher - .sink { [weak self] in - self?.addButtonTapSubject.send() - } - .store(in: &cancellables) + // 사진이 있을 때만 탭 Publisher 바인딩 + if hasPhotos { + newEmptyView.addButtonTapPublisher + .sink { [weak self] in + self?.addButtonTapSubject.send() + } + .store(in: &cancellables) + } } private func showCardStackState(record: FoodRecord, totalCount: Int) { @@ -245,7 +252,7 @@ final class BottomContentView: UIView { extension BottomContentView { enum State: Equatable { - case empty + case empty(hasPhotos: Bool) case processing([FoodRecord]) case recorded([FoodRecord]) } diff --git a/FoodDiary/Presentation/Sources/Calendar/WeeklyCalendar/ViewModel/WeeklyCalendarViewModel.swift b/FoodDiary/Presentation/Sources/Calendar/WeeklyCalendar/ViewModel/WeeklyCalendarViewModel.swift index a6e36b8..5ea07ba 100644 --- a/FoodDiary/Presentation/Sources/Calendar/WeeklyCalendar/ViewModel/WeeklyCalendarViewModel.swift +++ b/FoodDiary/Presentation/Sources/Calendar/WeeklyCalendar/ViewModel/WeeklyCalendarViewModel.swift @@ -194,12 +194,30 @@ public final class WeeklyCalendarViewModel< let completedRecords = allRecords.filter { !$0.isProcessing } let processingRecords = allRecords.filter { $0.isProcessing } + var hasFoodPhotos = false + if completedRecords.isEmpty && processingRecords.isEmpty { + hasFoodPhotos = await checkFoodPhotosExist(for: date) + } + state.dateContent = DateContent( records: completedRecords, - processingRecords: processingRecords + processingRecords: processingRecords, + hasFoodPhotos: hasFoodPhotos ) } + private func checkFoodPhotosExist(for date: Date) async -> Bool { + guard requestPhotoAuthorizationUseCase.isAuthorized() else { + return false + } + do { + let photos = try await loadWeeklyCalendarDataUseCase.loadPhotos(for: date) + return !photos.isEmpty + } catch { + return false + } + } + @MainActor private func savePhotosAsRecord(_ assets: [AssetRepo.Asset]) async { guard !assets.isEmpty else { return } @@ -318,6 +336,7 @@ extension WeeklyCalendarViewModel { public struct DateContent: Equatable { public let records: [FoodRecord] public let processingRecords: [FoodRecord] + public let hasFoodPhotos: Bool } } diff --git a/FoodDiary/Presentation/Sources/Calendar/WeeklyCalendar/WeeklyCalendarViewController.swift b/FoodDiary/Presentation/Sources/Calendar/WeeklyCalendar/WeeklyCalendarViewController.swift index 13fe78d..3eacdb3 100644 --- a/FoodDiary/Presentation/Sources/Calendar/WeeklyCalendar/WeeklyCalendarViewController.swift +++ b/FoodDiary/Presentation/Sources/Calendar/WeeklyCalendar/WeeklyCalendarViewController.swift @@ -213,7 +213,7 @@ public final class WeeklyCalendarViewController< } else if !content.processingRecords.isEmpty { .processing(content.processingRecords) } else { - .empty + .empty(hasPhotos: content.hasFoodPhotos) } bottomContentView.configure(state: state) diff --git a/FoodDiary/Presentation/Sources/Components/EmptyFoodRecordView.swift b/FoodDiary/Presentation/Sources/Components/EmptyFoodRecordView.swift index a57dd4e..3ba1c57 100644 --- a/FoodDiary/Presentation/Sources/Components/EmptyFoodRecordView.swift +++ b/FoodDiary/Presentation/Sources/Components/EmptyFoodRecordView.swift @@ -11,6 +11,13 @@ import UIKit /// 음식 기록이 없을 때 표시되는 빈 상태 뷰 final class EmptyFoodRecordView: UIView { + // MARK: - Style + + enum Style { + case addable + case unavailable + } + // MARK: - Constants private enum Constants { @@ -35,7 +42,6 @@ final class EmptyFoodRecordView: UIView { private let addImageView: UIImageView = { let iv = UIImageView() - iv.image = DesignSystemAsset.add.image iv.contentMode = .scaleAspectFit return iv }() @@ -49,11 +55,13 @@ final class EmptyFoodRecordView: UIView { // MARK: - Init - init(text: String) { + init(text: String, style: Style = .addable) { super.init(frame: .zero) - setupUI() + setupUI(style: style) setupConstraints() - setupActions() + if style == .addable { + setupActions() + } placeholderLabel.setText(text, style: .p14, color: .gray050) } @@ -64,7 +72,7 @@ final class EmptyFoodRecordView: UIView { // MARK: - Setup - private func setupUI() { + private func setupUI(style: Style) { dashedBorderView.cornerRadius = Constants.cornerRadius dashedBorderView.backgroundColor = .sd900 dashedBorderView.layer.cornerRadius = Constants.cornerRadius @@ -72,6 +80,13 @@ final class EmptyFoodRecordView: UIView { addSubview(dashedBorderView) dashedBorderView.addSubview(contentView) + switch style { + case .addable: + addImageView.image = DesignSystemAsset.add.image + case .unavailable: + addImageView.image = DesignSystemAsset.emptyMeal.image + } + contentView.addSubview(addImageView) contentView.addSubview(placeholderLabel) }