Skip to content

Commit e272b18

Browse files
committed
[Feat] #192 - 이미지별 메모 기능 구현
1 parent f59d53b commit e272b18

7 files changed

Lines changed: 382 additions & 55 deletions

File tree

Neki-iOS/Features/Archive/Sources/Presentation/Sources/Components/ArchiveImageFooter.swift

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ struct ArchiveImageFooter: View {
2020
let onDownload: () -> Void
2121
let onDelete: () -> Void
2222
let onFavorite: (() -> Void)?
23+
let onTapMemo: (() -> Void)?
2324

2425
// MARK: - Init
2526

@@ -28,13 +29,15 @@ struct ArchiveImageFooter: View {
2829
isFavorite: Bool? = nil,
2930
onDownload: @escaping () -> Void,
3031
onDelete: @escaping () -> Void,
31-
onFavorite: (() -> Void)? = nil
32+
onFavorite: (() -> Void)? = nil,
33+
onTapMemo: (() -> Void)? = nil
3234
) {
3335
self.isEnabled = isEnabled
3436
self.isFavorite = isFavorite
3537
self.onDownload = onDownload
3638
self.onDelete = onDelete
3739
self.onFavorite = onFavorite
40+
self.onTapMemo = onTapMemo
3841
}
3942

4043
// MARK: - Body
@@ -44,33 +47,38 @@ struct ArchiveImageFooter: View {
4447
Button(action: onDownload) {
4548
Image(isEnabled ? .iconDownloadFill : .iconDownload)
4649
.renderingMode(.template)
47-
.foregroundStyle(isEnabled ? .gray500 : .gray100)
50+
.foregroundStyle(isEnabled ? .gray700 : .gray100)
4851
}
49-
.frame(width: 44, height: 44)
5052
.disabled(!isEnabled)
5153

5254
if let isFavorite = isFavorite, let onFavorite = onFavorite {
5355
Button(action: onFavorite) {
5456
Image(isFavorite ? .iconHeart28Fill : .iconHeart28Gray)
5557
.renderingMode(.template)
56-
.foregroundStyle(isFavorite ? .red : .gray300)
58+
.foregroundStyle(isFavorite ? .red : .gray700)
5759
}
58-
.padding(.leading, 12)
59-
.frame(width: 44, height: 44)
60+
.padding(.leading, 16)
61+
}
62+
63+
if let onTapMemo = onTapMemo {
64+
Button(action: onTapMemo) {
65+
Image(.iconNote)
66+
.foregroundStyle(.gray700)
67+
}
68+
.padding(.leading, 16)
6069
}
6170

6271
Spacer()
6372

6473
Button(action: onDelete) {
6574
Image(isEnabled ? .iconTrashFill : .iconTrash)
6675
.renderingMode(.template)
67-
.foregroundStyle(isEnabled ? .gray600 : .gray100)
76+
.foregroundStyle(isEnabled ? .gray700 : .gray100)
6877
}
69-
.frame(width: 44, height: 44)
7078
.disabled(!isEnabled)
7179
}
7280
.padding(.horizontal, 20)
73-
.padding(.vertical, 12)
81+
.padding(.vertical, 20)
7482
.background(Color.white)
7583
.overlay(
7684
Rectangle()

Neki-iOS/Features/Archive/Sources/Presentation/Sources/Feature/ArchivePhotoDetailFeature.swift

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,28 @@ struct ArchivePhotoDetailFeature {
3232
}
3333

3434
var isLoading: Bool = false
35+
36+
// MARK: - Memo States
37+
38+
var isMemoVisible: Bool = false // 단순 조회 모드 가시성
39+
var isMemoExpanded: Bool = false // 단순 조회 모드 더 보기(확장) 여부
40+
var isMemoEditing: Bool = false // 편집 모드 여부
41+
var editingMemoText: String = "" // 편집 중인 임시 텍스트
3542
}
3643

3744
enum Action: BindableAction {
3845
case binding(BindingAction<State>)
3946

47+
// 메모 조회 모드 액션
48+
case toggleMemoVisibility
49+
case toggleMemoExpanded(Bool)
50+
51+
// 메모 편집 모드 액션
52+
case startMemoEditing
53+
case cancelMemoEditing
54+
case doneMemoEditing
55+
case clearAllMemoEditing
56+
4057
case onTapTransform
4158
case imageFetchResponse(Result<UIImage, Error>)
4259
case imageTransform(PresentationAction<ImageTransformFeature.Action>)
@@ -67,6 +84,42 @@ struct ArchivePhotoDetailFeature {
6784
Reduce { state, action in
6885
switch action {
6986

87+
// MARK: - 메모 조회 모드 로직
88+
case .toggleMemoVisibility:
89+
state.isMemoVisible.toggle()
90+
if !state.isMemoVisible {
91+
state.isMemoExpanded = false
92+
}
93+
return .none
94+
95+
case let .toggleMemoExpanded(isExpanded):
96+
state.isMemoExpanded = isExpanded
97+
return .none
98+
99+
// MARK: - 메모 편집 모드 로직
100+
case .startMemoEditing:
101+
state.isMemoEditing = true
102+
state.isMemoVisible = true
103+
state.isMemoExpanded = true
104+
state.editingMemoText = state.currentItem?.memo ?? ""
105+
return .none
106+
107+
case .cancelMemoEditing:
108+
state.isMemoEditing = false
109+
state.isMemoExpanded = false
110+
return .none
111+
112+
case .doneMemoEditing:
113+
let limitedText = String(state.editingMemoText.prefix(100))
114+
state.photos[id: state.currentItemID]?.memo = limitedText
115+
state.isMemoEditing = false
116+
state.isMemoExpanded = false
117+
return .none
118+
119+
case .clearAllMemoEditing:
120+
state.editingMemoText = ""
121+
return .none
122+
70123
case .onTapTransform:
71124
guard let url = state.currentItem?.imageURL else { return .none }
72125

Neki-iOS/Features/Archive/Sources/Presentation/Sources/Item/ArchiveImageItem.swift

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,18 @@ struct ArchiveImageItem: Equatable, Identifiable {
1313
var isFavorite: Bool
1414
let date: Date
1515
var folderId: Int?
16+
var memo: String
1617

17-
init(id: Int, imageURL: URL?, isFavorite: Bool = false, date: Date = Date(), folderId: Int? = nil) {
18-
self.id = id
19-
self.imageURL = imageURL
20-
self.isFavorite = isFavorite
21-
self.date = date
22-
self.folderId = folderId
23-
}
18+
init(id: Int, imageURL: URL?, isFavorite: Bool = false, date: Date = Date(), folderId: Int? = nil, memo: String = "") {
19+
self.id = id
20+
self.imageURL = imageURL
21+
self.isFavorite = isFavorite
22+
self.date = date
23+
self.folderId = folderId
24+
self.memo = memo
25+
}
2426

25-
init(id: Int, imageURLString: String, isFavorite: Bool = false, date: Date = Date(), folderId: Int? = nil) {
26-
self.init(id: id, imageURL: URL(string: imageURLString), isFavorite: isFavorite, date: date, folderId: folderId)
27-
}
27+
init(id: Int, imageURLString: String, isFavorite: Bool = false, date: Date = Date(), folderId: Int? = nil, memo: String = "") {
28+
self.init(id: id, imageURL: URL(string: imageURLString), isFavorite: isFavorite, date: date, folderId: folderId, memo: memo)
29+
}
2830
}

0 commit comments

Comments
 (0)