From f8c3b4d1fc5696840b4d3fd2bcda9033083346d7 Mon Sep 17 00:00:00 2001 From: makinosp Date: Fri, 1 Nov 2024 22:14:05 +0900 Subject: [PATCH 01/11] refactor: code refactoring --- .../Previews/Services/AuthenticationPreviewService.swift | 6 ++---- harmonie/Previews/Services/FriendPreviewService.swift | 6 ++---- harmonie/Previews/Services/InstancePreviewService.swift | 6 ++---- harmonie/Previews/Services/UserNotePreviewService.swift | 6 ++---- harmonie/Previews/Services/UserPreviewService.swift | 6 ++---- harmonie/Previews/Services/WorldPreviewService.swift | 8 +++----- 6 files changed, 13 insertions(+), 25 deletions(-) diff --git a/harmonie/Previews/Services/AuthenticationPreviewService.swift b/harmonie/Previews/Services/AuthenticationPreviewService.swift index e61f4f76..1ec0d412 100644 --- a/harmonie/Previews/Services/AuthenticationPreviewService.swift +++ b/harmonie/Previews/Services/AuthenticationPreviewService.swift @@ -5,15 +5,13 @@ // Created by makinosp on 2024/07/06. // +import MemberwiseInit import VRCKit +@MemberwiseInit final actor AuthenticationPreviewService: APIService, AuthenticationServiceProtocol { let client: APIClient - init(client: APIClient) { - self.client = client - } - func exists(userId: String) async throws -> Bool { true } func loginUserInfo() async throws -> Either { diff --git a/harmonie/Previews/Services/FriendPreviewService.swift b/harmonie/Previews/Services/FriendPreviewService.swift index cd6dbdc7..94bf0e08 100644 --- a/harmonie/Previews/Services/FriendPreviewService.swift +++ b/harmonie/Previews/Services/FriendPreviewService.swift @@ -5,15 +5,13 @@ // Created by makinosp on 2024/07/07. // +import MemberwiseInit import VRCKit +@MemberwiseInit final actor FriendPreviewService: APIService, FriendServiceProtocol { let client: APIClient - init(client: APIClient) { - self.client = client - } - func fetchFriends(offset: Int, n: Int, offline: Bool) async throws -> [Friend] { offline ? PreviewDataProvider.shared.offlineFriends : PreviewDataProvider.shared.onlineFriends } diff --git a/harmonie/Previews/Services/InstancePreviewService.swift b/harmonie/Previews/Services/InstancePreviewService.swift index 09949bcd..27fd9f07 100644 --- a/harmonie/Previews/Services/InstancePreviewService.swift +++ b/harmonie/Previews/Services/InstancePreviewService.swift @@ -5,15 +5,13 @@ // Created by makinosp on 2024/07/09. // +import MemberwiseInit import VRCKit +@MemberwiseInit final actor InstancePreviewService: APIService, InstanceServiceProtocol { let client: APIClient - init(client: APIClient) { - self.client = client - } - func fetchInstance(location: String) async throws -> Instance { PreviewDataProvider.shared.instances[0] } diff --git a/harmonie/Previews/Services/UserNotePreviewService.swift b/harmonie/Previews/Services/UserNotePreviewService.swift index 57861686..f28b8878 100644 --- a/harmonie/Previews/Services/UserNotePreviewService.swift +++ b/harmonie/Previews/Services/UserNotePreviewService.swift @@ -6,15 +6,13 @@ // import Foundation +import MemberwiseInit import VRCKit +@MemberwiseInit final actor UserNotePreviewService: APIService, UserNoteServiceProtocol { let client: APIClient - init(client: APIClient) { - self.client = client - } - func updateUserNote( targetUserId: String, note: String diff --git a/harmonie/Previews/Services/UserPreviewService.swift b/harmonie/Previews/Services/UserPreviewService.swift index cbc25012..59f958d3 100644 --- a/harmonie/Previews/Services/UserPreviewService.swift +++ b/harmonie/Previews/Services/UserPreviewService.swift @@ -5,15 +5,13 @@ // Created by makinosp on 2024/07/14. // +import MemberwiseInit import VRCKit +@MemberwiseInit final actor UserPreviewService: APIService, UserServiceProtocol { let client: APIClient - init(client: APIClient) { - self.client = client - } - func fetchUser(userId: String) async throws -> UserDetail { PreviewDataProvider.shared.userDetails.first { $0.id == userId }! } diff --git a/harmonie/Previews/Services/WorldPreviewService.swift b/harmonie/Previews/Services/WorldPreviewService.swift index 8bd5dd05..e372aba5 100644 --- a/harmonie/Previews/Services/WorldPreviewService.swift +++ b/harmonie/Previews/Services/WorldPreviewService.swift @@ -6,17 +6,15 @@ // import Foundation +import MemberwiseInit import VRCKit +@MemberwiseInit final actor WorldPreviewService: APIService, WorldServiceProtocol { let client: APIClient - init(client: APIClient) { - self.client = client - } - func fetchWorld(worldId: String) async throws -> World { - PreviewDataProvider.world + PreviewDataProvider.bar } func fetchFavoritedWorlds() async throws -> [FavoriteWorld] { From 4b09b1f3a190e0b752afe18091f1227f179253a3 Mon Sep 17 00:00:00 2001 From: makinosp Date: Sat, 2 Nov 2024 12:50:54 +0900 Subject: [PATCH 02/11] feat: improvement preview data --- harmonie/Previews/Friend.swift | 30 +++++++------- harmonie/Previews/Instance.swift | 16 ++++---- harmonie/Previews/PreviewDataProvider.swift | 15 +++---- .../Services/WorldPreviewService.swift | 2 +- harmonie/Previews/World.swift | 41 +++++++++++-------- harmonie/Views/World/WorldView.swift | 2 +- 6 files changed, 59 insertions(+), 47 deletions(-) diff --git a/harmonie/Previews/Friend.swift b/harmonie/Previews/Friend.swift index 4278c07b..2a829804 100644 --- a/harmonie/Previews/Friend.swift +++ b/harmonie/Previews/Friend.swift @@ -9,7 +9,10 @@ import Foundation import VRCKit extension PreviewDataProvider { - typealias FriendSet = (friend: Friend, userDetail: UserDetail) + struct FriendSet { + let friend: Friend + let userDetail: UserDetail + } var onlineFriends: [Friend] { friends.filter { $0.status != .offline } @@ -19,26 +22,24 @@ extension PreviewDataProvider { friends.filter { $0.status == .offline } } - static func friend(id: UUID, location: Location, status: UserStatus) -> Friend { - Friend(id: id, location: location, status: status) - } - static var friend: Friend { Friend(id: UUID(), location: .offline, status: .offline) } +} - static func friendSet( +extension PreviewDataProvider.FriendSet { + init( id: UUID, location: Location, status: UserStatus - ) -> FriendSet { - ( - Friend( + ) { + self.init( + friend: Friend( id: id, location: location, status: status ), - PreviewDataProvider.userDetail( + userDetail: PreviewDataProvider.userDetail( id: id, location: location, state: status == .offline ? .offline : .active, @@ -51,6 +52,7 @@ extension PreviewDataProvider { private extension Friend { init( id: UUID, + avatarImageUrl: URL? = PreviewDataProvider.iconImageUrl, displayName: String = PreviewString.Name.randomValue, location: Location, status: UserStatus @@ -58,19 +60,19 @@ private extension Friend { self.init( bio: "Biography", bioLinks: SafeDecodingArray(), - avatarImageUrl: PreviewDataProvider.iconImageUrl, - avatarThumbnailUrl: PreviewDataProvider.iconImageUrl, + avatarImageUrl: avatarImageUrl, + avatarThumbnailUrl: avatarImageUrl, displayName: displayName, id: "usr_\(id.uuidString)", isFriend: true, lastLogin: Date(), lastPlatform: "standalonewindows", platform: .blank, - profilePicOverride: PreviewDataProvider.iconImageUrl, + profilePicOverride: nil, status: status, statusDescription: "", tags: UserTags(), - userIcon: PreviewDataProvider.iconImageUrl, + userIcon: nil, location: location, friendKey: "" ) diff --git a/harmonie/Previews/Instance.swift b/harmonie/Previews/Instance.swift index bb9340ed..01147133 100644 --- a/harmonie/Previews/Instance.swift +++ b/harmonie/Previews/Instance.swift @@ -10,25 +10,27 @@ import VRCKit extension PreviewDataProvider { static func instance(worldId: UUID, instanceId: Int) -> Instance { - Instance(worldId: worldId, instanceId: instanceId) + Instance(world: bar) } static func instance() -> Instance { - Instance(worldId: UUID(), instanceId: 0) + Instance(world: bar) } + + static let instance1 = Instance(world: bar) } private extension Instance { - init(worldId: UUID, instanceId: Int) { + init(world: World, instanceId: Int = 0) { self.init( active: true, capacity: 32, full: false, groupAccessType: nil, - id: "wrld_\(worldId):\(instanceId)", + id: "\(world.id):\(instanceId)", instanceId: instanceId.description, - location: .id("wrld_\(worldId.uuidString)"), - name: "DummyInstance_\(instanceId)", + location: .id(world.id), + name: world.name, ownerId: "usr_\(UUID().uuidString)", permanent: false, platforms: Platforms(), @@ -37,7 +39,7 @@ private extension Instance { tags: [], type: [.public, .friends].randomElement() ?? .public, userCount: 0, - world: PreviewDataProvider.generateWorld(worldId: worldId) + world: world ) } } diff --git a/harmonie/Previews/PreviewDataProvider.swift b/harmonie/Previews/PreviewDataProvider.swift index 01b41385..8ed9092a 100644 --- a/harmonie/Previews/PreviewDataProvider.swift +++ b/harmonie/Previews/PreviewDataProvider.swift @@ -15,23 +15,24 @@ final class PreviewDataProvider: Sendable { let userDetails: [UserDetail] let instances: [Instance] - static let iconImageUrl = URL(string: "https://www.mediafire.com/convkey/e2dd/ksfjh96ukjtwhuczg.jpg") + static let imageBaseURL = "https://images2.imgbox.com" + static let iconImageUrl = URL(string: "\(imageBaseURL)/44/8f/IQToHkKa_o.jpg") private init() { - let instance = Self.instance(worldId: UUID(), instanceId: 0) + let instance = Self.instance1 let onlineFriendsSet: [FriendSet] = (0..<50).map { count in let id = UUID() return switch count { case ..<10: - Self.friendSet(id: id, location: .id(instance.id), status: .active) + FriendSet(id: id, location: .id(instance.id), status: .active) case ..<20: - Self.friendSet(id: id, location: .private, status: .askMe) + FriendSet(id: id, location: .private, status: .askMe) case ..<30: - Self.friendSet(id: id, location: .id(instance.id), status: .joinMe) + FriendSet(id: id, location: .id(instance.id), status: .joinMe) case ..<40: - Self.friendSet(id: id, location: .private, status: .busy) + FriendSet(id: id, location: .private, status: .busy) default: - Self.friendSet(id: id, location: .offline, status: .offline) + FriendSet(id: id, location: .offline, status: .offline) } } var userDetails = onlineFriendsSet.map(\.userDetail) diff --git a/harmonie/Previews/Services/WorldPreviewService.swift b/harmonie/Previews/Services/WorldPreviewService.swift index e372aba5..112760e5 100644 --- a/harmonie/Previews/Services/WorldPreviewService.swift +++ b/harmonie/Previews/Services/WorldPreviewService.swift @@ -20,7 +20,7 @@ final actor WorldPreviewService: APIService, WorldServiceProtocol { func fetchFavoritedWorlds() async throws -> [FavoriteWorld] { (0..<100).map { number in FavoriteWorld( - world: PreviewDataProvider.world, + world: PreviewDataProvider.casino, favoriteId: "fvrt_\(UUID())", favoriteGroup: number.description ) diff --git a/harmonie/Previews/World.swift b/harmonie/Previews/World.swift index 35451b80..87f19afd 100644 --- a/harmonie/Previews/World.swift +++ b/harmonie/Previews/World.swift @@ -9,24 +9,31 @@ import Foundation import VRCKit extension PreviewDataProvider { - static var world: World { - generateWorld(worldId: UUID()) - } + static let bar = World( + id: UUID(), + name: "Bar", + description: "Bar", + imageUrl: URL(string: "\(imageBaseURL)/7a/95/kLHkm3Ez_o.jpg"), + thumbnailImageUrl: URL(string: "\(imageBaseURL)/7a/95/kLHkm3Ez_o.jpg"), + organization: "", + favorites: 50, + visits: 100, + popularity: 10, + heat: 4 + ) - static func generateWorld(worldId: UUID) -> World { - World( - id: worldId, - name: "Dummy World", - description: "Dummy World", - imageUrl: Const.privateWorldImageUrl, - thumbnailImageUrl: Const.privateWorldImageUrl, - organization: "", - favorites: 1, - visits: 1, - popularity: 1, - heat: 1 - ) - } + static let casino = World( + id: UUID(), + name: "Casino", + description: "Casino", + imageUrl: URL(string: "\(imageBaseURL)/83/48/NtBOJpF1_o.jpg"), + thumbnailImageUrl: URL(string: "\(imageBaseURL)/83/48/NtBOJpF1_o.jpg"), + organization: "", + favorites: 50, + visits: 75, + popularity: 5, + heat: 3 + ) } extension World { diff --git a/harmonie/Views/World/WorldView.swift b/harmonie/Views/World/WorldView.swift index 7330d334..0aad01ae 100644 --- a/harmonie/Views/World/WorldView.swift +++ b/harmonie/Views/World/WorldView.swift @@ -178,7 +178,7 @@ struct WorldView: View { #Preview { PreviewContainer { NavigationStack { - WorldView(world: PreviewDataProvider.world) + WorldView(world: PreviewDataProvider.casino) } } } From d2e7ffafce68354b5104b012bdc63be5c9b5338b Mon Sep 17 00:00:00 2001 From: makinosp Date: Sat, 2 Nov 2024 13:04:02 +0900 Subject: [PATCH 03/11] refact: directory structure --- harmonie/Previews/{ => Models}/Friend.swift | 0 harmonie/Previews/{ => Models}/FriendsLocation.swift | 0 harmonie/Previews/{ => Models}/Instance.swift | 0 harmonie/Previews/{ => Models}/PreviewString.swift | 0 harmonie/Previews/{ => Models}/UserDetail.swift | 0 harmonie/Previews/{ => Models}/World.swift | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename harmonie/Previews/{ => Models}/Friend.swift (100%) rename harmonie/Previews/{ => Models}/FriendsLocation.swift (100%) rename harmonie/Previews/{ => Models}/Instance.swift (100%) rename harmonie/Previews/{ => Models}/PreviewString.swift (100%) rename harmonie/Previews/{ => Models}/UserDetail.swift (100%) rename harmonie/Previews/{ => Models}/World.swift (100%) diff --git a/harmonie/Previews/Friend.swift b/harmonie/Previews/Models/Friend.swift similarity index 100% rename from harmonie/Previews/Friend.swift rename to harmonie/Previews/Models/Friend.swift diff --git a/harmonie/Previews/FriendsLocation.swift b/harmonie/Previews/Models/FriendsLocation.swift similarity index 100% rename from harmonie/Previews/FriendsLocation.swift rename to harmonie/Previews/Models/FriendsLocation.swift diff --git a/harmonie/Previews/Instance.swift b/harmonie/Previews/Models/Instance.swift similarity index 100% rename from harmonie/Previews/Instance.swift rename to harmonie/Previews/Models/Instance.swift diff --git a/harmonie/Previews/PreviewString.swift b/harmonie/Previews/Models/PreviewString.swift similarity index 100% rename from harmonie/Previews/PreviewString.swift rename to harmonie/Previews/Models/PreviewString.swift diff --git a/harmonie/Previews/UserDetail.swift b/harmonie/Previews/Models/UserDetail.swift similarity index 100% rename from harmonie/Previews/UserDetail.swift rename to harmonie/Previews/Models/UserDetail.swift diff --git a/harmonie/Previews/World.swift b/harmonie/Previews/Models/World.swift similarity index 100% rename from harmonie/Previews/World.swift rename to harmonie/Previews/Models/World.swift From 3ff6557dc5369c63bfd9d627574cce0c3c42784c Mon Sep 17 00:00:00 2001 From: makinosp Date: Sat, 2 Nov 2024 13:51:12 +0900 Subject: [PATCH 04/11] feat: improvement preview data --- harmonie/Previews/Models/Instance.swift | 1 + harmonie/Previews/PreviewDataProvider.swift | 16 +++++++++------- .../Services/InstancePreviewService.swift | 18 ++++++++++++++++-- 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/harmonie/Previews/Models/Instance.swift b/harmonie/Previews/Models/Instance.swift index 01147133..a4e85465 100644 --- a/harmonie/Previews/Models/Instance.swift +++ b/harmonie/Previews/Models/Instance.swift @@ -18,6 +18,7 @@ extension PreviewDataProvider { } static let instance1 = Instance(world: bar) + static let instance2 = Instance(world: casino) } private extension Instance { diff --git a/harmonie/Previews/PreviewDataProvider.swift b/harmonie/Previews/PreviewDataProvider.swift index 8ed9092a..29667ea1 100644 --- a/harmonie/Previews/PreviewDataProvider.swift +++ b/harmonie/Previews/PreviewDataProvider.swift @@ -13,34 +13,36 @@ final class PreviewDataProvider: Sendable { private let previewUserId = UUID() let friends: [Friend] let userDetails: [UserDetail] - let instances: [Instance] static let imageBaseURL = "https://images2.imgbox.com" static let iconImageUrl = URL(string: "\(imageBaseURL)/44/8f/IQToHkKa_o.jpg") private init() { - let instance = Self.instance1 let onlineFriendsSet: [FriendSet] = (0..<50).map { count in let id = UUID() return switch count { + case ..<5: + FriendSet(id: id, location: .id(Self.instance1.id), status: .active) case ..<10: - FriendSet(id: id, location: .id(instance.id), status: .active) + FriendSet(id: id, location: .id(Self.instance2.id), status: .active) + case ..<15: + FriendSet(id: id, location: .id(Self.instance2.id), status: .joinMe) case ..<20: FriendSet(id: id, location: .private, status: .askMe) + case ..<25: + FriendSet(id: id, location: .id(Self.instance1.id), status: .joinMe) case ..<30: - FriendSet(id: id, location: .id(instance.id), status: .joinMe) - case ..<40: FriendSet(id: id, location: .private, status: .busy) default: FriendSet(id: id, location: .offline, status: .offline) } } + var userDetails = onlineFriendsSet.map(\.userDetail) - userDetails.append(PreviewDataProvider.previewUserDetail(id: previewUserId, instance: instance)) + userDetails.append(PreviewDataProvider.previewUserDetail(id: previewUserId, instance: Self.instance1)) self.userDetails = userDetails self.friends = onlineFriendsSet.map(\.friend) - self.instances = [instance] } var previewUser: User { diff --git a/harmonie/Previews/Services/InstancePreviewService.swift b/harmonie/Previews/Services/InstancePreviewService.swift index 27fd9f07..eec7fc25 100644 --- a/harmonie/Previews/Services/InstancePreviewService.swift +++ b/harmonie/Previews/Services/InstancePreviewService.swift @@ -13,10 +13,24 @@ final actor InstancePreviewService: APIService, InstanceServiceProtocol { let client: APIClient func fetchInstance(location: String) async throws -> Instance { - PreviewDataProvider.shared.instances[0] + switch location { + case PreviewDataProvider.instance1.id: + PreviewDataProvider.instance1 + case PreviewDataProvider.instance2.id: + PreviewDataProvider.instance2 + default: + PreviewDataProvider.instance1 + } } func fetchInstance(worldId: String, instanceId: String) async throws -> Instance { - PreviewDataProvider.shared.instances[0] + switch instanceId { + case PreviewDataProvider.instance1.instanceId: + PreviewDataProvider.instance1 + case PreviewDataProvider.instance2.instanceId: + PreviewDataProvider.instance2 + default: + PreviewDataProvider.instance1 + } } } From b3d33c289a43d7c79633819cf0bff4f67e104785 Mon Sep 17 00:00:00 2001 From: makinosp Date: Sat, 2 Nov 2024 14:14:39 +0900 Subject: [PATCH 05/11] feat: improvement PreviewData --- .../Previews/Services/FavoritePreviewService.swift | 4 ++++ .../Previews/Services/WorldPreviewService.swift | 14 +++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/harmonie/Previews/Services/FavoritePreviewService.swift b/harmonie/Previews/Services/FavoritePreviewService.swift index a51e6fb5..9bb6ba1b 100644 --- a/harmonie/Previews/Services/FavoritePreviewService.swift +++ b/harmonie/Previews/Services/FavoritePreviewService.swift @@ -39,6 +39,10 @@ final actor FavoritePreviewService: APIService, FavoriteServiceProtocol { } } + func listFavorites(n: Int, offset: Int, type: FavoriteType, tag: String?) async throws -> [Favorite] { + [] + } + func fetchFavoriteList(favoriteGroups: [FavoriteGroup], type: FavoriteType) async throws -> [FavoriteList] { [] } diff --git a/harmonie/Previews/Services/WorldPreviewService.swift b/harmonie/Previews/Services/WorldPreviewService.swift index 112760e5..34017276 100644 --- a/harmonie/Previews/Services/WorldPreviewService.swift +++ b/harmonie/Previews/Services/WorldPreviewService.swift @@ -14,7 +14,14 @@ final actor WorldPreviewService: APIService, WorldServiceProtocol { let client: APIClient func fetchWorld(worldId: String) async throws -> World { - PreviewDataProvider.bar + switch worldId { + case PreviewDataProvider.bar.id: + PreviewDataProvider.bar + case PreviewDataProvider.casino.id: + PreviewDataProvider.casino + default: + PreviewDataProvider.bar + } } func fetchFavoritedWorlds() async throws -> [FavoriteWorld] { @@ -26,4 +33,9 @@ final actor WorldPreviewService: APIService, WorldServiceProtocol { ) } } + + func fetchFavoritedWorlds(n: Int, offset: Int) async throws -> [FavoriteWorld] { + // No implementation required + [] + } } From dc59ab5d889ba4335b2281c2af510129c418d4e3 Mon Sep 17 00:00:00 2001 From: makinosp Date: Sat, 2 Nov 2024 14:15:32 +0900 Subject: [PATCH 06/11] 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 8477ad3d..5fb4450a 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" : "b2c6886ea0e8e9ee836dd62450caa619e293f3f1" + "revision" : "b93b92892aa629919f87e9be78d2bc5439cca3ad" } } ], From d38e277932de156b94f59f8aea90d57d5e5c81f6 Mon Sep 17 00:00:00 2001 From: makinosp Date: Sat, 2 Nov 2024 14:44:52 +0900 Subject: [PATCH 07/11] feat: improvement LocationsView, refreshable --- harmonie/Models/SegmentModel.swift | 11 +---- harmonie/ViewModels/FavoriteViewModel.swift | 12 ------ harmonie/Views/Favorite/FavoritesView.swift | 47 ++++++++++++++++----- harmonie/Views/Location/LocationsView.swift | 2 - 4 files changed, 39 insertions(+), 33 deletions(-) diff --git a/harmonie/Models/SegmentModel.swift b/harmonie/Models/SegmentModel.swift index 2732e198..0bc1e0bd 100644 --- a/harmonie/Models/SegmentModel.swift +++ b/harmonie/Models/SegmentModel.swift @@ -7,20 +7,14 @@ import SwiftUI -enum FavoriteViewSegment: String { - case all, friends, world +enum FavoriteViewSegment: String, CaseIterable { + case friends, world } extension FavoriteViewSegment: Identifiable { var id: Int { hashValue } } -extension FavoriteViewSegment: CaseIterable { - var allCases: [Self] { - [.all, .friends, .world] - } -} - extension FavoriteViewSegment: CustomStringConvertible { var localizedString: LocalizedStringResource { LocalizedStringResource(stringLiteral: rawValue.capitalized) @@ -34,7 +28,6 @@ extension FavoriteViewSegment: CustomStringConvertible { extension FavoriteViewSegment { var icon: Iconizable { switch self { - case .all: IconSet.favoriteSquares case .friends: IconSet.friends case .world: IconSet.world } diff --git a/harmonie/ViewModels/FavoriteViewModel.swift b/harmonie/ViewModels/FavoriteViewModel.swift index 22516086..8652d2e2 100644 --- a/harmonie/ViewModels/FavoriteViewModel.swift +++ b/harmonie/ViewModels/FavoriteViewModel.swift @@ -15,7 +15,6 @@ final class FavoriteViewModel { var favoriteGroups: [FavoriteGroup] = [] var favoriteFriends: [FavoriteFriend] = [] var favoriteWorlds: [FavoriteWorld] = [] - var segment: FavoriteViewSegment = .all /// Filters and returns the favorite groups of a specific type. /// - Parameter type: The `FavoriteType` to filter the favorite groups by. @@ -24,17 +23,6 @@ final class FavoriteViewModel { favoriteGroups.filter { $0.type == type } } - var isSelectedEmpty: Bool { - switch segment { - case .all: - favoriteGroups(.friend).isEmpty && favoriteWorldGroups.isEmpty - case .friends: - favoriteGroups(.friend).isEmpty - case .world: - favoriteWorldGroups.isEmpty - } - } - /// Filters the favorite groups by the given set of favorite types, /// and returns a dictionary where the keys are the favorite types. /// - Parameter types: A set of `FavoriteType` values used to filter the favorite groups. diff --git a/harmonie/Views/Favorite/FavoritesView.swift b/harmonie/Views/Favorite/FavoritesView.swift index f4324c58..a35ccfb5 100644 --- a/harmonie/Views/Favorite/FavoritesView.swift +++ b/harmonie/Views/Favorite/FavoritesView.swift @@ -10,23 +10,25 @@ import VRCKit struct FavoritesView: View { @Environment(AppViewModel.self) var appVM + @Environment(FriendViewModel.self) var friendVM @Environment(FavoriteViewModel.self) var favoriteVM @State private var selected: SegmentIdSelection? @State private var columnVisibility: NavigationSplitViewVisibility = .all + @State private var segment: FavoriteViewSegment? var body: some View { @Bindable var favoriteVM = favoriteVM NavigationSplitView(columnVisibility: $columnVisibility) { List(selection: $selected) { - if favoriteVM.segment != .world { + if segment != .world { favoriteFriends } - if favoriteVM.segment != .friends { + if segment != .friends { favoriteWorlds } } .overlay { - if favoriteVM.isSelectedEmpty { + if isSelectedEmpty { ContentUnavailableView { Label("No Favorites", systemImage: IconSet.favorite.systemName) } @@ -34,16 +36,21 @@ struct FavoritesView: View { } } .contentMargins(.top, 8) - .navigationTitle(favoriteVM.segment.description) - .navigationBarTitleDisplayMode(.inline) + .navigationTitle("Favorites") + .navigationBarTitleDisplayMode(.automatic) .toolbarTitleMenu { toolbarTitleMenu } } detail: { detail } .navigationSplitViewStyle(.balanced) + .refreshable { + segment = .none + await fetchFavoriteAction() + } } @ViewBuilder private var toolbarTitleMenu: some View { - @Bindable var favoriteVM = favoriteVM - Picker("", selection: $favoriteVM.segment) { + Picker("", selection: $segment) { + Label("All", systemImage: IconSet.favoriteSquares.systemName) + .tag(Optional.none) ForEach(FavoriteViewSegment.allCases) { segment in Label(segment.description, systemImage: segment.icon.systemName) .tag(segment) @@ -60,8 +67,6 @@ struct FavoritesView: View { case .world: WorldPresentationView(id: selectedContainer.selected.id) .id(selectedContainer.id) - default: - EmptyView() } } else { ContentUnavailableView { @@ -107,7 +112,7 @@ struct FavoritesView: View { } } - var favoriteWorlds: some View { + private var favoriteWorlds: some View { Section("World") { ForEach(favoriteVM.favoriteWorldGroups) { favoriteWorlds in if let group = favoriteWorlds.group { @@ -162,6 +167,28 @@ struct FavoritesView: View { Text(title) } } + + private var isSelectedEmpty: Bool { + switch segment { + case .friends: + favoriteVM.favoriteGroups(.friend).isEmpty + case .world: + favoriteVM.favoriteWorldGroups.isEmpty + case .none: + favoriteVM.favoriteGroups(.friend).isEmpty && favoriteVM.favoriteWorldGroups.isEmpty + } + } + + private func fetchFavoriteAction() async { + do { + try await favoriteVM.fetchFavoriteFriends( + service: appVM.services.favoriteService, + friendVM: friendVM + ) + } catch { + appVM.handleError(error) + } + } } #Preview { diff --git a/harmonie/Views/Location/LocationsView.swift b/harmonie/Views/Location/LocationsView.swift index fca3cca6..86342a2e 100644 --- a/harmonie/Views/Location/LocationsView.swift +++ b/harmonie/Views/Location/LocationsView.swift @@ -80,8 +80,6 @@ struct LocationsView: View { UserDetailPresentationView(selected: selection.selected) case .world: WorldPresentationView(id: selection.selected.id) - default: - EmptyView() } } .id(selection.selected.id) From e8152e66bc5c73013960ce6cfe86c098b5575610 Mon Sep 17 00:00:00 2001 From: makinosp Date: Sat, 2 Nov 2024 14:45:28 +0900 Subject: [PATCH 08/11] update: localization --- harmonie/Localization/Localizable.xcstrings | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/harmonie/Localization/Localizable.xcstrings b/harmonie/Localization/Localizable.xcstrings index a7ac12d4..83405af1 100644 --- a/harmonie/Localization/Localizable.xcstrings +++ b/harmonie/Localization/Localizable.xcstrings @@ -63,6 +63,16 @@ } } }, + "All" : { + "localizations" : { + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "全て" + } + } + } + }, "App Name" : { "localizations" : { "ja" : { From b09c0f8abfe5e9fbf375da8dea69e773e3065511 Mon Sep 17 00:00:00 2001 From: makinosp Date: Sat, 2 Nov 2024 22:59:47 +0900 Subject: [PATCH 09/11] 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 5fb4450a..3ee4457d 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" : "b93b92892aa629919f87e9be78d2bc5439cca3ad" + "revision" : "7c88c46ceaf6d12b048cd03220c844de07206ec2" } } ], From e34e1aa12947caae95fe83e8fb08d2d478b0b384 Mon Sep 17 00:00:00 2001 From: makinosp Date: Sat, 2 Nov 2024 23:00:33 +0900 Subject: [PATCH 10/11] feat: improvement displaying ContentUnavailableView in LocationsView --- harmonie/Views/Location/LocationsView.swift | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/harmonie/Views/Location/LocationsView.swift b/harmonie/Views/Location/LocationsView.swift index 86342a2e..5c1c7352 100644 --- a/harmonie/Views/Location/LocationsView.swift +++ b/harmonie/Views/Location/LocationsView.swift @@ -59,15 +59,13 @@ struct LocationsView: View { LocationDetailView($selection, location: location, instance: instance) } else if let instance = selectedInstance, instance.location.location == .private { PrivateLocationView($selection, friends: instance.location.friends) - } - } - .overlay { - if selectedInstance == nil { + } else { ContentUnavailableView { Label("Select a location", systemImage: IconSet.location.systemName) } } } + .background(Color(.systemGroupedBackground)) .setColumn() } @@ -83,15 +81,13 @@ struct LocationsView: View { } } .id(selection.selected.id) - } - } - .overlay { - if selection == nil { + } else { ContentUnavailableView { Label("Select a friend or world", systemImage: IconSet.info.systemName) } } } + .background(Color(.systemGroupedBackground)) .setColumn() } @@ -156,9 +152,9 @@ extension Location { } } -fileprivate extension View { +private extension View { func setColumn() -> some View { - self.navigationSplitViewColumnWidth( + navigationSplitViewColumnWidth( min: WindowUtil.width * 1 / 3, ideal: WindowUtil.width * 1 / 3, max: WindowUtil.width / 2 From 851f70ab878408a4223b59bd24165d7b2e2cd9f0 Mon Sep 17 00:00:00 2001 From: makinosp Date: Sat, 2 Nov 2024 23:01:19 +0900 Subject: [PATCH 11/11] update: bump up to 0.9.7 --- Harmonie.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Harmonie.xcodeproj/project.pbxproj b/Harmonie.xcodeproj/project.pbxproj index 6fbe6856..4fbeb7ae 100644 --- a/Harmonie.xcodeproj/project.pbxproj +++ b/Harmonie.xcodeproj/project.pbxproj @@ -474,7 +474,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 0.9.6; + MARKETING_VERSION = 0.9.7; PRODUCT_BUNDLE_IDENTIFIER = jp.mknn.harmonie; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; @@ -510,7 +510,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 0.9.6; + MARKETING_VERSION = 0.9.7; PRODUCT_BUNDLE_IDENTIFIER = jp.mknn.harmonie; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES;