diff --git a/HappyAnding/HappyAnding.xcodeproj/project.pbxproj b/HappyAnding/HappyAnding.xcodeproj/project.pbxproj index a2ec4dac..0a35bf03 100644 --- a/HappyAnding/HappyAnding.xcodeproj/project.pbxproj +++ b/HappyAnding/HappyAnding.xcodeproj/project.pbxproj @@ -15,6 +15,7 @@ 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 */; }; 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 */; }; @@ -192,6 +193,7 @@ 4D6A9F0029A3A92E00D02522 /* wrappinghstack+license.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "wrappinghstack+license.txt"; sourceTree = ""; }; 4D778A33290A53BA00C15AC4 /* UIApplication+Keyboard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIApplication+Keyboard.swift"; sourceTree = ""; }; 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 = ""; }; 4DAD635D292AB61700ABF8C1 /* UpdateShortcutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateShortcutView.swift; sourceTree = ""; }; 87276C372933F6AB00C92F4C /* CustomTextEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTextEditor.swift; sourceTree = ""; }; 872A7D8E2918393B004A05B8 /* PrivacyPolicyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacyPolicyView.swift; sourceTree = ""; }; @@ -653,6 +655,7 @@ A0F822AB2910B8F100AF4448 /* ShortcutsZipViewModel.swift */, 4D61A766291E1EE8000EF531 /* NavigationViewModel.swift */, F9AC2BB52935201C00165820 /* CheckUpdateVersion.swift */, + 4D93D06E2A5956E60042CBA8 /* ShowProfileViewModel.swift */, ); path = ViewModel; sourceTree = ""; @@ -912,6 +915,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 */, diff --git a/HappyAnding/HappyAnding/Extensions/View/View+Navigation.swift b/HappyAnding/HappyAnding/Extensions/View/View+Navigation.swift index d3722e17..8f659162 100644 --- a/HappyAnding/HappyAnding/Extensions/View/View+Navigation.swift +++ b/HappyAnding/HappyAnding/Extensions/View/View+Navigation.swift @@ -85,8 +85,8 @@ extension View { 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: @@ -115,8 +115,8 @@ 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 ?? User())) } .navigationDestination(for: Curation.self) { data in ReadCurationView(viewModel: ReadCurationViewModel(data: data)) diff --git a/HappyAnding/HappyAnding/ViewModel/ShowProfileViewModel.swift b/HappyAnding/HappyAnding/ViewModel/ShowProfileViewModel.swift new file mode 100644 index 00000000..e659af83 --- /dev/null +++ b/HappyAnding/HappyAnding/ViewModel/ShowProfileViewModel.swift @@ -0,0 +1,39 @@ +// +// ShowProfileViewModel.swift +// HappyAnding +// +// Created by kimjimin on 2023/07/08. +// + +import SwiftUI + +final class ShowProfileViewModel: ObservableObject { + + var shortcutsZipViewModel = ShortcutsZipViewModel.share + + @Published var user: User + @Published private(set) var shortcuts: [Shortcuts] = [] + @Published private(set) var curations: [Curation] = [] + @Published private(set) var userGrade = Image(systemName: "person.crop.circle.fill") + @Published var currentTab: Int = 0 + @Published var animationAmount = 0.0 + + init(data: User) { + self.user = data + fetchUserGrade() + fetchShortcuts() + fetchCurations() + } + + private func fetchUserGrade() { + self.userGrade = shortcutsZipViewModel.fetchShortcutGradeImage(isBig: true, shortcutGrade: shortcutsZipViewModel.checkShortcutGrade(userID: user.id)) + } + + private func fetchShortcuts() { + self.shortcuts = shortcutsZipViewModel.allShortcuts.filter { $0.author == user.id } + } + + private func fetchCurations() { + self.curations = shortcutsZipViewModel.fetchCurationByAuthor(author: user.id) + } +} diff --git a/HappyAnding/HappyAnding/Views/Components/UserNameCell.swift b/HappyAnding/HappyAnding/Views/Components/UserNameCell.swift index ab5dd37a..ce0ce231 100644 --- a/HappyAnding/HappyAnding/Views/Components/UserNameCell.swift +++ b/HappyAnding/HappyAnding/Views/Components/UserNameCell.swift @@ -56,7 +56,7 @@ struct UserNameCell: View { RoundedRectangle(cornerRadius: 12) .foregroundColor(.gray1) ) - .navigationLinkRouter(data: NavigationProfile(userInfo: self.userInformation)) + .navigationLinkRouter(data: self.userInformation) .disabled(self.userInformation == nil) } } diff --git a/HappyAnding/HappyAnding/Views/ReadShortcutViews/ShowProfileView.swift b/HappyAnding/HappyAnding/Views/ReadShortcutViews/ShowProfileView.swift index 3fc3a211..3613ae4b 100644 --- a/HappyAnding/HappyAnding/Views/ReadShortcutViews/ShowProfileView.swift +++ b/HappyAnding/HappyAnding/Views/ReadShortcutViews/ShowProfileView.swift @@ -9,46 +9,46 @@ import SwiftUI struct ShowProfileView: View { - @EnvironmentObject var shortcutsZipViewModel: ShortcutsZipViewModel - - @State var data: NavigationProfile - - @State var shortcuts: [Shortcuts] = [] - @State var curations: [Curation] = [] - @State var currentTab: Int = 0 - - @State private var animationAmount = 0.0 + @StateObject var viewModel: ShowProfileViewModel @Namespace var namespace - + private let tabItems = [TextLiteral.showProfileViewShortcutTabTitle, TextLiteral.showProfileViewCurationTabTitle] var body: some View { ScrollView { VStack(spacing: 0) { - StickyHeader(height: 24) //MARK: 프로필이미지 및 닉네임 VStack(spacing: 8) { Button { withAnimation(.interpolatingSpring(stiffness: 10, damping: 3)) { - self.animationAmount += 360 + viewModel.animationAmount += 360 } } label: { - ZStack(alignment: .center) { - Circle() + if viewModel.shortcuts.isEmpty { + viewModel.userGrade + .resizable() .frame(width: 72, height: 72) - .foregroundColor(.gray1) - shortcutsZipViewModel.fetchShortcutGradeImage(isBig: true, shortcutGrade: shortcutsZipViewModel.checkShortcutGrade(userID: data.userInfo?.id ?? "")) - .rotation3DEffect( - .degrees(animationAmount), axis: (x: 0.0, y: 1.0, z: 0.0)) + .foregroundColor(.gray3) + } else { + ZStack(alignment: .center) { + Circle() + .frame(width: 72, height: 72) + .foregroundColor(.gray1) + viewModel.userGrade + .rotation3DEffect( + .degrees(viewModel.animationAmount), axis: (x: 0.0, y: 1.0, z: 0.0)) + } } } - Text(data.userInfo?.nickname ?? TextLiteral.defaultUser) + + Text(viewModel.user.nickname) .shortcutsZipTitle1() .foregroundColor(.gray5) } + .disabled(viewModel.shortcuts.isEmpty) .frame(maxWidth: .infinity) .padding(.bottom, 35) .background(Color.shortcutsZipWhite) @@ -66,16 +66,11 @@ struct ShowProfileView: View { .background(Color.shortcutsZipBackground) .toolbar(.visible, for: .tabBar) .onAppear { - shortcuts = shortcutsZipViewModel.allShortcuts.filter { $0.author == self.data.userInfo?.id } - curations = shortcutsZipViewModel.fetchCurationByAuthor(author: data.userInfo?.id ?? "") withAnimation(.interpolatingSpring(stiffness: 10, damping: 3)) { - self.animationAmount += 360 + viewModel.animationAmount += 360 } } } -} - -extension ShowProfileView { //MARK: 탭바 var tabBarView: some View { @@ -91,10 +86,10 @@ extension ShowProfileView { private func tabBarItem(string: String, tab: Int) -> some View { Button { - self.currentTab = tab + viewModel.currentTab = tab } label: { VStack { - if self.currentTab == tab { + if viewModel.currentTab == tab { Text(string) .shortcutsZipHeadline() .foregroundColor(.gray5) @@ -110,7 +105,7 @@ extension ShowProfileView { .frame(height: 2) } } - .animation(.spring(), value: currentTab) + .animation(.spring(), value: viewModel.currentTab) } .buttonStyle(.plain) } @@ -119,16 +114,16 @@ extension ShowProfileView { var profileContentView: some View { VStack { ZStack { - TabView(selection: self.$currentTab) { + TabView(selection: $viewModel.currentTab) { Color.clear.tag(0) Color.clear.tag(1) } .frame(minHeight: UIScreen.screenHeight / 2) .tabViewStyle(.page(indexDisplayMode: .never)) - switch(currentTab) { + switch(viewModel.currentTab) { case 0: - if shortcuts.isEmpty { + if viewModel.shortcuts.isEmpty { VStack { Text(TextLiteral.showProfileViewNoShortcuts) .padding(.top, 16) @@ -139,7 +134,7 @@ extension ShowProfileView { } VStack(spacing: 0) { - ForEach(shortcuts, id:\.self) { shortcut in + ForEach(viewModel.shortcuts, id:\.self) { shortcut in let data = NavigationReadShortcutType(shortcutID:shortcut.id, navigationParentView: .shortcuts) @@ -153,7 +148,7 @@ extension ShowProfileView { } .padding(.bottom, 44) case 1: - if curations.isEmpty { + if viewModel.curations.isEmpty { VStack{ Text(TextLiteral.showProfileViewNoCurations) .padding(.top, 16) @@ -179,7 +174,7 @@ extension ShowProfileView { EmptyView() } } - .animation(.easeInOut, value: currentTab) + .animation(.easeInOut, value: viewModel.currentTab) } } }