From 574818147e407a04aecb8f4cb8281e939d63eb10 Mon Sep 17 00:00:00 2001 From: Anton Yarmolenko Date: Fri, 19 Apr 2024 10:24:38 +0200 Subject: [PATCH] fix for discussion pull to refresh (#393) * chore: get data from API when refresh * chore: refactor; added refresh flag * chore: code style * fix: fixed tests --------- Co-authored-by: Vadim Kuznetsov --- Discussion/Discussion/Domain/Model/Post.swift | 26 +++++++++++++---- .../Discussion/Domain/Model/UserComment.swift | 21 +++++++++++--- .../Discussion/Domain/Model/UserThread.swift | 29 +++++++++++++++---- .../Comments/Responses/ResponsesView.swift | 7 +++-- .../Responses/ResponsesViewModel.swift | 28 ++++++++++++++---- .../Comments/Thread/ThreadView.swift | 11 ++----- .../Comments/Thread/ThreadViewModel.swift | 26 ++++++++++++++--- .../Comment/ThreadViewModelTests.swift | 8 ++--- .../Responses/ResponsesViewModelTests.swift | 6 ++-- 9 files changed, 119 insertions(+), 43 deletions(-) diff --git a/Discussion/Discussion/Domain/Model/Post.swift b/Discussion/Discussion/Domain/Model/Post.swift index 0e2f09047..ec034e61f 100644 --- a/Discussion/Discussion/Domain/Model/Post.swift +++ b/Discussion/Discussion/Domain/Model/Post.swift @@ -24,13 +24,27 @@ public struct Post { public let commentID: String public let parentID: String? public var abuseFlagged: Bool - public let closed: Bool + public var closed: Bool - public init(authorName: String, authorAvatar: String, postDate: Date, postTitle: String, postBodyHtml: String, - postBody: String, - postVisible: Bool, voted: Bool, followed: Bool, votesCount: Int, responsesCount: Int, - comments: [Post], threadID: String, commentID: String, parentID: String?, abuseFlagged: Bool, - closed: Bool) { + public init( + authorName: String, + authorAvatar: String, + postDate: Date, + postTitle: String, + postBodyHtml: String, + postBody: String, + postVisible: Bool, + voted: Bool, + followed: Bool, + votesCount: Int, + responsesCount: Int, + comments: [Post], + threadID: String, + commentID: String, + parentID: String?, + abuseFlagged: Bool, + closed: Bool + ) { self.authorName = authorName self.authorAvatar = authorAvatar self.postDate = postDate diff --git a/Discussion/Discussion/Domain/Model/UserComment.swift b/Discussion/Discussion/Domain/Model/UserComment.swift index cdc8ecb92..4f3ef35af 100644 --- a/Discussion/Discussion/Domain/Model/UserComment.swift +++ b/Discussion/Discussion/Domain/Model/UserComment.swift @@ -24,10 +24,23 @@ public struct UserComment: Hashable { public let parentID: String? public var abuseFlagged: Bool - public init(authorName: String, authorAvatar: String, postDate: Date, postTitle: String, postBody: String, - postBodyHtml: String, - postVisible: Bool, voted: Bool, followed: Bool, votesCount: Int, responsesCount: Int, - threadID: String, commentID: String, parentID: String?, abuseFlagged: Bool) { + public init( + authorName: String, + authorAvatar: String, + postDate: Date, + postTitle: String, + postBody: String, + postBodyHtml: String, + postVisible: Bool, + voted: Bool, + followed: Bool, + votesCount: Int, + responsesCount: Int, + threadID: String, + commentID: String, + parentID: String?, + abuseFlagged: Bool + ) { self.authorName = authorName self.authorAvatar = authorAvatar self.postDate = postDate diff --git a/Discussion/Discussion/Domain/Model/UserThread.swift b/Discussion/Discussion/Domain/Model/UserThread.swift index b87a14a36..81e8dcf0c 100644 --- a/Discussion/Discussion/Domain/Model/UserThread.swift +++ b/Discussion/Discussion/Domain/Model/UserThread.swift @@ -33,16 +33,35 @@ public struct UserThread { public let closed: Bool public var following: Bool public var commentCount: Int - public let avatar: String + public var avatar: String public var unreadCommentCount: Int public var abuseFlagged: Bool public let hasEndorsed: Bool public let numPages: Int - public init(id: String, author: String, authorLabel: String, createdAt: Date, updatedAt: Date, rawBody: String, - renderedBody: String, voted: Bool, voteCount: Int, courseID: String, type: PostType, title: String, - pinned: Bool, closed: Bool, following: Bool, commentCount: Int, avatar: String, unreadCommentCount: Int, - abuseFlagged: Bool, hasEndorsed: Bool, numPages: Int) { + public init( + id: String, + author: String, + authorLabel: String, + createdAt: Date, + updatedAt: Date, + rawBody: String, + renderedBody: String, + voted: Bool, + voteCount: Int, + courseID: String, + type: PostType, + title: String, + pinned: Bool, + closed: Bool, + following: Bool, + commentCount: Int, + avatar: String, + unreadCommentCount: Int, + abuseFlagged: Bool, + hasEndorsed: Bool, + numPages: Int + ) { self.id = id self.author = author self.authorLabel = authorLabel diff --git a/Discussion/Discussion/Presentation/Comments/Responses/ResponsesView.swift b/Discussion/Discussion/Presentation/Comments/Responses/ResponsesView.swift index a9b8ef2cb..d4dab6464 100644 --- a/Discussion/Discussion/Presentation/Comments/Responses/ResponsesView.swift +++ b/Discussion/Discussion/Presentation/Comments/Responses/ResponsesView.swift @@ -33,7 +33,7 @@ public struct ResponsesView: View { self.viewModel = viewModel self.router = router Task { - await viewModel.getComments(commentID: commentID, parentComment: parentComment, page: 1) + await viewModel.getResponsesData(commentID: commentID, parentComment: parentComment, page: 1) } viewModel.addCommentsIsVisible = false self.viewModel.isBlackedOut = isBlackedOut @@ -48,10 +48,11 @@ public struct ResponsesView: View { ZStack(alignment: .top) { RefreshableScrollViewCompat(action: { viewModel.comments = [] - _ = await viewModel.getComments( + _ = await viewModel.getResponsesData( commentID: commentID, parentComment: parentComment, - page: 1 + page: 1, + refresh: true ) }) { VStack { diff --git a/Discussion/Discussion/Presentation/Comments/Responses/ResponsesViewModel.swift b/Discussion/Discussion/Presentation/Comments/Responses/ResponsesViewModel.swift index 91ac5d515..c8992fd8a 100644 --- a/Discussion/Discussion/Presentation/Comments/Responses/ResponsesViewModel.swift +++ b/Discussion/Discussion/Presentation/Comments/Responses/ResponsesViewModel.swift @@ -76,9 +76,11 @@ public class ResponsesViewModel: BaseResponsesViewModel, ObservableObject { if index == comments.count - 3 { if totalPages != 1 { if nextPage != totalPages + 1 { - if await self.getComments(commentID: commentID, - parentComment: parentComment, - page: nextPage) { + if await self.getResponsesData( + commentID: commentID, + parentComment: parentComment, + page: nextPage + ) { self.nextPage += 1 } } @@ -88,19 +90,23 @@ public class ResponsesViewModel: BaseResponsesViewModel, ObservableObject { } @MainActor - func getComments(commentID: String, parentComment: Post, page: Int) async -> Bool { + func getResponsesData(commentID: String, parentComment: Post, page: Int, refresh: Bool = false) async -> Bool { guard !fetchInProgress else { return false } do { let (comments, pagination) = try await interactor .getCommentResponses(commentID: commentID, page: page) self.totalPages = pagination.numPages self.itemsCount = pagination.count + var parentPost = parentComment if page == 1 { self.comments = comments + if refresh { + parentPost = await getParentPost(parentComment: parentComment) + } } else { self.comments += comments } - postComments = generateCommentsResponses(comments: self.comments, parentComment: parentComment) + postComments = generateCommentsResponses(comments: self.comments, parentComment: parentPost) return true } catch let error { if error.isInternetError { @@ -112,6 +118,18 @@ public class ResponsesViewModel: BaseResponsesViewModel, ObservableObject { } } + func getParentPost(parentComment: Post) async -> Post { + do { + let parentCommentData = try await interactor.getResponse(responseID: parentComment.commentID) + var parentPost = parentCommentData.post + parentPost.closed = parentComment.closed + parentPost.authorAvatar = parentComment.authorAvatar + return parentPost + } catch { + return parentComment + } + } + func sendThreadLikeState() { if let postComments { threadStateSubject.send(.voted( diff --git a/Discussion/Discussion/Presentation/Comments/Thread/ThreadView.swift b/Discussion/Discussion/Presentation/Comments/Thread/ThreadView.swift index 2c7632730..84f2b6816 100644 --- a/Discussion/Discussion/Presentation/Comments/Thread/ThreadView.swift +++ b/Discussion/Discussion/Presentation/Comments/Thread/ThreadView.swift @@ -37,7 +37,7 @@ public struct ThreadView: View { VStack { ZStack(alignment: .top) { RefreshableScrollViewCompat(action: { - _ = await viewModel.getPosts(thread: thread, page: 1) + _ = await viewModel.getThreadData(thread: thread, page: 1, refresh: true) }) { VStack { if let comments = viewModel.postComments { @@ -241,7 +241,7 @@ public struct ThreadView: View { } .onFirstAppear { Task { - await viewModel.getPosts(thread: thread, page: 1) + await viewModel.getThreadData(thread: thread, page: 1) } } .onDisappear { @@ -255,13 +255,6 @@ public struct ThreadView: View { ) } } - - private func reloadPage(onSuccess: @escaping () -> Void) { - Task { - if await viewModel.getPosts(thread: thread, - page: viewModel.nextPage-1) { onSuccess() } - } - } } #if DEBUG diff --git a/Discussion/Discussion/Presentation/Comments/Thread/ThreadViewModel.swift b/Discussion/Discussion/Presentation/Comments/Thread/ThreadViewModel.swift index 247a097d0..2fb75b60f 100644 --- a/Discussion/Discussion/Presentation/Comments/Thread/ThreadViewModel.swift +++ b/Discussion/Discussion/Presentation/Comments/Thread/ThreadViewModel.swift @@ -113,7 +113,7 @@ public class ThreadViewModel: BaseResponsesViewModel, ObservableObject { if index == comments.count - 3 { if totalPages != 1 { if nextPage != totalPages+1 { - if await self.getPosts(thread: thread, page: nextPage) { + if await self.getThreadData(thread: thread, page: nextPage) { self.nextPage += 1 return true } @@ -125,7 +125,7 @@ public class ThreadViewModel: BaseResponsesViewModel, ObservableObject { } @MainActor - public func getPosts(thread: UserThread, page: Int) async -> Bool { + public func getThreadData(thread: UserThread, page: Int, refresh: Bool = false) async -> Bool { guard !fetchInProgress else { return false } fetchInProgress = true do { @@ -136,23 +136,31 @@ public class ThreadViewModel: BaseResponsesViewModel, ObservableObject { .getQuestionComments(threadID: thread.id, page: page) self.totalPages = pagination.numPages self.itemsCount = pagination.count + var threadPost = thread if page == 1 { self.comments = comments + if refresh { + threadPost = await getThreadPost(thread: thread) + } } else { self.comments += comments } - postComments = generateComments(comments: self.comments, thread: thread) + postComments = generateComments(comments: self.comments, thread: threadPost) case .discussion: let (comments, pagination) = try await interactor .getDiscussionComments(threadID: thread.id, page: page) self.totalPages = pagination.numPages self.itemsCount = pagination.count + var threadPost = thread if page == 1 { self.comments = comments + if refresh { + threadPost = await getThreadPost(thread: thread) + } } else { self.comments += comments } - postComments = generateComments(comments: self.comments, thread: thread) + postComments = generateComments(comments: self.comments, thread: threadPost) } fetchInProgress = false return true @@ -167,6 +175,16 @@ public class ThreadViewModel: BaseResponsesViewModel, ObservableObject { } } + func getThreadPost(thread: UserThread) async -> UserThread { + do { + var threadPost = try await interactor.getThread(threadID: thread.id) + threadPost.avatar = thread.avatar + return threadPost + } catch { + return thread + } + } + func sendPostFollowedState() { if let postComments { postStateSubject.send(.followed(id: postComments.threadID, postComments.followed)) diff --git a/Discussion/DiscussionTests/Presentation/Comment/ThreadViewModelTests.swift b/Discussion/DiscussionTests/Presentation/Comment/ThreadViewModelTests.swift index 724e99e32..7da4cdf55 100644 --- a/Discussion/DiscussionTests/Presentation/Comment/ThreadViewModelTests.swift +++ b/Discussion/DiscussionTests/Presentation/Comment/ThreadViewModelTests.swift @@ -221,7 +221,7 @@ final class ThreadViewModelTests: XCTestCase { count: 1, numPages: 1)))) - result = await viewModel.getPosts(thread: threads.threads[0], page: 1) + result = await viewModel.getThreadData(thread: threads.threads[0], page: 1) Verify(interactor, .readBody(threadID: .value(threads.threads[0].id))) Verify(interactor, .getQuestionComments(threadID: .value(threads.threads[0].id), page: .value(1))) @@ -250,7 +250,7 @@ final class ThreadViewModelTests: XCTestCase { count: 1, numPages: 1)))) - result = await viewModel.getPosts(thread: threads.threads[1], page: 1) + result = await viewModel.getThreadData(thread: threads.threads[1], page: 1) Verify(interactor, .readBody(threadID: .value(threads.threads[1].id))) Verify(interactor, .getDiscussionComments(threadID: .value(threads.threads[1].id), page: .value(1))) @@ -277,7 +277,7 @@ final class ThreadViewModelTests: XCTestCase { Given(interactor, .readBody(threadID: .any, willThrow: noInternetError)) Given(interactor, .getQuestionComments(threadID: .any, page: .any, willThrow: noInternetError)) - result = await viewModel.getPosts(thread: threads.threads[0], page: 1) + result = await viewModel.getThreadData(thread: threads.threads[0], page: 1) viewModel.postComments = postComments @@ -306,7 +306,7 @@ final class ThreadViewModelTests: XCTestCase { Given(interactor, .readBody(threadID: .any, willThrow: NSError())) Given(interactor, .getQuestionComments(threadID: .any, page: .any, willThrow: NSError())) - result = await viewModel.getPosts(thread: threads.threads[0], page: 1) + result = await viewModel.getThreadData(thread: threads.threads[0], page: 1) viewModel.postComments = postComments diff --git a/Discussion/DiscussionTests/Presentation/Responses/ResponsesViewModelTests.swift b/Discussion/DiscussionTests/Presentation/Responses/ResponsesViewModelTests.swift index 997364f10..a7c59806a 100644 --- a/Discussion/DiscussionTests/Presentation/Responses/ResponsesViewModelTests.swift +++ b/Discussion/DiscussionTests/Presentation/Responses/ResponsesViewModelTests.swift @@ -116,7 +116,7 @@ final class ResponsesViewModelTests: XCTestCase { count: 1, numPages: 1)))) - result = await viewModel.getComments(commentID: "1", parentComment: post, page: 1) + result = await viewModel.getResponsesData(commentID: "1", parentComment: post, page: 1) Verify(interactor, .getCommentResponses(commentID: .any, page: .any)) @@ -141,7 +141,7 @@ final class ResponsesViewModelTests: XCTestCase { Given(interactor, .getCommentResponses(commentID: .any, page: .any, willThrow: noInternetError)) - result = await viewModel.getComments(commentID: "1", parentComment: post, page: 1) + result = await viewModel.getResponsesData(commentID: "1", parentComment: post, page: 1) Verify(interactor, .getCommentResponses(commentID: .any, page: .any)) @@ -165,7 +165,7 @@ final class ResponsesViewModelTests: XCTestCase { Given(interactor, .getCommentResponses(commentID: .any, page: .any, willThrow: NSError())) - result = await viewModel.getComments(commentID: "1", parentComment: post, page: 1) + result = await viewModel.getResponsesData(commentID: "1", parentComment: post, page: 1) Verify(interactor, .getCommentResponses(commentID: .any, page: .any))