diff --git a/Sources/Photochk/Views/GroupDetailView.swift b/Sources/Photochk/Views/GroupDetailView.swift new file mode 100644 index 0000000..8cc89ee --- /dev/null +++ b/Sources/Photochk/Views/GroupDetailView.swift @@ -0,0 +1,57 @@ +import SwiftUI + +struct GroupDetailView: View { + @Bindable var model: ScanViewModel + let group: SimilarityGroup + + private let columns = [GridItem(.adaptive(minimum: 168, maximum: 168), spacing: 18, alignment: .top)] + + var body: some View { + ScrollView { + LazyVGrid(columns: columns, alignment: .leading, spacing: 20) { + ForEach(group.members) { member in + PhotoTileView( + member: member, + isRepresentative: member.id == group.representativeID, + isMarked: model.markedForDeletion.contains(member.id), + canMark: model.canMark(member.id, in: group), + onToggle: { model.toggleMark(member.id, in: group) } + ) + } + } + .padding(20) + } + .safeAreaInset(edge: .top) { header } + .navigationTitle(group.representative.fileName) + .navigationSubtitle("\(group.members.count) 枚") + } + + private var header: some View { + VStack(alignment: .leading, spacing: 4) { + HStack(spacing: 8) { + Text(group.kindText) + .font(.caption.weight(.semibold)) + .padding(.horizontal, 7) + .padding(.vertical, 2) + .background( + group.isAllExact ? Color.orange.opacity(0.22) : Color.accentColor.opacity(0.18), + in: Capsule() + ) + Text("\(group.members.count) 枚・合計 \(group.totalBytesText)") + Text("1枚残すと \(group.reclaimableBytesText) 削減") + .foregroundStyle(.secondary) + } + .font(.callout) + + Text(group.representative.url.deletingLastPathComponent().path) + .font(.caption) + .foregroundStyle(.tertiary) + .lineLimit(1) + .truncationMode(.head) + } + .frame(maxWidth: .infinity, alignment: .leading) + .padding(.horizontal, 20) + .padding(.vertical, 10) + .background(.bar) + } +}