Skip to content

Commit

Permalink
fixed profile refresh problems
Browse files Browse the repository at this point in the history
  • Loading branch information
EricBAndrews committed Oct 6, 2023
1 parent 343ef1c commit 2635597
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 42 deletions.
10 changes: 10 additions & 0 deletions Mlem/API/Internal/HierarchicalComment.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,16 @@ extension HierarchicalComment: Equatable {
}
}

extension HierarchicalComment: Hashable {
func hash(into hasher: inout Hasher) {
hasher.combine(commentView.id)
hasher.combine(commentView.comment.updated)
hasher.combine(commentView.counts.upvotes)
hasher.combine(commentView.counts.downvotes)
hasher.combine(commentView.myVote)
}
}

extension [HierarchicalComment] {
/// A method to insert an updated `APICommentView` into this array of `HierarchicalComment`
/// - Parameter commentView: The `APICommentView` you wish to insert
Expand Down
2 changes: 1 addition & 1 deletion Mlem/Enums/Content Type.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@
import Foundation

enum ContentType: Int, Codable {
case post, community, user
case post, comment, community, user
}
2 changes: 1 addition & 1 deletion Mlem/Models/Trackers/Post Tracker.swift
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ class PostTracker: ObservableObject {
}

@MainActor
private func reset(
func reset(
with newItems: [PostModel] = .init(),
filteredWith filter: @escaping (_: PostModel) -> Bool = { _ in true }
) {
Expand Down
15 changes: 14 additions & 1 deletion Mlem/Repositories/PersonRepository.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,24 @@ class PersonRepository {
return users
}

func loadDetails(for id: Int) async throws -> UserModel {
/// Gets the UserModel for a given user
/// - Parameter id: id of the user to get
/// - Returns: UserModel for the given user
func getUser(for id: Int) async throws -> UserModel {
let response = try await apiClient.getPersonDetails(for: id, limit: 1, savedOnly: false)
return UserModel(from: response.personView)
}

/// Gets full user details for the given user
/// - Parameters:
/// - id: user id to get for
/// - limit: max number of content items to fetch
/// - savedOnly: if present, whether to fetch saved items; calling user must be the requested user
/// - Returns: GetPersonDetailsResponse for the given user
func getUserDetails(for id: Int, limit: Int, savedOnly: Bool = false) async throws -> GetPersonDetailsResponse {
try await apiClient.getPersonDetails(for: id, limit: limit, savedOnly: savedOnly)
}

func getUnreadCounts() async throws -> APIPersonUnreadCounts {
do {
return try await apiClient.getUnreadCount()
Expand Down
71 changes: 38 additions & 33 deletions Mlem/Views/Tabs/Profile/User View.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ struct UserView: View {
@Dependency(\.apiClient) var apiClient
@Dependency(\.errorHandler) var errorHandler
@Dependency(\.notifier) var notifier
@Dependency(\.personRepository) var personRepository

// appstorage
@AppStorage("shouldShowUserHeaders") var shouldShowUserHeaders: Bool = true
let internetSpeed: InternetSpeed

// environment
@EnvironmentObject var appState: AppState
Expand All @@ -41,6 +43,8 @@ struct UserView: View {
@AppStorage("internetSpeed") var internetSpeed: InternetSpeed = .fast
@AppStorage("upvoteOnSave") var upvoteOnSave = false

self.internetSpeed = internetSpeed

self._userID = State(initialValue: userID)
self._userDetails = State(initialValue: userDetails)

Expand Down Expand Up @@ -147,7 +151,7 @@ struct UserView: View {
.navigationBarColor()
.headerProminence(.standard)
.refreshable {
await tryLoadUser()
await tryReloadUser()
}.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
accountSwitcher
Expand Down Expand Up @@ -190,28 +194,50 @@ struct UserView: View {
}
}
.task(priority: .userInitiated) {
await tryLoadUser()
await tryReloadUser()
}
}

private func tryLoadUser() async {
// swiftlint:disable function_body_length
private func tryReloadUser() async {
do {
let authoredContent = try await loadUser(savedItems: false)
let authoredContent = try await personRepository.getUserDetails(for: userID, limit: internetSpeed.pageSize)
var savedContentData: GetPersonDetailsResponse?
if isShowingOwnProfile() {
savedContentData = try await loadUser(savedItems: true)
savedContentData = try await personRepository.getUserDetails(
for: userID,
limit: internetSpeed.pageSize,
savedOnly: true
)
}

if isShowingOwnProfile(), let currentAccount = appState.currentActiveAccount {
// take this opportunity to update the users avatar url to catch changes
// we should be able to shift this down to the repository layer in the future so that we
// catch anytime the app loads the signed in users details from any location in the app 🤞
// -> we'll need to find a way to stop the state changes this creates from cancelling other in-flight requests
let url = authoredContent.personView.person.avatarUrl
let updatedAccount = SavedAccount(
id: currentAccount.id,
instanceLink: currentAccount.instanceLink,
accessToken: currentAccount.accessToken,
username: currentAccount.username,
storedNickname: currentAccount.storedNickname,
avatarUrl: url
)
appState.setActiveAccount(updatedAccount)
}

privateCommentTracker.add(authoredContent.comments
privateCommentTracker.comments = authoredContent.comments
.sorted(by: { $0.comment.published > $1.comment.published })
.map { HierarchicalComment(comment: $0, children: [], parentCollapsed: false, collapsed: false) })
.map { HierarchicalComment(comment: $0, children: [], parentCollapsed: false, collapsed: false) }

privatePostTracker.add(authoredContent.posts.map { PostModel(from: $0) })
privatePostTracker.reset(with: authoredContent.posts.map { PostModel(from: $0) })

if let savedContent = savedContentData {
privateCommentTracker.add(savedContent.comments
privateCommentTracker.comments = savedContent.comments
.sorted(by: { $0.comment.published > $1.comment.published })
.map { HierarchicalComment(comment: $0, children: [], parentCollapsed: false, collapsed: false) })
.map { HierarchicalComment(comment: $0, children: [], parentCollapsed: false, collapsed: false) }

privatePostTracker.add(savedContent.posts.map { PostModel(from: $0) })
}
Expand All @@ -224,7 +250,7 @@ struct UserView: View {
} catch {
if userDetails == nil {
errorDetails = ErrorDetails(error: error, refresh: {
await tryLoadUser()
await tryReloadUser()
return userDetails != nil
})
} else {
Expand All @@ -238,28 +264,7 @@ struct UserView: View {
}
}
}

private func loadUser(savedItems: Bool) async throws -> GetPersonDetailsResponse {
let response = try await apiClient.getPersonDetails(for: userID, limit: 20, savedOnly: savedItems)

if isShowingOwnProfile(), let currentAccount = appState.currentActiveAccount {
// take this opportunity to update the users avatar url to catch changes
// we should be able to shift this down to the repository layer in the future so that we
// catch anytime the app loads the signed in users details from any location in the app 🤞
let url = response.personView.person.avatarUrl
let updatedAccount = SavedAccount(
id: currentAccount.id,
instanceLink: currentAccount.instanceLink,
accessToken: currentAccount.accessToken,
username: currentAccount.username,
storedNickname: currentAccount.storedNickname,
avatarUrl: url
)
appState.setActiveAccount(updatedAccount)
}

return response
}
// swiftlint:enable function_body_length
}

// TODO: darknavi - Move these to a common area for reuse
Expand Down
30 changes: 24 additions & 6 deletions Mlem/Views/Tabs/Profile/UserFeedView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,17 @@ struct UserFeedView: View {

@Binding var selectedTab: UserViewTab

struct FeedItem: Identifiable {
let id = UUID()
struct FeedItem: Identifiable, Hashable {
static func == (lhs: UserFeedView.FeedItem, rhs: UserFeedView.FeedItem) -> Bool {
lhs.hashValue == rhs.hashValue
}

var id: Int { hashValue }
var uid: ContentModelIdentifier
let published: Date
let comment: HierarchicalComment?
let post: PostModel?
let hashValue: Int
}

var body: some View {
Expand All @@ -43,7 +49,7 @@ struct UserFeedView: View {
}

func content(_ feed: [FeedItem]) -> some View {
ForEach(feed) { feedItem in
ForEach(feed, id: \.uid) { feedItem in
if let post = feedItem.post {
postEntry(for: post)
}
Expand Down Expand Up @@ -81,7 +87,7 @@ struct UserFeedView: View {
Divider()
}
}
.buttonStyle(.plain)
.buttonStyle(EmptyButtonStyle())
}

private func commentEntry(for comment: HierarchicalComment) -> some View {
Expand Down Expand Up @@ -126,7 +132,13 @@ struct UserFeedView: View {

// Create Feed Items
.map {
FeedItem(published: $0.commentView.comment.published, comment: $0, post: nil)
FeedItem(
uid: ContentModelIdentifier(contentType: .comment, contentId: $0.commentView.comment.id),
published: $0.commentView.comment.published,
comment: $0,
post: nil,
hashValue: $0.hashValue
)
}
}

Expand All @@ -145,7 +157,13 @@ struct UserFeedView: View {

// Create Feed Items
.map {
FeedItem(published: $0.post.published, comment: nil, post: $0)
FeedItem(
uid: ContentModelIdentifier(contentType: .post, contentId: $0.postId),
published: $0.post.published,
comment: nil,
post: $0,
hashValue: $0.hashValue
)
}
}

Expand Down

0 comments on commit 2635597

Please sign in to comment.