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,34 +28,29 @@ 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)
|
||||
PhotosPicker(
|
||||
selection: $selectedItem,
|
||||
matching: .any(of: [.images]),
|
||||
photoLibrary: .shared()) {
|
||||
ZStack(alignment: .bottomTrailing) {
|
||||
if let selectedImage = viewModel.postImageData {
|
||||
AnimatedImage(data: selectedImage)
|
||||
.resizable()
|
||||
.scaledToFill()
|
||||
.frame(width: 107, height: 107)
|
||||
.background(Color(hex: "3e3358"))
|
||||
.frame(width: 300)
|
||||
.cornerRadius(8)
|
||||
.clipped()
|
||||
} else if let postImageUrl = viewModel.postImageUrl {
|
||||
KFImage(URL(string: postImageUrl))
|
||||
.cancelOnDisappear(true)
|
||||
.downsampling(
|
||||
size: CGSize(
|
||||
width: 107,
|
||||
height: 107
|
||||
)
|
||||
)
|
||||
AnimatedImage(url: URL(string: postImageUrl))
|
||||
.resizable()
|
||||
.scaledToFill()
|
||||
.frame(width: 107, height: 107)
|
||||
.background(Color(hex: "3e3358"))
|
||||
.frame(width: 300)
|
||||
.cornerRadius(8)
|
||||
.clipped()
|
||||
} else {
|
||||
@@ -62,20 +59,35 @@ struct CreatorCommunityModifyView: View {
|
||||
.scaledToFit()
|
||||
.padding(13.3)
|
||||
.frame(width: 107, height: 107)
|
||||
.background(Color(hex: "13181B"))
|
||||
.background(Color.bg)
|
||||
.cornerRadius(8)
|
||||
.clipped()
|
||||
}
|
||||
|
||||
Image("ic_camera")
|
||||
.padding(10)
|
||||
.background(Color(hex: "3BB9F1"))
|
||||
.background(Color.button)
|
||||
.cornerRadius(30)
|
||||
.offset(x: 50, y: 36)
|
||||
.offset(x: 15, y: 0)
|
||||
}
|
||||
.frame(alignment: .bottomTrailing)
|
||||
.contentShape(Rectangle())
|
||||
.onTapGesture { isShowPhotoPicker = true }
|
||||
}
|
||||
.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)")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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,19 +30,22 @@ 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)
|
||||
PhotosPicker(
|
||||
selection: $selectedItem,
|
||||
matching: .any(of: [.images]),
|
||||
photoLibrary: .shared()) {
|
||||
ZStack(alignment: .bottomTrailing) {
|
||||
if let selectedImage = viewModel.postImageData {
|
||||
AnimatedImage(data: selectedImage)
|
||||
.resizable()
|
||||
.scaledToFill()
|
||||
.frame(width: 107, height: 107)
|
||||
.background(Color(hex: "3e3358"))
|
||||
.frame(width: 300)
|
||||
.cornerRadius(8)
|
||||
.clipped()
|
||||
} else {
|
||||
@@ -56,11 +63,26 @@ struct CreatorCommunityWriteView: View {
|
||||
.padding(10)
|
||||
.background(Color.button)
|
||||
.cornerRadius(30)
|
||||
.offset(x: 50, y: 36)
|
||||
.offset(x: 15, y: 0)
|
||||
}
|
||||
.frame(alignment: .bottomTrailing)
|
||||
.contentShape(Rectangle())
|
||||
.onTapGesture { isShowPhotoPicker = true }
|
||||
}
|
||||
.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)")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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