From 7d9ce8ca99c103628647aedea96a01fe6e5bbbc3 Mon Sep 17 00:00:00 2001 From: jeonjimin Date: Sat, 20 Apr 2024 16:34:01 +0900 Subject: [PATCH] wip --- .../Extensions/String/String+Date.swift | 39 +- .../Extensions/View/View+Shape.swift | 10 + .../ReadShortcutViewModel.swift | 1 + .../Views/Components/ShortcutIcon.swift | 2 +- .../ReadShortcutViews/ReadShortcutView.swift | 892 +++++------------- 5 files changed, 280 insertions(+), 664 deletions(-) diff --git a/HappyAnding/HappyAnding/Extensions/String/String+Date.swift b/HappyAnding/HappyAnding/Extensions/String/String+Date.swift index 598bdc6c..3e12ed5a 100644 --- a/HappyAnding/HappyAnding/Extensions/String/String+Date.swift +++ b/HappyAnding/HappyAnding/Extensions/String/String+Date.swift @@ -37,17 +37,32 @@ extension String { func getPostDateFormat() -> String? { let inputFormatter = DateFormatter() - inputFormatter.dateFormat = "yyyyMMddHHmmss" - - if let date = inputFormatter.date(from: self) { - let outputFormatter = DateFormatter() - outputFormatter.locale = Locale(identifier: "ko_KR") - outputFormatter.dateFormat = "M월 d일 a h시 m분" - - let output = outputFormatter.string(from: date) - return output - } else { - return nil - } + inputFormatter.dateFormat = "yyyyMMddHHmmss" + + if let date = inputFormatter.date(from: self) { + let outputFormatter = DateFormatter() + outputFormatter.locale = Locale(identifier: "ko_KR") + outputFormatter.dateFormat = "M월 d일 a h시 m분" + + let output = outputFormatter.string(from: date) + return output + } else { + return nil + } + } + func getVersionDateFormat() -> String? { + let inputFormatter = DateFormatter() + inputFormatter.dateFormat = "yyyyMMddHHmmss" + + if let date = inputFormatter.date(from: self) { + let outputFormatter = DateFormatter() + outputFormatter.locale = Locale(identifier: "ko_KR") + outputFormatter.dateFormat = "yyyy년 M월 d일" + + let output = outputFormatter.string(from: date) + return output + } else { + return nil + } } } diff --git a/HappyAnding/HappyAnding/Extensions/View/View+Shape.swift b/HappyAnding/HappyAnding/Extensions/View/View+Shape.swift index 2c5a964b..e523ed04 100644 --- a/HappyAnding/HappyAnding/Extensions/View/View+Shape.swift +++ b/HappyAnding/HappyAnding/Extensions/View/View+Shape.swift @@ -30,6 +30,16 @@ extension View { ) .clipShape(RoundedRectangle(cornerRadius: cornerRadius)) } + + func roundedBackground() -> some View { + self + .font(.system(size: 14, weight: .regular)) + .foregroundStyle(SCZColor.CharcoalGray.opacity64) + .padding(.horizontal, 10) + .padding(.vertical, 8) + .background(SCZColor.CharcoalGray.opacity04) + .roundedBorder(cornerRadius: 16, color: Color.white.opacity(0.12), isNormalBlend: true) + } } diff --git a/HappyAnding/HappyAnding/ViewModel/ReadShortcutViewModels/ReadShortcutViewModel.swift b/HappyAnding/HappyAnding/ViewModel/ReadShortcutViewModels/ReadShortcutViewModel.swift index eb945867..017dcf0b 100644 --- a/HappyAnding/HappyAnding/ViewModel/ReadShortcutViewModels/ReadShortcutViewModel.swift +++ b/HappyAnding/HappyAnding/ViewModel/ReadShortcutViewModels/ReadShortcutViewModel.swift @@ -52,6 +52,7 @@ final class ReadShortcutViewModel: ObservableObject { } init(data: Shortcuts) { + print("*****init") self.author = User() self.shortcut = shortcutsZipViewModel.fetchShortcutDetail(id: data.id) ?? data self.isMyLike = shortcutsZipViewModel.checkLikedShortrcut(shortcutID: data.id) diff --git a/HappyAnding/HappyAnding/Views/Components/ShortcutIcon.swift b/HappyAnding/HappyAnding/Views/Components/ShortcutIcon.swift index 800d259f..22798259 100644 --- a/HappyAnding/HappyAnding/Views/Components/ShortcutIcon.swift +++ b/HappyAnding/HappyAnding/Views/Components/ShortcutIcon.swift @@ -21,7 +21,7 @@ struct ShortcutIcon: View { .roundedBorder(cornerRadius: 13, color: .white, isNormalBlend: true, opacity: 0.24) .frame(width: size, height: size) Image(systemName: sfSymbol) - .font(.system(size: 28)) + .font(.system(size: size/2 - 5)) .foregroundStyle(Color.white) } } diff --git a/HappyAnding/HappyAnding/Views/ReadShortcutViews/ReadShortcutView.swift b/HappyAnding/HappyAnding/Views/ReadShortcutViews/ReadShortcutView.swift index e5e2a269..f3ae547c 100644 --- a/HappyAnding/HappyAnding/Views/ReadShortcutViews/ReadShortcutView.swift +++ b/HappyAnding/HappyAnding/Views/ReadShortcutViews/ReadShortcutView.swift @@ -15,722 +15,312 @@ struct ReadShortcutView: View { @Environment(\.loginAlertKey) var loginAlerter @StateObject var viewModel: ReadShortcutViewModel - @StateObject var writeNavigation = WriteShortcutNavigation() - - @AppStorage("useWithoutSignIn") var useWithoutSignIn: Bool = false - @FocusState private var isFocused: Bool - @Namespace var namespace - @Namespace var bottomID - - private let tabItems = [TextLiteral.readShortcutViewBasicTabTitle, TextLiteral.readShortcutViewVersionTabTitle, TextLiteral.readShortcutViewCommentTabTitle] - private let hapticManager = HapticManager.instance var body: some View { - ZStack { - ScrollViewReader { proxy in - ScrollView { - VStack(spacing: 0) { - StickyHeader(height: 40) - - /// 단축어 타이틀 - ReadShortcutViewHeader(viewModel: self.viewModel) - - /// 탭뷰 (기본 정보, 버전 정보, 댓글) - LazyVStack(pinnedViews: [.sectionHeaders]) { - Section(header: tabBarView) { - ZStack { - TabView(selection: $viewModel.currentTab) { - Color.clear - .tag(0) - Color.clear - .tag(1) - Color.clear - .tag(2) - } - .tabViewStyle(.page(indexDisplayMode: .never)) - .frame(minHeight: UIScreen.screenHeight / 2) - - switch viewModel.currentTab { - case 0: - ReadShortcutContentView(viewModel: self.viewModel) - case 1: - ReadShortcutVersionView(viewModel: self.viewModel) - case 2: - ReadShortcutCommentView(viewModel: self.viewModel) - .id(bottomID) - default: - EmptyView() - } - } - .animation(.easeInOut, value: viewModel.currentTab) - .padding(.top, 4) - .padding(.horizontal, 16) - } - } - } - } - .onAppear { - NotificationCenter.default.addObserver(forName: UIResponder.keyboardDidShowNotification, object: nil, queue: .main) { - notification in - withAnimation { - if viewModel.currentTab == 2 && !viewModel.isEditingComment && viewModel.comment.depth == 0 { - proxy.scrollTo(bottomID, anchor: .bottom) - } - } - } + ScrollView { + VStack(alignment: .leading, spacing: 16) { + + Text("\" \(viewModel.shortcut.subtitle) \"") + .font(.system(size: 16, weight: .semibold)) + .foregroundStyle(SCZColor.Basic) + .frame(maxWidth: .infinity) + .padding(.vertical, 10) + .background(SCZColor.CharcoalGray.opacity04) + .roundedBorder(cornerRadius: 16, color: Color.white.opacity(0.12), isNormalBlend: true) + .padding(.top, 8) + + Divider() + .padding(.vertical, 8) + + ReadShortcutHeader(viewModel: self.viewModel) + + Divider() + .padding(.vertical, 8) + + ScrollView(.horizontal) { + //TODO: 이미지 추가 } - } - .scrollDisabled(viewModel.isEditingComment) - .background(Color.shortcutsZipBackground) - .navigationBarBackground ({ Color.shortcutsZipWhite }) - .navigationBarTitleDisplayMode(NavigationBarItem.TitleDisplayMode.inline) - .navigationBarItems(trailing: readShortcutViewNavigationBarItems()) - .toolbar(.hidden, for: .tabBar) - .safeAreaInset(edge: .bottom, spacing: 0) { + .padding(.horizontal, 8) - /// Safe Area에 고정된 댓글창, 다운로드 버튼 - VStack { - if !viewModel.isEditingComment { - if viewModel.currentTab == 2 { - commentTextField - } - if !isFocused { - Button { - if !useWithoutSignIn { - if let url = URL(string: viewModel.shortcut.downloadLink[0]) { - viewModel.checkIfDownloaded() - viewModel.isDownloadingShortcut = true - openURL(url) - } - hapticManager.notification(type: .success) - viewModel.updateNumberOfDownload(index: 0) - } else { - loginAlerter.isPresented = true - } - } label: { - Text("다운로드 | \(Image(systemName: "arrow.down.app.fill")) \(viewModel.shortcut.numberOfDownload)") - .shortcutsZipBody1() - .foregroundStyle(Color.textIcon) - .padding() - .frame(maxWidth: .infinity) - .background(Color.shortcutsZipPrimary) - } + Divider() + .padding(.vertical, 8) + Text(viewModel.shortcut.description.replacingOccurrences(of: "\\n", with: "\n")) + .font(.system(size: 14, weight: .regular)) + .foregroundStyle(SCZColor.CharcoalGray.color) + .padding(8) + .frame(maxWidth: .infinity, alignment: .leading) + + Divider() + .padding(.vertical, 8) + + VStack(alignment: .leading, spacing: 16) { + SectionTitle(text: "필요한 앱") + HStack { + ForEach(viewModel.shortcut.requiredApp, id: \.self) { requirement in + Text(requirement) + .roundedBackground() } } } - .ignoresSafeArea(.keyboard) - } - .onAppear { - UINavigationBar.appearance().standardAppearance.configureWithTransparentBackground() - } - .onDisappear { - viewModel.onViewDisappear() - } - .alert(TextLiteral.readShortcutViewDeletionTitle, isPresented: $viewModel.isDeletingShortcut) { - Button(role: .cancel) { - } label: { - Text(TextLiteral.cancel) - } + .padding(.horizontal, 8) - Button(role: .destructive) { - viewModel.deleteShortcut() - self.presentation.wrappedValue.dismiss() - } label: { - Text(TextLiteral.delete) - } - } message: { - Text(viewModel.isDowngradingUserLevel ? TextLiteral.readShortcutViewDeletionMessageDowngrade : TextLiteral.readShortcutViewDeletionMessage) - } - .fullScreenCover(isPresented: $viewModel.isEditingShortcut) { - NavigationRouter(content: writeShortcutView, - path: $writeNavigation.navigationPath) - .environmentObject(writeNavigation) - .onDisappear { - viewModel.refreshShortcut() - } - } - .fullScreenCover(isPresented: $viewModel.isUpdatingShortcut) { - UpdateShortcutView(viewModel: self.viewModel) - } - - /// 댓글 수정할 때 뒷 배경을 어둡게 만들기 위한 뷰 - if viewModel.isEditingComment { - Color.black - .ignoresSafeArea() - .opacity(0.4) - .safeAreaInset(edge: .bottom, spacing: 0) { - commentTextField - .ignoresSafeArea(.keyboard) - .focused($isFocused, equals: true) - .task { - DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { - isFocused = true - } - } - } - .onAppear { - viewModel.commentText = viewModel.comment.contents - } - .onTapGesture(count: 1) { - isFocused.toggle() - viewModel.isUndoingCommentEdit.toggle() - } - .alert(TextLiteral.readShortcutViewDeleteFixesTitle, isPresented: $viewModel.isUndoingCommentEdit) { - Button(role: .cancel) { - isFocused.toggle() + Divider() + .padding(.vertical, 8) + + VStack(alignment: .leading, spacing: 6) { + HStack { + SectionTitle(text: "버전 업데이트 정보") + Spacer() + Button { + } label: { - Text(TextLiteral.readShortcutViewKeepFixes) - } - - Button(role: .destructive) { - withAnimation(.easeInOut) { - viewModel.cancelEditingComment() + HStack(spacing: 4) { + Text("최신") + Image(systemName: "chevron.down") } - } label: { - Text(TextLiteral.delete) + .roundedBackground() } - } message: { - Text(TextLiteral.readShortcutViewDeleteFixes) } - } - } - } - - @ViewBuilder - private func writeShortcutView() -> some View { - WriteShortcutView(viewModel: WriteShortcutViewModel(isEdit: true, shortcut: viewModel.shortcut)) - } -} - -extension ReadShortcutView { - - // MARK: - 댓글창 - - private var commentTextField: some View { - - VStack(spacing: 0) { - if viewModel.comment.depth == 1 && !viewModel.isEditingComment { - nestedCommentTargetView - } - HStack { - if viewModel.comment.depth == 1 && !viewModel.isEditingComment { - Image(systemName: "arrow.turn.down.right") - .smallIcon() - .foregroundStyle(Color.gray4) - } - TextField(useWithoutSignIn ? TextLiteral.readShortcutViewCommentDescriptionBeforeLogin : TextLiteral.readShortcutViewCommentDescription, text: $viewModel.commentText, axis: .vertical) - .keyboardType(.default) - .disabled(useWithoutSignIn) - .disableAutocorrection(true) - .textInputAutocapitalization(.never) - .shortcutsZipBody2() - .lineLimit(viewModel.comment.depth == 1 ? 2 : 4) - .focused($isFocused) - .onAppear { - UIApplication.shared.hideKeyboard() + ForEach(0.. some View { - if viewModel.checkAuthor() { - Menu { - Section { - editButton - updateButton - shareButton - deleteButton - } - } label: { - Image(systemName: "ellipsis") - .mediumIcon() - .foregroundStyle(Color.gray4) - } - } else { - shareButton - } - } - - private var editButton: some View { - Button { - viewModel.isEditingShortcut.toggle() - } label: { - Label(TextLiteral.edit, systemImage: "square.and.pencil") - } - } - - private var updateButton: some View { - Button { - viewModel.isUpdatingShortcut.toggle() - } label: { - Label(TextLiteral.update, systemImage: "clock.arrow.circlepath") - } - } - - private var shareButton: some View { - Button { - viewModel.shareShortcut() - } label: { - Label(TextLiteral.share, systemImage: "square.and.arrow.up") - .foregroundStyle(Color.gray4) - .fontWeight(.medium) - } - } - - private var deleteButton: some View { - Button(role: .destructive) { - viewModel.checkDowngrading() - } label: { - Label(TextLiteral.delete, systemImage: "trash.fill") } } +} + +struct UpdateListItem: View { + //"Ver \(viewModel.shortcut.updateDescription.count - index).0" + let index: Int + let description: String + let date: String - // MARK: - 탭바 - - private var tabBarView: some View { - HStack(spacing: 20) { - ForEach(Array(zip(self.tabItems.indices, self.tabItems)), id: \.0) { index, name in - tabBarItem(title: name, tabID: index) + var body: some View { + VStack(alignment: .leading, spacing: 4) { + HStack { + Text("Ver \(index).0") + .font(.system(size: 14, weight: .medium)) + .foregroundStyle(SCZColor.CharcoalGray.opacity64) + Text("최신") + .roundedBackground() } - } - .padding(.horizontal, 16) - .frame(height: 36) - .background(Color.shortcutsZipWhite) + Text(description) + Text(date.getVersionDateFormat() ?? "") + .foregroundStyle(SCZColor.CharcoalGray.opacity48) + }.font(.system(size: 14, weight: .regular)) } - - private func tabBarItem(title: String, tabID: Int) -> some View { - Button { - viewModel.moveTab(to: tabID) - } label: { - VStack { - if viewModel.currentTab == tabID { - Text(title) - .shortcutsZipHeadline() - .foregroundStyle(Color.gray5) - Color.gray5 - .frame(height: 2) - .matchedGeometryEffect(id: "underline", in: namespace, properties: .frame) - - } else { - Text(title) - .shortcutsZipBody1() - .foregroundStyle(Color.gray3) - Color.clear.frame(height: 2) - } - } - .animation(.spring(), value: viewModel.currentTab) - } - .buttonStyle(.plain) +} + +private struct SectionTitle: View { + let text: String + var body: some View { + Text(text) + //Pretendard 14 medium + .font(.system(size: 14, weight: .medium)) + .foregroundStyle(SCZColor.CharcoalGray.opacity48) } } -extension ReadShortcutView { - - //MARK: - 단축어 타이틀 - - struct ReadShortcutViewHeader: View { - @Environment(\.loginAlertKey) var loginAlerter - @EnvironmentObject var shortcutsZipViewModel: ShortcutsZipViewModel - - @StateObject var viewModel: ReadShortcutViewModel - - @AppStorage("useWithoutSignIn") var useWithoutSignIn: Bool = false - - private let hapticManager = HapticManager.instance - - var body: some View { - VStack(alignment: .leading, spacing: 16) { +struct ReadShortcutHeader: View { + @StateObject var viewModel: ReadShortcutViewModel + var body: some View { + HStack(spacing: 12) { + ShortcutIcon(sfSymbol: viewModel.shortcut.sfSymbol, color: viewModel.shortcut.color, size: 96) + .padding(.horizontal, 8) + + VStack(alignment: .leading, spacing: 3) { + Text(viewModel.shortcut.title) + .font(.system(size: 20, weight: .bold)) + .foregroundStyle(SCZColor.CharcoalGray.color) + .frame(maxWidth: .infinity, alignment: .leading) HStack { - - /// 단축어 아이콘 - VStack { - Image(systemName: viewModel.shortcut.sfSymbol) - .mediumShortcutIcon() - .foregroundStyle(Color.textIcon) - } - .frame(width: 52, height: 52) - .background(Color.fetchGradient(color: viewModel.shortcut.color)) - .cornerRadius(8) - - Spacer() - - /// 좋아요 버튼 - Text("\(viewModel.isMyLike ? Image(systemName: "heart.fill") : Image(systemName: "heart")) \(viewModel.numberOfLike)") - .shortcutsZipBody2() - .padding(10) - .foregroundStyle(viewModel.isMyLike ? Color.textIcon : Color.gray4) - .background(viewModel.isMyLike ? Color.shortcutsZipPrimary : Color.gray1) - .cornerRadius(12) - .onTapGesture { - if !useWithoutSignIn { - viewModel.isMyLike.toggle() - viewModel.numberOfLike += viewModel.isMyLike ? 1 : -1 - hapticManager.impact(style: .rigid) - } else { - loginAlerter.isPresented = true - } + ForEach (0.. some View { + @FocusState var isFocused: Bool + var body: some View { + VStack(alignment: .leading) { - VStack(alignment: .leading) { - - Text(title) + if viewModel.comments.comments.isEmpty { + Text(TextLiteral.readShortcutCommentViewNoComments) .shortcutsZipBody2() - .fontWeight(.bold) - .foregroundStyle(Color.gray6) - - WrappingHStack(content, id: \.self, alignment: .leading, spacing: .constant(8), lineSpacing: 8) { item in - if Category.allCases.contains(where: { $0.rawValue == item }) { - Text(Category(rawValue: item)?.translateName() ?? "") - .shortcutsZipBody2() - .padding(.trailing, 8) - .foregroundStyle(Color.gray5) - } else { - Text(item) - .shortcutsZipBody2() - .padding(.trailing, 8) - .foregroundStyle(Color.gray5) - } - if item != content.last { - Divider() - } - } + .foregroundStyle(Color.gray4) + .padding(.top, 16) + } else { + commentView } + + Spacer() + .frame(maxHeight: .infinity) } - } - - //MARK: - 버전 정보 탭 - - struct ReadShortcutVersionView: View { - - @Environment(\.openURL) var openURL - @Environment(\.loginAlertKey) var loginAlerter - @EnvironmentObject var shortcutsZipViewModel: ShortcutsZipViewModel - - @StateObject var viewModel: ReadShortcutViewModel - - @AppStorage("useWithoutSignIn") var useWithoutSignIn: Bool = false - - var body: some View { - VStack(alignment: .leading, spacing: 16) { + .padding(.top, 16) + .alert(TextLiteral.readShortcutCommentViewDeletionTitle, isPresented: $viewModel.isDeletingComment) { + Button(role: .cancel) { - if viewModel.shortcut.updateDescription.count == 1 { - HStack { - Text("Ver 1.0") - .shortcutsZipBody2() - .foregroundStyle(Color.gray5) - - Spacer() - - Text(viewModel.shortcut.date.first?.getVersionUpdateDateFormat() ?? "") - .shortcutsZipBody2() - .foregroundStyle(Color.gray3) - } - Text(TextLiteral.readShortcutVersionViewNoUpdates) - .shortcutsZipBody2() - .foregroundStyle(Color.gray4) - } else { - Text(TextLiteral.readShortcutVersionViewUpdateContent) - .shortcutsZipBody2() - .foregroundStyle(Color.gray4) - - versionView - } - - Spacer() - .frame(maxHeight: .infinity) + } label: { + Text(TextLiteral.cancel) } - .padding(.top, 16) - } - - private var versionView: some View { - ForEach(Array(zip(viewModel.shortcut.updateDescription, viewModel.shortcut.updateDescription.indices)), id: \.0) { data, index in - VStack(alignment: .leading, spacing: 12) { - HStack { - Text("Ver \(viewModel.shortcut.updateDescription.count - index).0") - .shortcutsZipBody2() - .foregroundStyle(Color.gray5) - - Spacer() - - Text(viewModel.shortcut.date[index].getVersionUpdateDateFormat()) - .shortcutsZipBody2() - .foregroundStyle(Color.gray3) - } - - if data.trimmingCharacters(in: .whitespacesAndNewlines) != "" { - Text(data) - .shortcutsZipBody2() - .foregroundStyle(Color.gray5) - } - - if index != 0 { - Button { - if !useWithoutSignIn { - if let url = URL(string: viewModel.shortcut.downloadLink[index]) { - viewModel.checkIfDownloaded() - viewModel.updateNumberOfDownload(index: index) - openURL(url) - } - } else { - loginAlerter.isPresented = true - } - } label: { - Text(TextLiteral.readShortcutVersionViewDownloadPreviousVersion) - .shortcutsZipBody2() - .foregroundStyle(Color.shortcutsZipPrimary) - } - } - - Divider() - .foregroundStyle(Color.gray1) - } + Button(role: .destructive) { + viewModel.deleteComment() + } label: { + Text(TextLiteral.delete) } + } message: { + Text(TextLiteral.readShortcutCommentViewDeletionMessage) } } - //MARK: - 댓글 탭 - - struct ReadShortcutCommentView: View { - - @EnvironmentObject var shortcutsZipViewModel: ShortcutsZipViewModel - - @StateObject var viewModel: ReadShortcutViewModel + private var commentView: some View { - @AppStorage("useWithoutSignIn") var useWithoutSignIn: Bool = false - - @FocusState var isFocused: Bool - - var body: some View { - VStack(alignment: .leading) { - - if viewModel.comments.comments.isEmpty { - Text(TextLiteral.readShortcutCommentViewNoComments) - .shortcutsZipBody2() + ForEach(viewModel.comments.comments, id: \.self) { comment in + + HStack(alignment: .top, spacing: 8) { + if comment.depth == 1 { + Image(systemName: "arrow.turn.down.right") + .smallIcon() .foregroundStyle(Color.gray4) - .padding(.top, 16) - } else { - commentView } - Spacer() - .frame(maxHeight: .infinity) - } - .padding(.top, 16) - .alert(TextLiteral.readShortcutCommentViewDeletionTitle, isPresented: $viewModel.isDeletingComment) { - Button(role: .cancel) { + VStack(alignment: .leading, spacing: 8) { - } label: { - Text(TextLiteral.cancel) - } - - Button(role: .destructive) { - viewModel.deleteComment() - } label: { - Text(TextLiteral.delete) - } - } message: { - Text(TextLiteral.readShortcutCommentViewDeletionMessage) - } - } - - private var commentView: some View { - - ForEach(viewModel.comments.comments, id: \.self) { comment in - - HStack(alignment: .top, spacing: 8) { - if comment.depth == 1 { - Image(systemName: "arrow.turn.down.right") - .smallIcon() + /// 유저 정보 + HStack(spacing: 8) { + + viewModel.fetchUserGrade(id: comment.user_id) + .font(.system(size: 24, weight: .medium)) + .frame(width: 24, height: 24) + .foregroundStyle(Color.gray3) + + Text(comment.user_nickname) + .shortcutsZipBody2() + .foregroundStyle(Color.gray4) + + Spacer() + + Text(comment.date.getVersionUpdateDateFormat()) + .shortcutsZipFootnote() .foregroundStyle(Color.gray4) } + .padding(.bottom, 4) - VStack(alignment: .leading, spacing: 8) { - - /// 유저 정보 - HStack(spacing: 8) { - - viewModel.fetchUserGrade(id: comment.user_id) - .font(.system(size: 24, weight: .medium)) - .frame(width: 24, height: 24) - .foregroundStyle(Color.gray3) - - Text(comment.user_nickname) - .shortcutsZipBody2() - .foregroundStyle(Color.gray4) - - Spacer() - - Text(comment.date.getVersionUpdateDateFormat()) - .shortcutsZipFootnote() - .foregroundStyle(Color.gray4) + /// 댓글 내용 + Text(.init(comment.contents)) + .textSelection(.enabled) + .shortcutsZipBody2() + .foregroundStyle(Color.gray5) + .tint(.shortcutsZipPrimary) + .frame(maxWidth: .infinity, alignment: .leading) + .padding(.leading, 4) + + /// 답글, 수정, 삭제 버튼 + HStack(spacing: 0) { + if !useWithoutSignIn { + Button { + viewModel.setReply(to: comment) + isFocused = true + } label: { + Text(TextLiteral.readShortcutCommentViewReply) + .shortcutsZipFootnote() + .foregroundStyle(Color.gray4) + .frame(width: 32, height: 24) + } } - .padding(.bottom, 4) - /// 댓글 내용 - Text(.init(comment.contents)) - .textSelection(.enabled) - .shortcutsZipBody2() - .foregroundStyle(Color.gray5) - .tint(.shortcutsZipPrimary) - .frame(maxWidth: .infinity, alignment: .leading) - .padding(.leading, 4) - - /// 답글, 수정, 삭제 버튼 - HStack(spacing: 0) { - if !useWithoutSignIn { + if let user = shortcutsZipViewModel.userInfo { + if user.id == comment.user_id { Button { - viewModel.setReply(to: comment) - isFocused = true + withAnimation(.easeInOut) { + viewModel.isEditingComment.toggle() + viewModel.comment = comment + } } label: { - Text(TextLiteral.readShortcutCommentViewReply) + Text(TextLiteral.readShortcutCommentViewEdit) .shortcutsZipFootnote() .foregroundStyle(Color.gray4) .frame(width: 32, height: 24) } - } - - if let user = shortcutsZipViewModel.userInfo { - if user.id == comment.user_id { - Button { - withAnimation(.easeInOut) { - viewModel.isEditingComment.toggle() - viewModel.comment = comment - } - } label: { - Text(TextLiteral.readShortcutCommentViewEdit) - .shortcutsZipFootnote() - .foregroundStyle(Color.gray4) - .frame(width: 32, height: 24) - } - - Button { - viewModel.isDeletingComment.toggle() - viewModel.deletedComment = comment - } label: { - Text(TextLiteral.delete) - .shortcutsZipFootnote() - .foregroundStyle(Color.gray4) - .frame(width: 32, height: 24) - } + + Button { + viewModel.isDeletingComment.toggle() + viewModel.deletedComment = comment + } label: { + Text(TextLiteral.delete) + .shortcutsZipFootnote() + .foregroundStyle(Color.gray4) + .frame(width: 32, height: 24) } } } - - Divider() - .background(Color.gray1) } + + Divider() + .background(Color.gray1) } - .padding(.bottom, 16) } + .padding(.bottom, 16) } } }