feat(diary): make the mood area a large square tile

'오늘 기분'을 카드의 주인공인 200pt 정사각형 타일로 재배치 — 사진은 꽉
채우고(이모지는 우하단 배지), 이모지만 있으면 크게 가운데, 비어 있으면
'탭해서 남기기' 플레이스홀더. 오른쪽에 이모지/사진/지우기 캡슐 버튼 열.
새 문자열 en/ja 번역 추가.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7
This commit is contained in:
songyc macbook 2026-07-13 15:08:08 +09:00
parent daf4fc3157
commit 8d4d20fc76
2 changed files with 159 additions and 56 deletions

View File

@ -4049,6 +4049,22 @@
}
}
},
"사진 선택": {
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Choose Photo"
}
},
"ja": {
"stringUnit": {
"state": "translated",
"value": "写真を選択"
}
}
}
},
"사진 앨범에 저장했어요.": {
"localizations": {
"en": {
@ -5604,7 +5620,40 @@
}
}
},
"이모지 선택": {
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Choose Emoji"
}
},
"ja": {
"stringUnit": {
"state": "translated",
"value": "絵文字を選択"
}
}
}
},
"이모지나 사진으로\n오늘의 기분을 남겨 보세요": {
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Capture todays mood\nwith an emoji or a photo"
}
},
"ja": {
"stringUnit": {
"state": "translated",
"value": "絵文字や写真で\n今日の気分を残しましょう"
}
}
}
},
"이모지나 사진으로 오늘의 기분을 남겨 보세요": {
"extractionState": "stale",
"localizations": {
"en": {
"stringUnit": {
@ -6597,6 +6646,22 @@
}
}
},
"지우기": {
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Clear"
}
},
"ja": {
"stringUnit": {
"state": "translated",
"value": "消去"
}
}
}
},
"지정된 꼬리표 없음": {
"localizations": {
"en": {
@ -7029,6 +7094,22 @@
}
}
},
"탭해서 남기기": {
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Tap to add"
}
},
"ja": {
"stringUnit": {
"state": "translated",
"value": "タップして記録"
}
}
}
},
"테마": {
"localizations": {
"en": {

View File

@ -992,75 +992,54 @@ private struct DiaryMoodCard: View {
@State private var showingEmojiPicker = false
@State private var photoSelection: PhotosPickerItem?
///
private let tileSize: CGFloat = 200
static let emojiChoices = [
"😀", "🙂", "😌", "🥰", "🥳", "🤗", "😴", "😐",
"😔", "😢", "😡", "😤", "🤒", "🤯", "😱", "🙃",
]
var body: some View {
HStack(spacing: 14) {
VStack(alignment: .leading, spacing: 3) {
HStack(alignment: .top, spacing: 16) {
moodTile
VStack(alignment: .leading, spacing: 6) {
Text("오늘 기분")
.font(.subheadline.weight(.semibold))
Text("이모지나 사진으로 오늘의 기분을 남겨 보세요")
.font(.caption2)
.font(.headline)
Text("이모지나 사진으로\n오늘의 기분을 남겨 보세요")
.font(.caption)
.foregroundStyle(.secondary)
}
Spacer()
//
Button {
showingEmojiPicker = true
} label: {
Group {
if entry.moodEmoji.isEmpty {
Image(systemName: "face.smiling")
.font(.system(size: 26))
.foregroundStyle(.secondary)
} else {
Text(entry.moodEmoji)
.font(.system(size: 34))
.fixedSize(horizontal: false, vertical: true)
Spacer(minLength: 8)
VStack(alignment: .leading, spacing: 8) {
Button {
showingEmojiPicker = true
} label: {
Label("이모지 선택", systemImage: "face.smiling")
}
}
.frame(width: 60, height: 60)
.background(AppTheme.background, in: RoundedRectangle(cornerRadius: 14, style: .continuous))
}
.buttonStyle(.plain)
.popover(isPresented: $showingEmojiPicker) {
emojiPicker
}
//
PhotosPicker(selection: $photoSelection, matching: .images) {
Group {
if let data = entry.moodImageData, let image = UIImage(data: data) {
Image(uiImage: image)
.resizable()
.scaledToFill()
} else {
Image(systemName: "photo.badge.plus")
.font(.system(size: 24))
.foregroundStyle(.secondary)
.popover(isPresented: $showingEmojiPicker) {
emojiPicker
}
}
.frame(width: 60, height: 60)
.background(AppTheme.background)
.clipShape(RoundedRectangle(cornerRadius: 14, style: .continuous))
}
.buttonStyle(.plain)
if !entry.moodEmoji.isEmpty || entry.moodImageData != nil {
Button {
entry.moodEmoji = ""
entry.moodImageData = nil
touch()
} label: {
Image(systemName: "xmark.circle.fill")
.font(.title3)
PhotosPicker(selection: $photoSelection, matching: .images) {
Label("사진 선택", systemImage: "photo.badge.plus")
}
if !entry.moodEmoji.isEmpty || entry.moodImageData != nil {
Button {
entry.moodEmoji = ""
entry.moodImageData = nil
touch()
} label: {
Label("지우기", systemImage: "xmark.circle")
}
.foregroundStyle(.secondary)
}
}
.buttonStyle(.plain)
.font(.footnote)
.buttonStyle(.bordered)
.buttonBorderShape(.capsule)
.tint(AppTheme.green)
}
.frame(maxWidth: .infinity, minHeight: tileSize, alignment: .leading)
}
.padding(14)
.background(AppTheme.surface, in: RoundedRectangle(cornerRadius: 16, style: .continuous))
@ -1078,6 +1057,49 @@ private struct DiaryMoodCard: View {
}
}
/// : ( ),
/// , .
private var moodTile: some View {
Button {
showingEmojiPicker = true
} label: {
ZStack {
RoundedRectangle(cornerRadius: 20, style: .continuous)
.fill(AppTheme.background)
if let data = entry.moodImageData, let image = UIImage(data: data) {
Image(uiImage: image)
.resizable()
.scaledToFill()
.frame(width: tileSize, height: tileSize)
.clipShape(RoundedRectangle(cornerRadius: 20, style: .continuous))
if !entry.moodEmoji.isEmpty {
Text(entry.moodEmoji)
.font(.system(size: 40))
.padding(7)
.background(.thinMaterial, in: Circle())
.frame(maxWidth: .infinity, maxHeight: .infinity,
alignment: .bottomTrailing)
.padding(10)
}
} else if !entry.moodEmoji.isEmpty {
Text(entry.moodEmoji)
.font(.system(size: 110))
} else {
VStack(spacing: 10) {
Image(systemName: "face.smiling")
.font(.system(size: 44))
Text("탭해서 남기기")
.font(.caption)
}
.foregroundStyle(.tertiary)
}
}
.frame(width: tileSize, height: tileSize)
.contentShape(RoundedRectangle(cornerRadius: 20, style: .continuous))
}
.buttonStyle(.plain)
}
private var emojiPicker: some View {
LazyVGrid(columns: Array(repeating: GridItem(.fixed(46)), count: 4), spacing: 8) {
ForEach(Self.emojiChoices, id: \.self) { emoji in