From 34bf3b6b2e43e3ec2b020b0c0e9945e0c4d6901f Mon Sep 17 00:00:00 2001 From: makinosp Date: Sat, 26 Oct 2024 20:24:32 +0900 Subject: [PATCH 1/6] feat: improvement requesting flag in LoginView --- harmonie/ViewModels/AppViewModel.swift | 6 +++--- harmonie/Views/Authentication/LoginView.swift | 17 ++++++++++------- harmonie/Views/Favorite/FavoritesView.swift | 2 +- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/harmonie/ViewModels/AppViewModel.swift b/harmonie/ViewModels/AppViewModel.swift index e11cae6..01bcbca 100644 --- a/harmonie/ViewModels/AppViewModel.swift +++ b/harmonie/ViewModels/AppViewModel.swift @@ -15,7 +15,7 @@ final class AppViewModel { var step: Step = .initializing var isPresentedAlert = false var vrckError: VRCKitError? - var isLoggingIn = false + var isRequesting = false var services: APIServiceUtil var verifyType: VerifyType? @ObservationIgnored var client: APIClient @@ -82,9 +82,9 @@ final class AppViewModel { } func login() async -> Either? { - defer { isLoggingIn = false } + defer { isRequesting = false } var result: Either? - isLoggingIn = true + isRequesting = true do { result = try await services.authenticationService.loginUserInfo() } catch { diff --git a/harmonie/Views/Authentication/LoginView.swift b/harmonie/Views/Authentication/LoginView.swift index 49ac6de..84e246c 100644 --- a/harmonie/Views/Authentication/LoginView.swift +++ b/harmonie/Views/Authentication/LoginView.swift @@ -15,15 +15,14 @@ struct LoginView: View { @State private var password = "" @State private var isPresentedSecurityPopover = false @State private var isPresentedSavingPasswordPopover = false - @State private var isInInitializing = true + @State private var isRequesting = false + @State private var isReady = false private let titleFont = "Avenir Next" var body: some View { @Bindable var appVM = appVM NavigationStack { - if isInInitializing { - ProgressScreen() - } else { + if isReady { VStack(spacing: 32) { title VStack(spacing: 16) { @@ -38,11 +37,13 @@ struct LoginView: View { OtpView() .navigationBarBackButtonHidden() } + } else { + ProgressScreen() } } .ignoresSafeArea(.keyboard) .task { - defer { isInInitializing = false } + defer { isReady = true } guard isSavedOnKeyChain, !username.isEmpty else { return } guard let password = await KeychainUtil.shared.getPassword(for: username) else { return } self.password = password @@ -121,9 +122,11 @@ struct LoginView: View { private var enterButton: some View { AsyncButton { + defer { isRequesting = false } + isRequesting = true await appVM.login(credential: cledential, isSavedOnKeyChain: isSavedOnKeyChain) } label: { - if appVM.isLoggingIn { + if isRequesting { ProgressView() } else { Text("Enter") @@ -135,7 +138,7 @@ struct LoginView: View { } private var isDisabledEnterButton: Bool { - appVM.isLoggingIn || username.count < 4 || password.count < 8 + isRequesting || username.count < 4 || password.count < 8 } } diff --git a/harmonie/Views/Favorite/FavoritesView.swift b/harmonie/Views/Favorite/FavoritesView.swift index af10c8b..6d4b3ea 100644 --- a/harmonie/Views/Favorite/FavoritesView.swift +++ b/harmonie/Views/Favorite/FavoritesView.swift @@ -26,7 +26,7 @@ struct FavoritesView: View { } } .overlay { - if appVM.isLoggingIn { + if appVM.isRequesting { ProgressScreen() } else if favoriteVM.isSelectedEmpty { ContentUnavailableView { From feee2bca7f03504a3f722dc92b9f373b9f18cbc2 Mon Sep 17 00:00:00 2001 From: makinosp Date: Sat, 26 Oct 2024 20:51:38 +0900 Subject: [PATCH 2/6] refact: code refactoring --- harmonie/Views/Authentication/LoginView.swift | 6 +++++- harmonie/Views/Favorite/FavoritesView.swift | 4 +--- harmonie/Views/Friend/FriendsListView.swift | 7 +++---- harmonie/Views/Location/LocationsView.swift | 4 +--- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/harmonie/Views/Authentication/LoginView.swift b/harmonie/Views/Authentication/LoginView.swift index 84e246c..2a5b6a6 100644 --- a/harmonie/Views/Authentication/LoginView.swift +++ b/harmonie/Views/Authentication/LoginView.swift @@ -44,13 +44,17 @@ struct LoginView: View { .ignoresSafeArea(.keyboard) .task { defer { isReady = true } - guard isSavedOnKeyChain, !username.isEmpty else { return } + guard isSettedLocalData else { return } guard let password = await KeychainUtil.shared.getPassword(for: username) else { return } self.password = password await appVM.login(credential: cledential, isSavedOnKeyChain: isSavedOnKeyChain) } } + private var isSettedLocalData: Bool { + isSavedOnKeyChain && !username.isEmpty + } + private var cledential: Credential { Credential(username: username, password: password) } diff --git a/harmonie/Views/Favorite/FavoritesView.swift b/harmonie/Views/Favorite/FavoritesView.swift index 6d4b3ea..453a215 100644 --- a/harmonie/Views/Favorite/FavoritesView.swift +++ b/harmonie/Views/Favorite/FavoritesView.swift @@ -26,9 +26,7 @@ struct FavoritesView: View { } } .overlay { - if appVM.isRequesting { - ProgressScreen() - } else if favoriteVM.isSelectedEmpty { + if favoriteVM.isSelectedEmpty { ContentUnavailableView { Label("No Favorites", systemImage: IconSet.favorite.systemName) } diff --git a/harmonie/Views/Friend/FriendsListView.swift b/harmonie/Views/Friend/FriendsListView.swift index b699868..04033cc 100644 --- a/harmonie/Views/Friend/FriendsListView.swift +++ b/harmonie/Views/Friend/FriendsListView.swift @@ -5,19 +5,18 @@ // Created by makinosp on 2024/09/16. // +import MemberwiseInit import SwiftUI +@MemberwiseInit struct FriendsListView: View { @Environment(\.isSearching) private var isSearching @Environment(AppViewModel.self) var appVM @Environment(FriendViewModel.self) var friendVM @Environment(FavoriteViewModel.self) var favoriteVM + @InitWrapper(.internal, type: Binding) @Binding private var selected: String? - init(selected: Binding) { - _selected = selected - } - var body: some View { List(friendVM.filterResultFriends, selection: $selected) { friend in Label { diff --git a/harmonie/Views/Location/LocationsView.swift b/harmonie/Views/Location/LocationsView.swift index 2ab9166..fe54d26 100644 --- a/harmonie/Views/Location/LocationsView.swift +++ b/harmonie/Views/Location/LocationsView.swift @@ -72,9 +72,7 @@ struct LocationsView: View { inPrivateInstance } .overlay { - if friendVM.isRequesting { - ProgressScreen() - } else if friendVM.friendsLocations.isEmpty { + if friendVM.friendsLocations.isEmpty { ContentUnavailableView { Label("No Friend Location", systemImage: IconSet.friends.systemName) } From c2b14d21a71c0e7f69054ba061bba0631eb2b316 Mon Sep 17 00:00:00 2001 From: makinosp Date: Sat, 26 Oct 2024 22:51:02 +0900 Subject: [PATCH 3/6] feat: store tab selection in UserDefaults --- harmonie/Utils/Constants.swift | 1 + harmonie/Views/Authentication/LoginView.swift | 32 +++++++++---------- harmonie/Views/MainTabView.swift | 8 +++-- 3 files changed, 22 insertions(+), 19 deletions(-) diff --git a/harmonie/Utils/Constants.swift b/harmonie/Utils/Constants.swift index 72c0bb7..eb1f2c1 100644 --- a/harmonie/Utils/Constants.swift +++ b/harmonie/Utils/Constants.swift @@ -11,6 +11,7 @@ enum Constants { enum Keys: String { case isSavedOnKeyChain case username + case tabSelection } enum MaxCountInFavoriteList: Int, CustomStringConvertible { diff --git a/harmonie/Views/Authentication/LoginView.swift b/harmonie/Views/Authentication/LoginView.swift index 2a5b6a6..da46906 100644 --- a/harmonie/Views/Authentication/LoginView.swift +++ b/harmonie/Views/Authentication/LoginView.swift @@ -22,26 +22,26 @@ struct LoginView: View { var body: some View { @Bindable var appVM = appVM NavigationStack { - if isReady { - VStack(spacing: 32) { - title - VStack(spacing: 16) { - loginFields - keychainToggle - enterButton - } + VStack(spacing: 32) { + title + VStack(spacing: 16) { + loginFields + keychainToggle + enterButton } - .frame(maxWidth: 560) - .padding(.horizontal, 32) - .navigationDestination(item: $appVM.verifyType) { _ in - OtpView() - .navigationBarBackButtonHidden() - } - } else { - ProgressScreen() + } + .frame(maxWidth: 560) + .padding(.horizontal, 32) + .navigationDestination(item: $appVM.verifyType) { _ in + OtpView() } } .ignoresSafeArea(.keyboard) + .overlay { + if !isReady { + ProgressScreen() + } + } .task { defer { isReady = true } guard isSettedLocalData else { return } diff --git a/harmonie/Views/MainTabView.swift b/harmonie/Views/MainTabView.swift index f08c12b..255368c 100644 --- a/harmonie/Views/MainTabView.swift +++ b/harmonie/Views/MainTabView.swift @@ -34,6 +34,8 @@ struct MainTabView: View { @Environment(AppViewModel.self) var appVM: AppViewModel @Environment(FriendViewModel.self) var friendVM: FriendViewModel @Environment(FavoriteViewModel.self) var favoriteVM: FavoriteViewModel + @AppStorage(Constants.Keys.tabSelection.rawValue) + private var selection: MainTabViewSegment = .social var body: some View { Group { @@ -61,7 +63,7 @@ struct MainTabView: View { } private var tabViewLegacy: some View { - TabView { + TabView(selection: $selection) { ForEach(MainTabViewSegment.allCases) { tabSegment in tabSegment.content .tag(tabSegment) @@ -73,8 +75,8 @@ struct MainTabView: View { } @available(iOS 18, *) private var tabView: some View { - TabView { - ForEach(MainTabViewSegment.allCases) { $0.tab } + TabView(selection: $selection) { + return ForEach(MainTabViewSegment.allCases) { $0.tab } } .tabViewStyle(.sidebarAdaptable) } From 3b5752a5320cc14c103a5600af68a2748ac81d09 Mon Sep 17 00:00:00 2001 From: makinosp Date: Sun, 27 Oct 2024 16:01:05 +0900 Subject: [PATCH 4/6] feat: storing UserData via AppStorage --- harmonie/Utils/Constants.swift | 1 + harmonie/Views/MainTabView.swift | 32 +++++++++++++++++++++++--------- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/harmonie/Utils/Constants.swift b/harmonie/Utils/Constants.swift index eb1f2c1..c1961da 100644 --- a/harmonie/Utils/Constants.swift +++ b/harmonie/Utils/Constants.swift @@ -11,6 +11,7 @@ enum Constants { enum Keys: String { case isSavedOnKeyChain case username + case userData case tabSelection } diff --git a/harmonie/Views/MainTabView.swift b/harmonie/Views/MainTabView.swift index 255368c..0a68957 100644 --- a/harmonie/Views/MainTabView.swift +++ b/harmonie/Views/MainTabView.swift @@ -24,8 +24,8 @@ extension MainTabViewSegment { } @available(iOS 18, *) - var tab: Tab { - Tab(description, systemImage: icon.systemName) { content } + var tab: some TabContent { + Tab(description, systemImage: icon.systemName, value: self) { content } } } @@ -34,8 +34,8 @@ struct MainTabView: View { @Environment(AppViewModel.self) var appVM: AppViewModel @Environment(FriendViewModel.self) var friendVM: FriendViewModel @Environment(FavoriteViewModel.self) var favoriteVM: FavoriteViewModel - @AppStorage(Constants.Keys.tabSelection.rawValue) - private var selection: MainTabViewSegment = .social + @AppStorage(Constants.Keys.tabSelection.rawValue) private var selection: MainTabViewSegment = .social + @AppStorage(Constants.Keys.userData.rawValue) private var userData = "" var body: some View { Group { @@ -53,15 +53,29 @@ struct MainTabView: View { Task { await fetchFavoritesTask() } } .onChange(of: scenePhase) { - if scenePhase == .active { - Task { - if await appVM.login() == nil { return } - appVM.step = .loggingIn - } + scenePhaseHandler(scenePhase) + } + } + + private func scenePhaseHandler(_ scenePhase: ScenePhase) { + switch scenePhase { + case .active: + restoreUserData() + Task { + if await appVM.login() == nil { return } } + case .background, .inactive: + guard let user = appVM.user else { return } + userData = user.rawValue + @unknown default: break } } + private func restoreUserData() { + guard let user = User(rawValue: userData) else { return } + appVM.user = user + } + private var tabViewLegacy: some View { TabView(selection: $selection) { ForEach(MainTabViewSegment.allCases) { tabSegment in From f7b0dc2d7cb95855a2a9379966d238603a9ef133 Mon Sep 17 00:00:00 2001 From: makinosp Date: Sun, 27 Oct 2024 16:01:20 +0900 Subject: [PATCH 5/6] refact: code refactoring --- harmonie/Models/MainTabViewSegment.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/harmonie/Models/MainTabViewSegment.swift b/harmonie/Models/MainTabViewSegment.swift index 711844c..598fb8a 100644 --- a/harmonie/Models/MainTabViewSegment.swift +++ b/harmonie/Models/MainTabViewSegment.swift @@ -22,7 +22,7 @@ extension MainTabViewSegment: CustomStringConvertible { } extension MainTabViewSegment: Identifiable { - var id: Int { hashValue } + var id: String { rawValue } } extension MainTabViewSegment { From 155c710e87c2eb8491055c3bba209e43c7f49416 Mon Sep 17 00:00:00 2001 From: makinosp Date: Sun, 27 Oct 2024 16:01:43 +0900 Subject: [PATCH 6/6] update: package dependencies --- .../project.xcworkspace/xcshareddata/swiftpm/Package.resolved | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Harmonie.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Harmonie.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 2b94f38..cf6f79b 100644 --- a/Harmonie.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Harmonie.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -52,7 +52,7 @@ "location" : "https://github.com/makinosp/vrckit", "state" : { "branch" : "develop", - "revision" : "94cf3114e97353a9302339cd073b3f1468c6e1ee" + "revision" : "fab9dbea46bb5dc755eb815a9a9529ff971949cb" } } ],