feat: 커뮤니티 글쓰기/수정
- 이미지 gif 등록 기능 추가
This commit is contained in:
		@@ -6,7 +6,9 @@
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
import SwiftUI
 | 
			
		||||
import PhotosUI
 | 
			
		||||
import Kingfisher
 | 
			
		||||
import SDWebImageSwiftUI
 | 
			
		||||
 | 
			
		||||
struct CreatorCommunityModifyView: View {
 | 
			
		||||
    
 | 
			
		||||
@@ -14,7 +16,7 @@ struct CreatorCommunityModifyView: View {
 | 
			
		||||
    @StateObject var keyboardHandler = KeyboardHandler()
 | 
			
		||||
    @StateObject private var viewModel = CreatorCommunityModifyViewModel()
 | 
			
		||||
    
 | 
			
		||||
    @State private var isShowPhotoPicker = false
 | 
			
		||||
    @State private var selectedItem: PhotosPickerItem? = nil
 | 
			
		||||
    let onSuccess: () -> Void
 | 
			
		||||
    
 | 
			
		||||
    var body: some View {
 | 
			
		||||
@@ -26,56 +28,66 @@ struct CreatorCommunityModifyView: View {
 | 
			
		||||
                        
 | 
			
		||||
                        ScrollView(.vertical, showsIndicators: false) {
 | 
			
		||||
                            VStack(spacing: 0) {
 | 
			
		||||
                                VStack(spacing: 0) {
 | 
			
		||||
                                VStack(spacing: 13.3) {
 | 
			
		||||
                                    Text("이미지")
 | 
			
		||||
                                        .font(.custom(Font.bold.rawValue, size: 16.7))
 | 
			
		||||
                                        .foregroundColor(Color(hex: "eeeeee"))
 | 
			
		||||
                                        .frame(maxWidth: .infinity, alignment: .leading)
 | 
			
		||||
                                    
 | 
			
		||||
                                    ZStack {
 | 
			
		||||
                                        if let selectedImage = viewModel.postImage {
 | 
			
		||||
                                            Image(uiImage: selectedImage)
 | 
			
		||||
                                                .resizable()
 | 
			
		||||
                                                .scaledToFill()
 | 
			
		||||
                                                .frame(width: 107, height: 107)
 | 
			
		||||
                                                .background(Color(hex: "3e3358"))
 | 
			
		||||
                                                .cornerRadius(8)
 | 
			
		||||
                                                .clipped()
 | 
			
		||||
                                        } else if let postImageUrl = viewModel.postImageUrl {
 | 
			
		||||
                                            KFImage(URL(string: postImageUrl))
 | 
			
		||||
                                                .cancelOnDisappear(true)
 | 
			
		||||
                                                .downsampling(
 | 
			
		||||
                                                    size: CGSize(
 | 
			
		||||
                                                        width: 107,
 | 
			
		||||
                                                        height: 107
 | 
			
		||||
                                                    )
 | 
			
		||||
                                                )
 | 
			
		||||
                                                .resizable()
 | 
			
		||||
                                                .scaledToFill()
 | 
			
		||||
                                                .frame(width: 107, height: 107)
 | 
			
		||||
                                                .background(Color(hex: "3e3358"))
 | 
			
		||||
                                                .cornerRadius(8)
 | 
			
		||||
                                                .clipped()
 | 
			
		||||
                                        } else {
 | 
			
		||||
                                            Image("ic_logo2")
 | 
			
		||||
                                                .resizable()
 | 
			
		||||
                                                .scaledToFit()
 | 
			
		||||
                                                .padding(13.3)
 | 
			
		||||
                                                .frame(width: 107, height: 107)
 | 
			
		||||
                                                .background(Color(hex: "13181B"))
 | 
			
		||||
                                                .cornerRadius(8)
 | 
			
		||||
                                                .clipped()
 | 
			
		||||
                                    PhotosPicker(
 | 
			
		||||
                                        selection: $selectedItem,
 | 
			
		||||
                                        matching: .any(of: [.images]),
 | 
			
		||||
                                        photoLibrary: .shared()) {
 | 
			
		||||
                                            ZStack(alignment: .bottomTrailing) {
 | 
			
		||||
                                                if let selectedImage = viewModel.postImageData {
 | 
			
		||||
                                                    AnimatedImage(data: selectedImage)
 | 
			
		||||
                                                        .resizable()
 | 
			
		||||
                                                        .scaledToFill()
 | 
			
		||||
                                                        .frame(width: 300)
 | 
			
		||||
                                                        .cornerRadius(8)
 | 
			
		||||
                                                        .clipped()
 | 
			
		||||
                                                } else if let postImageUrl = viewModel.postImageUrl {
 | 
			
		||||
                                                    AnimatedImage(url: URL(string: postImageUrl))
 | 
			
		||||
                                                        .resizable()
 | 
			
		||||
                                                        .scaledToFill()
 | 
			
		||||
                                                        .frame(width: 300)
 | 
			
		||||
                                                        .cornerRadius(8)
 | 
			
		||||
                                                        .clipped()
 | 
			
		||||
                                                } else {
 | 
			
		||||
                                                    Image("ic_logo2")
 | 
			
		||||
                                                        .resizable()
 | 
			
		||||
                                                        .scaledToFit()
 | 
			
		||||
                                                        .padding(13.3)
 | 
			
		||||
                                                        .frame(width: 107, height: 107)
 | 
			
		||||
                                                        .background(Color.bg)
 | 
			
		||||
                                                        .cornerRadius(8)
 | 
			
		||||
                                                        .clipped()
 | 
			
		||||
                                                }
 | 
			
		||||
                                                
 | 
			
		||||
                                                Image("ic_camera")
 | 
			
		||||
                                                    .padding(10)
 | 
			
		||||
                                                    .background(Color.button)
 | 
			
		||||
                                                    .cornerRadius(30)
 | 
			
		||||
                                                    .offset(x: 15, y: 0)
 | 
			
		||||
                                            }
 | 
			
		||||
                                            .frame(alignment: .bottomTrailing)
 | 
			
		||||
                                        }
 | 
			
		||||
                                        .onChange(of: selectedItem) { newItem in
 | 
			
		||||
                                            Task {
 | 
			
		||||
                                                if let item = newItem {
 | 
			
		||||
                                                    do {
 | 
			
		||||
                                                        // ✅ 이미지 원본 Data 가져오기 (GIF 포함)
 | 
			
		||||
                                                        if let data = try await item.loadTransferable(type: Data.self) {
 | 
			
		||||
                                                            viewModel.postImageData = data
 | 
			
		||||
                                                        }
 | 
			
		||||
                                                    } catch {
 | 
			
		||||
                                                        viewModel.errorMessage = "이미지를 로드하지 못했습니다."
 | 
			
		||||
                                                        viewModel.isShowPopup = true
 | 
			
		||||
                                                        DEBUG_LOG("이미지 로드 실패: \(error)")
 | 
			
		||||
                                                    }
 | 
			
		||||
                                                }
 | 
			
		||||
                                            }
 | 
			
		||||
                                        }
 | 
			
		||||
                                        
 | 
			
		||||
                                        Image("ic_camera")
 | 
			
		||||
                                            .padding(10)
 | 
			
		||||
                                            .background(Color(hex: "3BB9F1"))
 | 
			
		||||
                                            .cornerRadius(30)
 | 
			
		||||
                                            .offset(x: 50, y: 36)
 | 
			
		||||
                                    }
 | 
			
		||||
                                    .frame(alignment: .bottomTrailing)
 | 
			
		||||
                                    .contentShape(Rectangle())
 | 
			
		||||
                                    .onTapGesture { isShowPhotoPicker = true }
 | 
			
		||||
                                    
 | 
			
		||||
                                    HStack(alignment: .top, spacing: 0) {
 | 
			
		||||
                                        Text("※ ")
 | 
			
		||||
@@ -230,14 +242,6 @@ struct CreatorCommunityModifyView: View {
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    
 | 
			
		||||
                    if isShowPhotoPicker {
 | 
			
		||||
                        ImagePicker(
 | 
			
		||||
                            isShowing: $isShowPhotoPicker,
 | 
			
		||||
                            selectedImage: $viewModel.postImage,
 | 
			
		||||
                            sourceType: .photoLibrary
 | 
			
		||||
                        )
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                .onTapGesture { hideKeyboard() }
 | 
			
		||||
                .edgesIgnoringSafeArea(.bottom)
 | 
			
		||||
@@ -249,7 +253,7 @@ struct CreatorCommunityModifyView: View {
 | 
			
		||||
                                .padding(.vertical, 13.3)
 | 
			
		||||
                                .frame(width: screenSize().width - 66.7, alignment: .center)
 | 
			
		||||
                                .font(.custom(Font.medium.rawValue, size: 12))
 | 
			
		||||
                                .background(Color(hex: "9970ff"))
 | 
			
		||||
                                .background(Color.button)
 | 
			
		||||
                                .foregroundColor(Color.white)
 | 
			
		||||
                                .multilineTextAlignment(.center)
 | 
			
		||||
                                .cornerRadius(20)
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,7 @@ final class CreatorCommunityModifyViewModel: ObservableObject {
 | 
			
		||||
    @Published var content = ""
 | 
			
		||||
    @Published var isAdult = false
 | 
			
		||||
    @Published var isAvailableComment = true
 | 
			
		||||
    @Published var postImage: UIImage? = nil
 | 
			
		||||
    @Published var postImageData: Data? = nil
 | 
			
		||||
    @Published var postImageUrl: String? = nil
 | 
			
		||||
    @Published private(set) var communityPost: GetCommunityPostListResponse?
 | 
			
		||||
    
 | 
			
		||||
@@ -95,13 +95,14 @@ final class CreatorCommunityModifyViewModel: ObservableObject {
 | 
			
		||||
            let jsonData = try? encoder.encode(request)
 | 
			
		||||
            
 | 
			
		||||
            if let jsonData = jsonData {
 | 
			
		||||
                if let postImage = postImage, let imageData = postImage.jpegData(compressionQuality: 0.8) {
 | 
			
		||||
                if let postImageData = postImageData {
 | 
			
		||||
                    multipartData.append(
 | 
			
		||||
                        MultipartFormData(
 | 
			
		||||
                            provider: .data(imageData),
 | 
			
		||||
                            provider: .data(postImageData),
 | 
			
		||||
                            name: "postImage",
 | 
			
		||||
                            fileName: "\(UUID().uuidString)_\(Date().timeIntervalSince1970 * 1000).jpg",
 | 
			
		||||
                            mimeType: "image/*")
 | 
			
		||||
                            fileName: "\(UUID().uuidString)_\(Date().timeIntervalSince1970 * 1000)",
 | 
			
		||||
                            mimeType: "image/*"
 | 
			
		||||
                        )
 | 
			
		||||
                    )
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
 
 | 
			
		||||
@@ -6,15 +6,19 @@
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
import SwiftUI
 | 
			
		||||
import PhotosUI
 | 
			
		||||
import SDWebImageSwiftUI
 | 
			
		||||
 | 
			
		||||
struct CreatorCommunityWriteView: View {
 | 
			
		||||
    
 | 
			
		||||
    @StateObject var keyboardHandler = KeyboardHandler()
 | 
			
		||||
    @StateObject private var viewModel = CreatorCommunityWriteViewModel()
 | 
			
		||||
    
 | 
			
		||||
    @State private var selectedItem: PhotosPickerItem? = nil
 | 
			
		||||
    
 | 
			
		||||
    @State private var isShowRecordingVoiceView = false
 | 
			
		||||
    @State private var isShowPhotoPicker = false
 | 
			
		||||
    @State private var fileName: String = "녹음"
 | 
			
		||||
    
 | 
			
		||||
    let onSuccess: () -> Void
 | 
			
		||||
    
 | 
			
		||||
    var body: some View {
 | 
			
		||||
@@ -26,41 +30,59 @@ struct CreatorCommunityWriteView: View {
 | 
			
		||||
                        
 | 
			
		||||
                        ScrollView(.vertical, showsIndicators: false) {
 | 
			
		||||
                            VStack(spacing: 0) {
 | 
			
		||||
                                VStack(spacing: 0) {
 | 
			
		||||
                                VStack(spacing: 13.3) {
 | 
			
		||||
                                    Text("이미지")
 | 
			
		||||
                                        .font(.custom(Font.bold.rawValue, size: 16.7))
 | 
			
		||||
                                        .foregroundColor(Color.grayee)
 | 
			
		||||
                                        .frame(maxWidth: .infinity, alignment: .leading)
 | 
			
		||||
                                    
 | 
			
		||||
                                    ZStack {
 | 
			
		||||
                                        if let selectedImage = viewModel.postImage {
 | 
			
		||||
                                            Image(uiImage: selectedImage)
 | 
			
		||||
                                                .resizable()
 | 
			
		||||
                                                .scaledToFill()
 | 
			
		||||
                                                .frame(width: 107, height: 107)
 | 
			
		||||
                                                .background(Color(hex: "3e3358"))
 | 
			
		||||
                                                .cornerRadius(8)
 | 
			
		||||
                                                .clipped()
 | 
			
		||||
                                        } else {
 | 
			
		||||
                                            Image("ic_logo2")
 | 
			
		||||
                                                .resizable()
 | 
			
		||||
                                                .scaledToFit()
 | 
			
		||||
                                                .padding(13.3)
 | 
			
		||||
                                                .frame(width: 107, height: 107)
 | 
			
		||||
                                                .background(Color.bg)
 | 
			
		||||
                                                .cornerRadius(8)
 | 
			
		||||
                                                .clipped()
 | 
			
		||||
                                    PhotosPicker(
 | 
			
		||||
                                        selection: $selectedItem,
 | 
			
		||||
                                        matching: .any(of: [.images]),
 | 
			
		||||
                                        photoLibrary: .shared()) {
 | 
			
		||||
                                            ZStack(alignment: .bottomTrailing) {
 | 
			
		||||
                                                if let selectedImage = viewModel.postImageData {
 | 
			
		||||
                                                    AnimatedImage(data: selectedImage)
 | 
			
		||||
                                                        .resizable()
 | 
			
		||||
                                                        .scaledToFill()
 | 
			
		||||
                                                        .frame(width: 300)
 | 
			
		||||
                                                        .cornerRadius(8)
 | 
			
		||||
                                                        .clipped()
 | 
			
		||||
                                                } else {
 | 
			
		||||
                                                    Image("ic_logo2")
 | 
			
		||||
                                                        .resizable()
 | 
			
		||||
                                                        .scaledToFit()
 | 
			
		||||
                                                        .padding(13.3)
 | 
			
		||||
                                                        .frame(width: 107, height: 107)
 | 
			
		||||
                                                        .background(Color.bg)
 | 
			
		||||
                                                        .cornerRadius(8)
 | 
			
		||||
                                                        .clipped()
 | 
			
		||||
                                                }
 | 
			
		||||
                                                
 | 
			
		||||
                                                Image("ic_camera")
 | 
			
		||||
                                                    .padding(10)
 | 
			
		||||
                                                    .background(Color.button)
 | 
			
		||||
                                                    .cornerRadius(30)
 | 
			
		||||
                                                    .offset(x: 15, y: 0)
 | 
			
		||||
                                            }
 | 
			
		||||
                                            .frame(alignment: .bottomTrailing)
 | 
			
		||||
                                        }
 | 
			
		||||
                                        .onChange(of: selectedItem) { newItem in
 | 
			
		||||
                                            Task {
 | 
			
		||||
                                                if let item = newItem {
 | 
			
		||||
                                                    do {
 | 
			
		||||
                                                        // ✅ 이미지 원본 Data 가져오기 (GIF 포함)
 | 
			
		||||
                                                        if let data = try await item.loadTransferable(type: Data.self) {
 | 
			
		||||
                                                            viewModel.postImageData = data
 | 
			
		||||
                                                        }
 | 
			
		||||
                                                    } catch {
 | 
			
		||||
                                                        viewModel.errorMessage = "이미지를 로드하지 못했습니다."
 | 
			
		||||
                                                        viewModel.isShowPopup = true
 | 
			
		||||
                                                        DEBUG_LOG("이미지 로드 실패: \(error)")
 | 
			
		||||
                                                    }
 | 
			
		||||
                                                }
 | 
			
		||||
                                            }
 | 
			
		||||
                                        }
 | 
			
		||||
                                        
 | 
			
		||||
                                        Image("ic_camera")
 | 
			
		||||
                                            .padding(10)
 | 
			
		||||
                                            .background(Color.button)
 | 
			
		||||
                                            .cornerRadius(30)
 | 
			
		||||
                                            .offset(x: 50, y: 36)
 | 
			
		||||
                                    }
 | 
			
		||||
                                    .frame(alignment: .bottomTrailing)
 | 
			
		||||
                                    .contentShape(Rectangle())
 | 
			
		||||
                                    .onTapGesture { isShowPhotoPicker = true }
 | 
			
		||||
                                    
 | 
			
		||||
                                    HStack(alignment: .top, spacing: 0) {
 | 
			
		||||
                                        Text("※ ")
 | 
			
		||||
@@ -72,9 +94,9 @@ struct CreatorCommunityWriteView: View {
 | 
			
		||||
                                            .foregroundColor(Color.gray77)
 | 
			
		||||
                                    }
 | 
			
		||||
                                    .frame(maxWidth: .infinity)
 | 
			
		||||
                                    .padding(.top, 24)
 | 
			
		||||
                                    .padding(.top, 16)
 | 
			
		||||
                                    
 | 
			
		||||
                                    if let _ = viewModel.postImage {
 | 
			
		||||
                                    if let _ = viewModel.postImageData {
 | 
			
		||||
                                        VStack(spacing: 13.3) {
 | 
			
		||||
                                            HStack(spacing: 0) {
 | 
			
		||||
                                                Text("오디오 녹음")
 | 
			
		||||
@@ -190,7 +212,7 @@ struct CreatorCommunityWriteView: View {
 | 
			
		||||
                                        .padding(.top, 26.7)
 | 
			
		||||
                                    }
 | 
			
		||||
                                    
 | 
			
		||||
                                    if let _ = viewModel.postImage {
 | 
			
		||||
                                    if let _ = viewModel.postImageData {
 | 
			
		||||
                                        VStack(spacing: 13.3) {
 | 
			
		||||
                                            Text("가격 설정")
 | 
			
		||||
                                                .font(.custom(Font.bold.rawValue, size: 16.7))
 | 
			
		||||
@@ -308,14 +330,6 @@ struct CreatorCommunityWriteView: View {
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    
 | 
			
		||||
                    if isShowPhotoPicker {
 | 
			
		||||
                        ImagePicker(
 | 
			
		||||
                            isShowing: $isShowPhotoPicker,
 | 
			
		||||
                            selectedImage: $viewModel.postImage,
 | 
			
		||||
                            sourceType: .photoLibrary
 | 
			
		||||
                        )
 | 
			
		||||
                    }
 | 
			
		||||
                    
 | 
			
		||||
                    if isShowRecordingVoiceView {
 | 
			
		||||
                        CreatorCommunityRecordingVoiceView(
 | 
			
		||||
                            isShowing: $isShowRecordingVoiceView,
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,7 @@ final class CreatorCommunityWriteViewModel: ObservableObject {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    @Published var isAvailableComment = true
 | 
			
		||||
    @Published var postImage: UIImage? = nil
 | 
			
		||||
    @Published var postImageData: Data? = nil
 | 
			
		||||
    
 | 
			
		||||
    @Published var priceString = "0" {
 | 
			
		||||
        didSet {
 | 
			
		||||
@@ -60,12 +60,12 @@ final class CreatorCommunityWriteViewModel: ObservableObject {
 | 
			
		||||
            let jsonData = try? encoder.encode(request)
 | 
			
		||||
            
 | 
			
		||||
            if let jsonData = jsonData {
 | 
			
		||||
                if let postImage = postImage, let imageData = postImage.jpegData(compressionQuality: 0.8) {
 | 
			
		||||
                if let postImageData = postImageData {
 | 
			
		||||
                    multipartData.append(
 | 
			
		||||
                        MultipartFormData(
 | 
			
		||||
                            provider: .data(imageData),
 | 
			
		||||
                            provider: .data(postImageData),
 | 
			
		||||
                            name: "postImage",
 | 
			
		||||
                            fileName: "\(UUID().uuidString)_\(Date().timeIntervalSince1970 * 1000).jpg",
 | 
			
		||||
                            fileName: "\(UUID().uuidString)_\(Date().timeIntervalSince1970 * 1000)",
 | 
			
		||||
                            mimeType: "image/*"
 | 
			
		||||
                        )
 | 
			
		||||
                    )
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user