Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feat] ReadShortcutViewModel 생성 #479

Merged
merged 12 commits into from
Aug 12, 2023
8 changes: 8 additions & 0 deletions HappyAnding/HappyAnding.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
4D778A34290A53BA00C15AC4 /* UIApplication+Keyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4D778A33290A53BA00C15AC4 /* UIApplication+Keyboard.swift */; };
4D7D16072986BBD7008B3332 /* TextLiteral.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4D7D16062986BBD7008B3332 /* TextLiteral.swift */; };
4D7D16082986BBDE008B3332 /* TextLiteral.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4D7D16062986BBD7008B3332 /* TextLiteral.swift */; };
4D93D06F2A5956E60042CBA8 /* ShowProfileViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4D93D06E2A5956E60042CBA8 /* ShowProfileViewModel.swift */; };
4D93D0752A61D0D10042CBA8 /* ReadShortcutViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4D93D0742A61D0D10042CBA8 /* ReadShortcutViewModel.swift */; };
4DAD635E292AB61700ABF8C1 /* UpdateShortcutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DAD635D292AB61700ABF8C1 /* UpdateShortcutView.swift */; };
4DF62DD52A0550ED00A8B377 /* UIScreen+Size.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8795A16F292AB945004B765F /* UIScreen+Size.swift */; };
87276C382933F6AB00C92F4C /* CustomTextEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87276C372933F6AB00C92F4C /* CustomTextEditor.swift */; };
Expand Down Expand Up @@ -192,6 +194,8 @@
4D6A9F0029A3A92E00D02522 /* wrappinghstack+license.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "wrappinghstack+license.txt"; sourceTree = "<group>"; };
4D778A33290A53BA00C15AC4 /* UIApplication+Keyboard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIApplication+Keyboard.swift"; sourceTree = "<group>"; };
4D7D16062986BBD7008B3332 /* TextLiteral.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = TextLiteral.swift; path = HappyAnding/TextLiteral.swift; sourceTree = SOURCE_ROOT; };
4D93D06E2A5956E60042CBA8 /* ShowProfileViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShowProfileViewModel.swift; sourceTree = "<group>"; };
4D93D0742A61D0D10042CBA8 /* ReadShortcutViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReadShortcutViewModel.swift; sourceTree = "<group>"; };
4DAD635D292AB61700ABF8C1 /* UpdateShortcutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateShortcutView.swift; sourceTree = "<group>"; };
87276C372933F6AB00C92F4C /* CustomTextEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTextEditor.swift; sourceTree = "<group>"; };
872A7D8E2918393B004A05B8 /* PrivacyPolicyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacyPolicyView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -389,6 +393,8 @@
8788E1A32A484533007C3852 /* ReadShortcutViewModels */ = {
isa = PBXGroup;
children = (
4D93D0742A61D0D10042CBA8 /* ReadShortcutViewModel.swift */,
4D93D06E2A5956E60042CBA8 /* ShowProfileViewModel.swift */,
);
path = ReadShortcutViewModels;
sourceTree = "<group>";
Expand Down Expand Up @@ -912,6 +918,7 @@
A0F822AC2910B8F100AF4448 /* ShortcutsZipViewModel.swift in Sources */,
87276C382933F6AB00C92F4C /* CustomTextEditor.swift in Sources */,
A34BF82D29AFC34F009BC946 /* AboutShortcutGradeView.swift in Sources */,
4D93D06F2A5956E60042CBA8 /* ShowProfileViewModel.swift in Sources */,
87E99CC429014572009B691F /* Color+Extension.swift in Sources */,
87CFD8492939187200F97B86 /* NicknameTextField.swift in Sources */,
4D3DBB962934E31A00DE8160 /* ShowProfileView.swift in Sources */,
Expand Down Expand Up @@ -965,6 +972,7 @@
F9136EB6293612310034AAB2 /* ShortcutsZipView.swift in Sources */,
87E99CB128FFF273009B691F /* WriteCurationSetView.swift in Sources */,
4D61A767291E1EE8000EF531 /* NavigationViewModel.swift in Sources */,
4D93D0752A61D0D10042CBA8 /* ReadShortcutViewModel.swift in Sources */,
F96D45BD29816578000C2441 /* StickyHeader.swift in Sources */,
87E99CEE29080D33009B691F /* User.swift in Sources */,
F976E82C29368E0D0088BBA1 /* Version.swift in Sources */,
Expand Down
16 changes: 8 additions & 8 deletions HappyAnding/HappyAnding/Extensions/View/View+Navigation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -79,14 +79,14 @@ extension View {
switch data {
case is NavigationListShortcutType:
ListShortcutView(data: data as! NavigationListShortcutType)
case is NavigationReadShortcutType:
ReadShortcutView(data: data as! NavigationReadShortcutType)
case is Shortcuts:
ReadShortcutView(viewModel: ReadShortcutViewModel(data: data as! Shortcuts))
case is Curation:
ReadCurationView(viewModel: ReadCurationViewModel(data: data as! Curation))
case is CurationType:
ListCurationView(viewModel: ListCurationViewModel(data: data as! CurationType))
case is NavigationProfile:
ShowProfileView(data: data as! NavigationProfile)
case is User:
ShowProfileView(viewModel: ShowProfileViewModel(data: data as! User))
case is NavigationSearch:
SearchView()
case is NavigationListCategoryShortcutType:
Expand Down Expand Up @@ -115,17 +115,17 @@ struct NavigationViewModifier: ViewModifier {
func body(content: Content) -> some View {
content

.navigationDestination(for: NavigationProfile.self) { data in
ShowProfileView(data: data)
.navigationDestination(for: User.self) { data in
ShowProfileView(viewModel: ShowProfileViewModel(data: data))
}
.navigationDestination(for: Curation.self) { data in
ReadCurationView(viewModel: ReadCurationViewModel(data: data))
}
.navigationDestination(for: CurationType.self) { data in
ListCurationView(viewModel: ListCurationViewModel(data: data))
}
.navigationDestination(for: NavigationReadShortcutType.self) { data in
ReadShortcutView(data: data)
.navigationDestination(for: Shortcuts.self) { data in
ReadShortcutView(viewModel: ReadShortcutViewModel(data: data))
}
.navigationDestination(for: NavigationListShortcutType.self) { data in
ListShortcutView(data: data)
Expand Down
26 changes: 26 additions & 0 deletions HappyAnding/HappyAnding/Model/Comment.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,16 @@ struct Comments: Identifiable, Codable, Equatable {
let data = (try? JSONEncoder().encode(self)) ?? Data()
return (try? JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any]) ?? [:]
}

init() {
self.id = ""
self.comments = []
}

init(id: String, comments: [Comment]) {
self.id = id
self.comments = comments
}
}

struct Comment: Identifiable, Codable, Hashable {
Expand All @@ -25,6 +35,22 @@ struct Comment: Identifiable, Codable, Hashable {
var date: String //처음 작성한 날짜만 저장
var depth: Int //0이면 원댓글, 1이면 대댓글
var contents: String

init() {
self.user_nickname = ""
self.user_id = ""
self.date = ""
self.depth = 0
self.contents = ""
}

init(user_nickname: String, user_id: String, date: String, depth: Int, contents: String) {
self.user_nickname = user_nickname
self.user_id = user_id
self.date = date
self.depth = depth
self.contents = contents
}
}

extension Comments {
Expand Down
15 changes: 0 additions & 15 deletions HappyAnding/HappyAnding/Model/NavigationStackModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,6 @@ struct NavigationListShortcutType: Identifiable, Hashable {
let navigationParentView: NavigationParentView
}

struct NavigationReadShortcutType: Identifiable, Hashable {
var id = UUID().uuidString

var shortcut: Shortcuts?
let shortcutID: String
let navigationParentView: NavigationParentView
}

struct NavigationProfile: Identifiable, Hashable {
var id = UUID().uuidString

var userInfo: User?
}

struct NavigationListCategoryShortcutType: Identifiable, Hashable {

var id = UUID().uuidString
Expand Down Expand Up @@ -67,7 +53,6 @@ enum NavigationNicknameView: Hashable, Equatable {
case first
}


enum NavigationLisence: Hashable, Equatable {
case first
}
Expand Down
32 changes: 32 additions & 0 deletions HappyAnding/HappyAnding/Model/Shortcuts.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,36 @@ struct Shortcuts: Identifiable, Codable, Equatable, Hashable {
let data = (try? JSONEncoder().encode(self)) ?? Data()
return (try? JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any]) ?? [:]
}

init() {
self.sfSymbol = ""
self.color = ""
self.title = ""
self.subtitle = ""
self.description = ""
self.category = []
self.requiredApp = []
self.numberOfLike = 0
self.numberOfDownload = 0
self.author = ""
self.shortcutRequirements = ""
self.downloadLink = []
self.curationIDs = []
}

init(sfSymbol: String, color: String, title: String, subtitle: String, description: String, category: [String], requiredApp: [String], numberOfLike: Int, numberOfDownload: Int, author: String, shortcutRequirements: String, downloadLink: [String], curationIDs: [String]) {
self.sfSymbol = sfSymbol
self.color = color
self.title = title
self.subtitle = subtitle
self.description = description
self.category = category
self.requiredApp = requiredApp
self.numberOfLike = numberOfLike
self.numberOfDownload = numberOfDownload
self.author = author
self.shortcutRequirements = shortcutRequirements
self.downloadLink = downloadLink
self.curationIDs = curationIDs
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,9 @@ final class ReadCurationViewModel: ObservableObject {
guard let window = windowScene?.windows.first else { return }
window.rootViewController?.present(activityVC, animated: true, completion: nil)
}

func fetchShortcut(from shortcutCellModel: ShortcutCellModel) -> Shortcuts {
shortcutsZipViewModel.fetchShortcutDetail(id: shortcutCellModel.id) ?? Shortcuts()
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
//
// ReadShortcutViewModel.swift
// HappyAnding
//
// Created by kimjimin on 2023/07/15.
//

import SwiftUI

final class ReadShortcutViewModel: ObservableObject {

private let shortcutsZipViewModel = ShortcutsZipViewModel.share

@Published private(set) var shortcut: Shortcuts

// ReadShortcutView
@Published var isDeletingShortcut = false
@Published var isEditingShortcut = false
@Published var isUpdatingShortcut = false

@Published var isMyLike = false
@Published private var isMyFirstLike = false
@Published var isDownloadingShortcut = false
@Published private(set) var isDowngradingUserLevel = false

@Published var currentTab: Int = 0
@Published private(set) var comments: Comments = Comments()
@Published var comment: Comment = Comment()
@Published var nestedCommentTarget: String = ""
@Published var commentText = ""

@Published var isEditingComment = false
@Published var isUndoingCommentEdit = false

// ReadShortcutViewHeader
@Published private(set) var author: User
@Published var numberOfLike = 0
@Published private(set) var userGrade = Image(systemName: "person.crop.circle.fill")

// ReadShortcutCommentView
@Published var isDeletingComment = false
@Published var deletedComment = Comment()

// UpdateShortcutView
@Published var updatedLink = ""
@Published var updateDescription = ""
@Published var isLinkValid = false
@Published var isDescriptionValid = false

var isUpdateValid: Bool {
isLinkValid && isDescriptionValid
}

init(data: Shortcuts) {
self.author = User()
self.shortcut = shortcutsZipViewModel.fetchShortcutDetail(id: data.id) ?? data
self.isMyLike = shortcutsZipViewModel.checkLikedShortrcut(shortcutID: data.id)
self.isMyFirstLike = isMyLike
self.comments = shortcutsZipViewModel.fetchComment(shortcutID: data.id)
self.numberOfLike = data.numberOfLike
fetchAuthor()
}

private func fetchAuthor() {
shortcutsZipViewModel.fetchUser(userID: shortcut.author,
isCurrentUser: false) { user in
self.author = user
let grade = self.shortcutsZipViewModel.checkShortcutGrade(userID: self.author.id)
let image = self.shortcutsZipViewModel.fetchShortcutGradeImage(isBig: false, shortcutGrade: grade)
self.userGrade = image
}
}

func moveTab(to tab: Int) {
self.currentTab = tab
}

func setReply(to comment: Comment) {
self.nestedCommentTarget = comment.user_nickname
self.comment.bundle_id = comment.bundle_id
self.comment.depth = 1
}

func checkIfDownloaded() {
if (shortcutsZipViewModel.userInfo?.downloadedShortcuts.firstIndex(where: { $0.id == shortcut.id })) == nil {
shortcut.numberOfDownload += 1
}
}

func updateNumberOfDownload(index: Int) {
shortcutsZipViewModel.updateNumberOfDownload(shortcut: shortcut, downloadlinkIndex: index)
}

func onViewDisappear() {
if isMyLike != isMyFirstLike {
shortcutsZipViewModel.updateNumberOfLike(isMyLike: isMyLike, shortcut: shortcut)
}
}

func deleteShortcut() {
shortcutsZipViewModel.deleteShortcutIDInUser(shortcutID: shortcut.id)
shortcutsZipViewModel.deleteShortcutInCuration(curationsIDs: shortcut.curationIDs, shortcutID: shortcut.id)
shortcutsZipViewModel.deleteData(model: shortcut)
shortcutsZipViewModel.shortcutsMadeByUser = shortcutsZipViewModel.shortcutsMadeByUser.filter { $0.id != shortcut.id }
shortcutsZipViewModel.updateShortcutGrade()
}

func cancelEditingComment() {
self.isEditingComment.toggle()
self.comment = self.comment.resetComment()
self.commentText = ""
}

func postComment() {
if !isEditingComment {
comment.contents = commentText
comment.date = Date().getDate()
comment.user_id = shortcutsZipViewModel.userInfo!.id
comment.user_nickname = shortcutsZipViewModel.userInfo!.nickname
comments.comments.append(comment)
} else {
if let index = comments.comments.firstIndex(where: { $0.id == comment.id }) {
comments.comments[index].contents = commentText
}
isEditingComment = false
}
shortcutsZipViewModel.setData(model: comments)
commentText = ""
comment = comment.resetComment()
self.comments.comments = comments.fetchSortedComment()
}

func cancelNestedComment() {
comment.bundle_id = "\(Date().getDate())_\(UUID().uuidString)"
comment.depth = 0
}

func checkAuthor() -> Bool {
return self.shortcut.author == shortcutsZipViewModel.currentUser()
}

func shareShortcut() {
guard let deepLink = URL(string: "ShortcutsZip://myPage/detailView?shortcutID=\(shortcut.id)") else { return }
let activityVC = UIActivityViewController(activityItems: [deepLink], applicationActivities: nil)
let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene
guard let window = windowScene?.windows.first else { return }
window.rootViewController?.present(activityVC, animated: true, completion: nil)
}

func checkDowngrading() {
isDeletingShortcut.toggle()
isDowngradingUserLevel = shortcutsZipViewModel.isShortcutDowngrade()
}

func updateShortcut() {
shortcutsZipViewModel.updateShortcutVersion(shortcut: shortcut,
updateDescription: updateDescription,
updateLink: updatedLink)
self.shortcut = shortcutsZipViewModel.fetchShortcutDetail(id: shortcut.id) ?? shortcut
isUpdatingShortcut.toggle()
}

func deleteComment() {
if deletedComment.depth == 0 {
comments.comments.removeAll(where: { $0.bundle_id == deletedComment.bundle_id})
} else {
comments.comments.removeAll(where: { $0.id == deletedComment.id})
}

shortcutsZipViewModel.setData(model: comments)
}

func fetchUserGrade(id: String) -> Image {
shortcutsZipViewModel.fetchShortcutGradeImage(isBig: false, shortcutGrade: shortcutsZipViewModel.checkShortcutGrade(userID: id))
}

func refreshShortcut() {
self.shortcut = shortcutsZipViewModel.fetchShortcutDetail(id: shortcut.id) ?? shortcut
}
}
Loading