From 83fdfb99529da39d487fa05e367b9adeb205c32f Mon Sep 17 00:00:00 2001 From: HanGyeongjun <030212hgjun@gmail.com> Date: Mon, 1 Apr 2024 17:19:59 +0900 Subject: [PATCH] [Feat] #516 - Create writePostView and photo import function - writePostView in Community tab - photo import (5 limit) - view custom in progress --- .../HappyAnding.xcodeproj/project.pbxproj | 6 +- .../CharcoalGray.colorset/Contents.json | 38 +++++++++++ .../Extensions/View/View+Shape.swift | 8 +++ HappyAnding/HappyAnding/Info.plist | 2 + .../Views/CommunityViews/CommunityView.swift | 68 ++++++++++++++++++- .../Views/CommunityViews/PhotoPicker.swift | 56 +++++++++++++++ .../Views/TabView/ShortcutTabView.swift | 2 +- 7 files changed, 177 insertions(+), 3 deletions(-) create mode 100644 HappyAnding/HappyAnding/Assets.xcassets/Colors/CharcoalGray.colorset/Contents.json create mode 100644 HappyAnding/HappyAnding/Views/CommunityViews/PhotoPicker.swift diff --git a/HappyAnding/HappyAnding.xcodeproj/project.pbxproj b/HappyAnding/HappyAnding.xcodeproj/project.pbxproj index b0bd1e27..f7e66d5d 100644 --- a/HappyAnding/HappyAnding.xcodeproj/project.pbxproj +++ b/HappyAnding/HappyAnding.xcodeproj/project.pbxproj @@ -109,6 +109,7 @@ A397D89E2BB81F9C0047A03D /* FirebaseMessaging in Frameworks */ = {isa = PBXBuildFile; productRef = A397D89D2BB81F9C0047A03D /* FirebaseMessaging */; }; A397D89F2BB821220047A03D /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4D5889E72AA36A52000C4849 /* AppDelegate.swift */; }; A397D8A32BB8219F0047A03D /* CommunityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A397D8A22BB8219F0047A03D /* CommunityView.swift */; }; + A397D8A52BB854560047A03D /* PhotoPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = A397D8A42BB854560047A03D /* PhotoPicker.swift */; }; A3A6AD1E292763E2004C49DC /* ShareExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = A3A6AD14292763E2004C49DC /* ShareExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; A3C404D62A23D0E800C3BA75 /* AboutUpdateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3C404D52A23D0E800C3BA75 /* AboutUpdateView.swift */; }; A3C5576C292BE084003907DC /* ShareExtensionWriteShortcutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3C5576B292BE084003907DC /* ShareExtensionWriteShortcutView.swift */; }; @@ -295,6 +296,7 @@ A38F3B1E2AE62E8D0036FCAC /* SuggestionFormView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SuggestionFormView.swift; sourceTree = ""; }; A39504862AD46B9B0019895E /* HapticManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HapticManager.swift; sourceTree = ""; }; A397D8A22BB8219F0047A03D /* CommunityView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommunityView.swift; sourceTree = ""; }; + A397D8A42BB854560047A03D /* PhotoPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoPicker.swift; sourceTree = ""; }; A3A6AD14292763E2004C49DC /* ShareExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = ShareExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; A3A6AD1B292763E2004C49DC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; A3A6AD232927BA06004C49DC /* ShareExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = ShareExtension.entitlements; sourceTree = ""; }; @@ -538,11 +540,11 @@ 87E99C9828FFF1D2009B691F /* Views */ = { isa = PBXGroup; children = ( - A397D8A12BB8217B0047A03D /* CommunityViews */, 87E99C6D28F94EA6009B691F /* HappyAndingApp.swift */, A04ACB0229027F4F004A85A6 /* TabView */, 87E99CC52901457B009B691F /* Components */, 87E99C9B28FFF1F4009B691F /* ExploreShortcutViews */, + A397D8A12BB8217B0047A03D /* CommunityViews */, 87E99C9728FFF1C0009B691F /* WriteShortcutViews */, 87E99C9A28FFF1E9009B691F /* ReadShortcutViews */, 87E99C9C28FFF1FE009B691F /* ExploreCurationViews */, @@ -732,6 +734,7 @@ isa = PBXGroup; children = ( A397D8A22BB8219F0047A03D /* CommunityView.swift */, + A397D8A42BB854560047A03D /* PhotoPicker.swift */, ); path = CommunityViews; sourceTree = ""; @@ -1001,6 +1004,7 @@ F96D45B72980301F000C2441 /* SubtitleTextView.swift in Sources */, A323D3CA2AEE870700DDA716 /* SuggestionForm.swift in Sources */, 4DF15D752A4ECE1F0014F854 /* ListCategoryShortcutViewModel.swift in Sources */, + A397D8A52BB854560047A03D /* PhotoPicker.swift in Sources */, 87E99CDB29042CCA009B691F /* Category.swift in Sources */, 876B4F6F299E3D91009672D9 /* NavigationRouter.swift in Sources */, A04ACB062903D0B2004A85A6 /* MyShortcutCardView.swift in Sources */, diff --git a/HappyAnding/HappyAnding/Assets.xcassets/Colors/CharcoalGray.colorset/Contents.json b/HappyAnding/HappyAnding/Assets.xcassets/Colors/CharcoalGray.colorset/Contents.json new file mode 100644 index 00000000..f592100b --- /dev/null +++ b/HappyAnding/HappyAnding/Assets.xcassets/Colors/CharcoalGray.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x40", + "green" : "0x40", + "red" : "0x40" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x40", + "green" : "0x40", + "red" : "0x40" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/HappyAnding/HappyAnding/Extensions/View/View+Shape.swift b/HappyAnding/HappyAnding/Extensions/View/View+Shape.swift index 52bc320d..a7e9e735 100644 --- a/HappyAnding/HappyAnding/Extensions/View/View+Shape.swift +++ b/HappyAnding/HappyAnding/Extensions/View/View+Shape.swift @@ -14,6 +14,14 @@ extension View { clipShape( RoundedCorner(radius: radius, corners: corners) ) } + func roundedBorder(cornerRadius: CGFloat, color: Color = Color("CharcoalGray"), opacity: Double = 0.04, lineWidth: CGFloat = 2) -> some View { + self.overlay( + RoundedRectangle(cornerRadius: cornerRadius) + .stroke(color.opacity(opacity), lineWidth: lineWidth) + .blendMode(.multiply) + ) + .clipShape(RoundedRectangle(cornerRadius: cornerRadius)) + } } diff --git a/HappyAnding/HappyAnding/Info.plist b/HappyAnding/HappyAnding/Info.plist index aa2b2c93..35f35218 100644 --- a/HappyAnding/HappyAnding/Info.plist +++ b/HappyAnding/HappyAnding/Info.plist @@ -2,6 +2,8 @@ + + CFBundleURLTypes diff --git a/HappyAnding/HappyAnding/Views/CommunityViews/CommunityView.swift b/HappyAnding/HappyAnding/Views/CommunityViews/CommunityView.swift index 6c46f4e3..e37c8cd4 100644 --- a/HappyAnding/HappyAnding/Views/CommunityViews/CommunityView.swift +++ b/HappyAnding/HappyAnding/Views/CommunityViews/CommunityView.swift @@ -8,8 +8,74 @@ import SwiftUI struct CommunityView: View { + + @State var postTite: String = "" + @State var postConetent: String = "" + + @State private var selectedImages: [UIImage] = [] + @State private var showingImagePicker = false + var body: some View { - Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/) + ScrollView { + writePostView() + } + .padding(.horizontal, 16) + .background(Color.shortcutsZipBackground) + .refreshable { + //Add code + } + } + + @ViewBuilder + private func writePostView() -> some View { + HStack(alignment: .top, spacing: 8) { + Image(systemName: "square.2.layers.3d.bottom.filled") + VStack(alignment: .leading, spacing: 4) { + TextField("hello", text: $postTite) + TextEditor(text: $postConetent) + ScrollView(.horizontal, showsIndicators: false) { + HStack(spacing: 4) { + ForEach(selectedImages, id: \.self) { image in + Image(uiImage: image) + .resizable() + .scaledToFill() + .frame(width: 64, height: 64) + .roundedBorder(cornerRadius: 12) + } + } + } + Divider() + HStack(alignment: .center, spacing: 8) { + Button { + showingImagePicker = true + } label: { + Image(systemName: "photo.badge.plus") + } + + Button { + //code + } label: { + Image(systemName: "square.2.layers.3d.bottom.filled") + } + + Spacer() + + Button { + //code + } label: { + Image(systemName: "plus.circle.fill") + .foregroundStyle(Color.shortcutsZipPrimary) + } + } + } + } + .padding(.all, 8) + .background(Color.white) + .cornerRadius(16, corners: .allCorners) + .sheet(isPresented: $showingImagePicker) { + PhotoPicker(selectedImages: $selectedImages) + .ignoresSafeArea() + } } } diff --git a/HappyAnding/HappyAnding/Views/CommunityViews/PhotoPicker.swift b/HappyAnding/HappyAnding/Views/CommunityViews/PhotoPicker.swift new file mode 100644 index 00000000..aadcc4ec --- /dev/null +++ b/HappyAnding/HappyAnding/Views/CommunityViews/PhotoPicker.swift @@ -0,0 +1,56 @@ +// +// PhotoPicker.swift +// HappyAnding +// +// Created by HanGyeongjun on 3/30/24. +// + +import SwiftUI +import PhotosUI + +struct PhotoPicker: UIViewControllerRepresentable { + @Binding var selectedImages: [UIImage] + @Environment(\.presentationMode) var presentationMode + + func makeUIViewController(context: Context) -> PHPickerViewController { + var config = PHPickerConfiguration(photoLibrary: .shared()) + config.selectionLimit = 5 + config.filter = .images + let picker = PHPickerViewController(configuration: config) + picker.delegate = context.coordinator + return picker + } + + func updateUIViewController(_ uiViewController: PHPickerViewController, context: Context) {} + + func makeCoordinator() -> Coordinator { + Coordinator(self) + } + + class Coordinator: NSObject, PHPickerViewControllerDelegate { + var parent: PhotoPicker + + init(_ parent: PhotoPicker) { + self.parent = parent + } + + //이미지 배열 생성. 최대 5개, 앞쪽에 추가 + func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) { + picker.dismiss(animated: true) + + for result in results.reversed() { + guard result.itemProvider.canLoadObject(ofClass: UIImage.self) else { continue } + result.itemProvider.loadObject(ofClass: UIImage.self) { (image, error) in + DispatchQueue.main.async { + if let image = image as? UIImage { + self.parent.selectedImages.insert(image, at: 0) + if self.parent.selectedImages.count > 5 { + self.parent.selectedImages.removeLast() + } + } + } + } + } + } + } +} diff --git a/HappyAnding/HappyAnding/Views/TabView/ShortcutTabView.swift b/HappyAnding/HappyAnding/Views/TabView/ShortcutTabView.swift index 1b728495..f1435167 100644 --- a/HappyAnding/HappyAnding/Views/TabView/ShortcutTabView.swift +++ b/HappyAnding/HappyAnding/Views/TabView/ShortcutTabView.swift @@ -118,7 +118,7 @@ struct ShortcutTabView: View { @ViewBuilder private func secondTab() -> some View { - CommunityView() + CommunityView(postTite: "") .modifierNavigation() .navigationBarBackground ({ Color.shortcutsZipBackground }) .id(secondTabID)