Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
2081b17
[Feat] #202 - Data extension
OneTen19 Apr 2, 2026
97c1bd8
[Feat] #202 - AlbumSelectionFeature
OneTen19 Apr 2, 2026
933f914
[Feat] #202 - AlbumSelectionView
OneTen19 Apr 2, 2026
6272f28
[Feat] #202 - PhotoDetail 뷰에서 앨범 선택 뷰 연결
OneTen19 Apr 2, 2026
81a78ab
[Chore] #202 - 이미지 변환기능 릴리즈 Scheme에서는 숨김 처리
OneTen19 Apr 2, 2026
745ca25
[Feat] #202 - ArchiveImageFooter 상세화면, 선택화면 분기 추가
OneTen19 Apr 2, 2026
8ceb20a
[Chore] #202 - 변경된 ArchiveImageFooter 적용
OneTen19 Apr 2, 2026
3a092c4
[Style] #202 - 앨범으로 이동&복제 플로우 UI 구현
OneTen19 Apr 2, 2026
eb3c60b
[Feat] #202 - 앨범 삭제 버튼 추가
OneTen19 Apr 2, 2026
82b2b85
[Chore] #202 - 사진 가져오기 버튼 추가
OneTen19 Apr 2, 2026
72722a6
[Feat] #202 - 사진 불러오기 기능 구현
OneTen19 Apr 2, 2026
1b7c581
[Feat] #202 - 업로드된 사진들 보여주는 시트 무한스크롤 구현
OneTen19 Apr 2, 2026
e6abf7e
[Feat] #202 - 그라데이션 추가 및 앨범 변경 시 선택된 사진 삭제
OneTen19 Apr 2, 2026
f35b953
[Chore] #202- 사진 가져오기 시트 테두리 둥글기 수정
OneTen19 Apr 2, 2026
a0cefe0
[Feat] #202 - 앨범 선택 시 자연스러운 애니메이션 적용
OneTen19 Apr 2, 2026
b9646dc
[Feat] #202 - 전반적으로 자연스러운 애니메이션 적용
OneTen19 Apr 2, 2026
b5383b3
[Feat] #202 - 인스타그램 스토리 공유 기능 구현
OneTen19 Apr 2, 2026
ac403a6
Merge remote-tracking branch 'refs/remotes/origin/develop'
OneTen19 Apr 3, 2026
07195f3
[Chore] #202 - 어색한 로딩메세지 수정
OneTen19 Apr 12, 2026
569524b
[Chore] #202 - DateFormatters 통합
OneTen19 Apr 12, 2026
fe31e34
[Chore] #202 - imageURL들을 꺼내오는 작업을 백그라운드 스레드 과정에 포함시켜 메인스레드의 부담 완화
OneTen19 Apr 12, 2026
fc3af95
[Chore] #202 - 불필요한 NavigationStack 래핑 제거
OneTen19 Apr 12, 2026
4a5b491
[Feat] #202 - 현재 폴더 선택 불가 및 복제시 다중 폴더 선택 가능하게 수정
OneTen19 Apr 12, 2026
e13f6b2
[Feat] #202 - 이동과 복제와 관련된 작업 하위 리듀서들로 캡슐화
OneTen19 Apr 12, 2026
c47c161
[Chore] #202 - 모든 사진 보기에서는 ArchiveImageFooter에 사진 이동 숨기기
OneTen19 Apr 12, 2026
199e20a
[Chore] #202 - PhotoSelectionPurpose 레이어 변경
OneTen19 Apr 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//
// PhotoSelectionPurpose.swift
// Neki-iOS
//
// Created by OneTen on 4/13/26.
//

import Foundation

public enum PhotoSelectionPurpose {
case duplicate
case move
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,55 +7,140 @@

import SwiftUI

public enum ArchiveFooterStyle {
case detail // 사진 상세 화면 (즐겨찾기, 메모 아이콘)
case selection // 사진 선택 화면 (다운로드, 복제, 이동, 삭제 + 텍스트)
}

struct ArchiveImageFooter: View {

// MARK: - Properties

/// 버튼 활성화 여부 (선택 모드에서는 선택된 아이템 유무, 상세 모드에서는 항상 true)
let isEnabled: Bool
let style: ArchiveFooterStyle

/// 즐겨찾기 상태 (nil이면 버튼 숨김)
/// 버튼 활성화 여부
let isEnabled: Bool
/// 즐겨찾기 상태 (상세 모드 전용)
let isFavorite: Bool?

// 아이콘 액션
let onDownload: () -> Void
let onDelete: () -> Void
let onFavorite: (() -> Void)?
let onTapMemo: (() -> Void)?
let onDuplicate: (() -> Void)?
let onMove: (() -> Void)?

// MARK: - Init

public init(
style: ArchiveFooterStyle = .detail,
isEnabled: Bool = true,
isFavorite: Bool? = nil,
onDownload: @escaping () -> Void,
onDelete: @escaping () -> Void,
onFavorite: (() -> Void)? = nil,
onTapMemo: (() -> Void)? = nil
onTapMemo: (() -> Void)? = nil,
onDuplicate: (() -> Void)? = nil,
onMove: (() -> Void)? = nil
) {
self.style = style
self.isEnabled = isEnabled
self.isFavorite = isFavorite
self.onDownload = onDownload
self.onDelete = onDelete
self.onFavorite = onFavorite
self.onTapMemo = onTapMemo
self.onDuplicate = onDuplicate
self.onMove = onMove
}

// MARK: - Body

var body: some View {
if style == .selection {
selectionModeFooter
} else {
detailModeFooter
}
}
}

extension ArchiveImageFooter {
private var selectionModeFooter: some View {
HStack(alignment: .center, spacing: 0) {
selectionButton(
title: "다운로드",
icon: Image(isEnabled ? .iconDownloadFill : .iconDownload),
action: onDownload
)

if let onDuplicate = onDuplicate {
selectionButton(
title: "사진 복제",
icon: Image(isEnabled ? .iconDuplicateFill : .iconDuplicate),
action: onDuplicate
)
}

if let onMove = onMove {
selectionButton(
title: "사진 이동",
icon: Image(isEnabled ? .iconMoveFill : .iconMove),
action: onMove
)
}

selectionButton(
title: "삭제",
icon: Image(isEnabled ? .iconTrashFill : .iconTrash),
action: onDelete
)
}
.padding(.top, 8)
.padding(.bottom, 10)
.background(.white)
.overlay(
Rectangle()
.frame(height: 1)
.foregroundColor(.gray75),
alignment: .top
)
}

// 버튼 공통 뷰 빌더
@ViewBuilder
private func selectionButton(title: String, icon: Image, action: @escaping () -> Void) -> some View {
Button(action: action) {
VStack(spacing: 4) {
icon
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 28, height: 28)
.foregroundStyle(isEnabled ? .gray700 : .gray200)

Text(title)
.nekiFont(.body14Medium)
.foregroundStyle(isEnabled ? .gray700 : .gray400)

}
.frame(maxWidth: .infinity)
.contentShape(Rectangle())
}
.disabled(!isEnabled)
}

private var detailModeFooter: some View {
HStack(alignment: .center, spacing: 0) {
Button(action: onDownload) {
Image(isEnabled ? .iconDownloadFill : .iconDownload)
.renderingMode(.template)
.foregroundStyle(isEnabled ? .gray700 : .gray100)
.foregroundStyle(isEnabled ? .gray700 : .gray200)
}
.disabled(!isEnabled)

if let isFavorite = isFavorite, let onFavorite = onFavorite {
Button(action: onFavorite) {
Image(isFavorite ? .iconHeart28Fill : .iconHeart28Gray)
.renderingMode(.template)
.foregroundStyle(isFavorite ? .red : .gray700)
}
.padding(.leading, 16)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//
// Date+.swift
// Neki-iOS
//
// Created by OneTen on 4/2/26.
//

import Foundation

extension Date {
/// Date를 "yyyy.MM.dd" 형태의 문자열로 변환합니다.
func toDotFormatString() -> String {
return DateFormatters.dotFormat.string(from: self)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ extension String {
}
}

private struct DateFormatters {
struct DateFormatters {

// 1. 밀리초 + 타임존 (Standard InternetDateTime + Fractional)
static let iso8601Fractional: ISO8601DateFormatter = {
Expand Down Expand Up @@ -71,4 +71,11 @@ private struct DateFormatters {
]
return formatter
}()

static let dotFormat: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy.MM.dd"
formatter.locale = Locale(identifier: "ko_KR")
return formatter
}()
}
Loading