diff --git a/Mlem/Views/Shared/Instance/InstanceView.swift b/Mlem/Views/Shared/Instance/InstanceView.swift index a2a562ef6..5633e3f28 100644 --- a/Mlem/Views/Shared/Instance/InstanceView.swift +++ b/Mlem/Views/Shared/Instance/InstanceView.swift @@ -107,7 +107,7 @@ struct InstanceView: View { if let administrators = instance.administrators { Divider() ForEach(administrators, id: \.self) { user in - UserResultView(user) + UserResultView(user, complications: [.instance, .date]) Divider() } } else { diff --git a/Mlem/Views/Tabs/Feeds/CommunityView.swift b/Mlem/Views/Tabs/Feeds/CommunityView.swift index 5d2a1a436..8f703394f 100644 --- a/Mlem/Views/Tabs/Feeds/CommunityView.swift +++ b/Mlem/Views/Tabs/Feeds/CommunityView.swift @@ -118,7 +118,7 @@ struct CommunityView: View { .padding(.top, 15) .background(Color.secondarySystemBackground) ForEach(moderators, id: \.id) { user in - UserResultView(user, communityContext: community) + UserResultView(user, complications: [.instance, .date], communityContext: community) Divider() } Color.secondarySystemBackground diff --git a/Mlem/Views/Tabs/Profile/UserFeedView.swift b/Mlem/Views/Tabs/Profile/UserFeedView.swift index 1bf7303c3..9d748dda4 100644 --- a/Mlem/Views/Tabs/Profile/UserFeedView.swift +++ b/Mlem/Views/Tabs/Profile/UserFeedView.swift @@ -50,7 +50,7 @@ struct UserFeedView: View { .padding(.vertical, 4) Divider() ForEach(communityTracker.items, id: \.uid) { community in - CommunityResultView(community, showTypeLabel: false, trackerCallback: { + CommunityResultView(community, complications: .instanceOnly, trackerCallback: { communityTracker.update(with: $0) }) diff --git a/Mlem/Views/Tabs/Search/RecentSearchesView.swift b/Mlem/Views/Tabs/Search/RecentSearchesView.swift index 4ed143a83..ceb236642 100644 --- a/Mlem/Views/Tabs/Search/RecentSearchesView.swift +++ b/Mlem/Views/Tabs/Search/RecentSearchesView.swift @@ -74,7 +74,7 @@ struct RecentSearchesView: View { if let community = contentModel.wrappedValue as? CommunityModel { CommunityResultView( community, - showTypeLabel: true, + complications: .withTypeLabel, swipeActions: .init(trailingActions: [deleteSwipeAction(contentModel)]), trackerCallback: { contentTracker.update(with: AnyContentModel($0)) @@ -83,7 +83,7 @@ struct RecentSearchesView: View { } else if let user = contentModel.wrappedValue as? UserModel { UserResultView( user, - showTypeLabel: true, + complications: [.type, .instance, .comments], swipeActions: .init(trailingActions: [deleteSwipeAction(contentModel)]), trackerCallback: { contentTracker.update(with: AnyContentModel($0)) diff --git a/Mlem/Views/Tabs/Search/Results/CommunityResultView.swift b/Mlem/Views/Tabs/Search/Results/CommunityResultView.swift index 6891f59e3..b51d2a69e 100644 --- a/Mlem/Views/Tabs/Search/Results/CommunityResultView.swift +++ b/Mlem/Views/Tabs/Search/Results/CommunityResultView.swift @@ -8,14 +8,24 @@ import SwiftUI import Dependencies +enum CommunityComplication: CaseIterable { + case type, instance, subscribers +} + +extension Array where Element == CommunityComplication { + static let withTypeLabel: [CommunityComplication] = [.type, .instance, .subscribers] + static let withoutTypeLabel: [CommunityComplication] = [.instance, .subscribers] + static let instanceOnly: [CommunityComplication] = [.instance] +} + struct CommunityResultView: View { @Dependency(\.apiClient) private var apiClient @Dependency(\.hapticManager) var hapticManager let community: CommunityModel - let showTypeLabel: Bool let trackerCallback: (_ item: CommunityModel) -> Void let swipeActions: SwipeConfiguration? + let complications: [CommunityComplication] @State private var isPresentingConfirmDestructive: Bool = false @State private var confirmationMenuFunction: StandardMenuFunction? @@ -24,12 +34,12 @@ struct CommunityResultView: View { init( _ community: CommunityModel, - showTypeLabel: Bool = false, + complications: [CommunityComplication] = .withoutTypeLabel, swipeActions: SwipeConfiguration? = nil, trackerCallback: @escaping (_ item: CommunityModel) -> Void = { _ in } ) { self.community = community - self.showTypeLabel = showTypeLabel + self.complications = complications self.swipeActions = swipeActions self.trackerCallback = trackerCallback } @@ -50,14 +60,14 @@ struct CommunityResultView: View { } var caption: String { - if let host = community.communityUrl.host { - if showTypeLabel { - return "Community ∙ @\(host)" - } else { - return "@\(host)" - } + var parts: [String] = [] + if complications.contains(.type) { + parts.append("Community") + } + if complications.contains(.instance), let host = community.communityUrl.host { + parts.append("@\(host)") } - return "Unknown instance" + return parts.joined(separator: " ∙ ") } var subscriberCountColor: Color { @@ -103,7 +113,7 @@ struct CommunityResultView: View { .lineLimit(1) } Spacer() - if let subscriberCount = community.subscriberCount { + if complications.contains(.subscribers), let subscriberCount = community.subscriberCount { HStack(spacing: 5) { Text(abbreviateNumber(subscriberCount)) .monospacedDigit() @@ -151,7 +161,6 @@ struct CommunityResultView: View { #Preview { CommunityResultView( - .init(from: .mock()), - showTypeLabel: true + .init(from: .mock()) ) } diff --git a/Mlem/Views/Tabs/Search/Results/UserResultView.swift b/Mlem/Views/Tabs/Search/Results/UserResultView.swift index b19a17292..cdbd0b05d 100644 --- a/Mlem/Views/Tabs/Search/Results/UserResultView.swift +++ b/Mlem/Views/Tabs/Search/Results/UserResultView.swift @@ -8,31 +8,39 @@ import Dependencies import SwiftUI +enum UserComplication: CaseIterable { + case type, instance, date, posts, comments +} + +extension Array where Element == UserComplication { + static let withTypeLabel: [UserComplication] = [.type, .instance, .comments] + static let withoutTypeLabel: [UserComplication] = [.instance, .date, .posts, .comments] + static let instanceOnly: [UserComplication] = [.instance] +} + struct UserResultView: View { @Dependency(\.apiClient) private var apiClient @Dependency(\.hapticManager) var hapticManager - @EnvironmentObject var contentTracker: ContentTracker - let user: UserModel let communityContext: CommunityModel? - let showTypeLabel: Bool let trackerCallback: (_ item: UserModel) -> Void let swipeActions: SwipeConfiguration? + let complications: [UserComplication] @State private var isPresentingConfirmDestructive: Bool = false @State private var confirmationMenuFunction: StandardMenuFunction? init( _ user: UserModel, + complications: [UserComplication] = .withoutTypeLabel, communityContext: CommunityModel? = nil, - showTypeLabel: Bool = false, swipeActions: SwipeConfiguration? = nil, trackerCallback: @escaping (_ item: UserModel) -> Void = { _ in } ) { self.user = user + self.complications = complications self.communityContext = communityContext - self.showTypeLabel = showTypeLabel self.swipeActions = swipeActions self.trackerCallback = trackerCallback } @@ -51,16 +59,19 @@ struct UserResultView: View { } var caption: String { - if let host = user.profileUrl.host { - if showTypeLabel { - return "User ∙ @\(host)" - } else { - let dateFormatter = DateFormatter() - dateFormatter.dateFormat = "yyyy" - return "@\(host) ∙ \(dateFormatter.string(from: user.creationDate))" - } + var parts: [String] = [] + if complications.contains(.type) { + parts.append("User") } - return "Unknown instance" + if complications.contains(.instance), let host = user.profileUrl.host { + parts.append("@\(host)") + } + if complications.contains(.date) { + let dateFormatter = DateFormatter() + dateFormatter.dateFormat = "yyyy" + parts.append(dateFormatter.string(from: user.creationDate)) + } + return parts.joined(separator: " ∙ ") } var body: some View { @@ -92,37 +103,7 @@ struct UserResultView: View { .lineLimit(1) } Spacer() - if showTypeLabel { - HStack(spacing: 5) { - if let commentCount = user.commentCount { - Text(abbreviateNumber(commentCount)) - .monospacedDigit() - Image(systemName: Icons.replies) - } - } - .foregroundStyle(.secondary) - } else { - if let commentCount = user.commentCount, let postCount = user.postCount { - HStack(spacing: 5) { - VStack(alignment: .trailing, spacing: 6) { - Text(abbreviateNumber(postCount)) - .font(.subheadline) - .monospacedDigit() - Text(abbreviateNumber(commentCount)) - .font(.subheadline) - .monospacedDigit() - } - .foregroundStyle(.secondary) - VStack(spacing: 10) { - Image(systemName: Icons.posts) - .imageScale(.small) - Image(systemName: Icons.replies) - .imageScale(.small) - } - } - .foregroundStyle(.secondary) - } - } + trailingInfo Image(systemName: Icons.forward) .imageScale(.small) .foregroundStyle(.tertiary) @@ -154,11 +135,52 @@ struct UserResultView: View { } } } + + @ViewBuilder + var trailingInfo: some View { + Group { + if complications.contains(.posts), let postCount = user.postCount { + if complications.contains(.comments), let commentCount = user.commentCount { + HStack(spacing: 5) { + VStack(alignment: .trailing, spacing: 6) { + Text(abbreviateNumber(postCount)) + .font(.subheadline) + .monospacedDigit() + Text(abbreviateNumber(commentCount)) + .font(.subheadline) + .monospacedDigit() + } + .foregroundStyle(.secondary) + VStack(spacing: 10) { + Image(systemName: Icons.posts) + .imageScale(.small) + Image(systemName: Icons.replies) + .imageScale(.small) + } + } + .foregroundStyle(.secondary) + } else { + HStack(spacing: 5) { + Text(abbreviateNumber(postCount)) + .monospacedDigit() + Image(systemName: Icons.posts) + } + .foregroundStyle(.secondary) + } + } else if complications.contains(.comments), let commentCount = user.commentCount { + HStack(spacing: 5) { + Text(abbreviateNumber(commentCount)) + .monospacedDigit() + Image(systemName: Icons.replies) + } + .foregroundStyle(.secondary) + } + } + } } #Preview { UserResultView( - .init(from: .mock()), - showTypeLabel: true + .init(from: .mock()) ) } diff --git a/Mlem/Views/Tabs/Search/SearchResultListView.swift b/Mlem/Views/Tabs/Search/SearchResultListView.swift index 97c46ccd7..5722c27b5 100644 --- a/Mlem/Views/Tabs/Search/SearchResultListView.swift +++ b/Mlem/Views/Tabs/Search/SearchResultListView.swift @@ -21,13 +21,21 @@ struct SearchResultListView: View { ForEach(contentTracker.items, id: \.uid) { contentModel in Group { if let community = contentModel.wrappedValue as? CommunityModel { - CommunityResultView(community, showTypeLabel: showTypeLabel, trackerCallback: { - contentTracker.update(with: AnyContentModel($0)) - }) + CommunityResultView( + community, + complications: showTypeLabel ? .withTypeLabel : .withoutTypeLabel, + trackerCallback: { + contentTracker.update(with: AnyContentModel($0)) + } + ) } else if let user = contentModel.wrappedValue as? UserModel { - UserResultView(user, showTypeLabel: showTypeLabel, trackerCallback: { - contentTracker.update(with: AnyContentModel($0)) - }) + UserResultView( + user, + complications: showTypeLabel ? .withTypeLabel : .withoutTypeLabel, + trackerCallback: { + contentTracker.update(with: AnyContentModel($0)) + } + ) } } .simultaneousGesture(TapGesture().onEnded {