diff --git a/Wikipedia/Code/TalkPageCellViewModel.swift b/Wikipedia/Code/TalkPageCellViewModel.swift index adeba46fa4c..31f617a9ac3 100644 --- a/Wikipedia/Code/TalkPageCellViewModel.swift +++ b/Wikipedia/Code/TalkPageCellViewModel.swift @@ -7,6 +7,7 @@ final class TalkPageCellViewModel { let topicTitle: String let timestamp: Date? + let topicName: String let id: String var leadComment: TalkPageCellCommentViewModel @@ -21,10 +22,11 @@ final class TalkPageCellViewModel { let isUserLoggedIn: Bool - init(id: String, topicTitle: String, timestamp: Date?, leadComment: TalkPageCellCommentViewModel, replies: [TalkPageCellCommentViewModel], activeUsersCount: String, isUserLoggedIn: Bool) { + init(id: String, topicTitle: String, timestamp: Date?, topicName: String, leadComment: TalkPageCellCommentViewModel, replies: [TalkPageCellCommentViewModel], activeUsersCount: String, isUserLoggedIn: Bool) { self.id = id self.topicTitle = topicTitle self.timestamp = timestamp + self.topicName = topicName self.leadComment = leadComment self.replies = replies self.activeUsersCount = activeUsersCount diff --git a/Wikipedia/Code/TalkPageDataController.swift b/Wikipedia/Code/TalkPageDataController.swift index 60abeb8ada1..596881909af 100644 --- a/Wikipedia/Code/TalkPageDataController.swift +++ b/Wikipedia/Code/TalkPageDataController.swift @@ -20,7 +20,7 @@ class TalkPageDataController { // MARK: Public - typealias TalkPageResult = Result<(articleSummary: WMFArticle?, items: [TalkPageItem]), Error> + typealias TalkPageResult = Result<(articleSummary: WMFArticle?, items: [TalkPageItem], subscribedTopicNames: [String]), Error> func fetchTalkPage(completion: @escaping (TalkPageResult) -> Void) { @@ -31,6 +31,7 @@ class TalkPageDataController { var finalErrors: [Error] = [] var finalItems: [TalkPageItem] = [] var finalArticleSummary: WMFArticle? + var finalSubscribedTopics: [String] = [] fetchTalkPageItems(dispatchGroup: group) { items, errors in finalItems = items @@ -42,15 +43,21 @@ class TalkPageDataController { finalErrors.append(contentsOf: errors) } + group.notify(queue: DispatchQueue.main, execute: { if let firstError = finalErrors.first { completion(.failure(firstError)) return } - - completion(.success((finalArticleSummary, finalItems))) + self.fetchTopicSubscriptions(for: finalItems, dispatchGroup: group) { items, errors in + finalSubscribedTopics = items + finalErrors.append(contentsOf: errors) + completion(.success((finalArticleSummary, finalItems, finalSubscribedTopics))) + } + }) + } func postReply(commentId: String, comment: String, completion: @escaping(Result) -> Void) { @@ -72,22 +79,40 @@ class TalkPageDataController { } func subscribeToTopic(topicName: String, shouldSubscribe: Bool, completion: @escaping (Result) -> Void) { - talkPageFetcher.subscribeToTopic(talkPageTitle: pageTitle, siteURL: siteURL, topic: topicName, shouldSubscribe: shouldSubscribe, completion: completion) - } - - func fetchSubscriptions(for topics: [String], completion: @escaping (Result<[String], Error>) -> Void) { - talkPageFetcher.getSubscribedTopics(siteURL: siteURL, topics: topics) { result in - switch result { - case let .success(result): - completion(.success(result)) - case let .failure(error): - completion(.failure(error)) + + talkPageFetcher.subscribeToTopic(talkPageTitle: pageTitle, siteURL: siteURL, topic: topicName, shouldSubscribe: shouldSubscribe) { result in + DispatchQueue.main.async { + completion(result) } } } // MARK: Private + private func fetchTopicSubscriptions(for items: [TalkPageItem], dispatchGroup group: DispatchGroup, completion: @escaping ([String], [Error]) -> Void) { + + var topicNames = [String]() + for item in items { + if let itemName = item.name { + topicNames.append(itemName) + } + } + + + talkPageFetcher.getSubscribedTopics(siteURL: siteURL, topics: topicNames) { result in + + DispatchQueue.main.async { + switch result { + case let .success(result): + completion(result, []) + case let .failure(error): + completion([], [error]) + } + } + + } + } + private func fetchTalkPageItems(dispatchGroup group: DispatchGroup, completion: @escaping ([TalkPageItem], [Error]) -> Void) { group.enter() diff --git a/Wikipedia/Code/TalkPageFetcher.swift b/Wikipedia/Code/TalkPageFetcher.swift index d5bfc1a00b5..484b595d894 100644 --- a/Wikipedia/Code/TalkPageFetcher.swift +++ b/Wikipedia/Code/TalkPageFetcher.swift @@ -145,6 +145,11 @@ class TalkPageFetcher: Fetcher { } } + /// Returns a list of active talk page topics subscription + /// - Parameters: + /// - siteURL: URL for the talk page, takes a URL object + /// - topics: Expects a array of Strings containing the `name` value from `TalkPageItem` + /// - completion: Returns either and array with the the `name` property of subscribed topics or an Error func getSubscribedTopics(siteURL: URL, topics: [String], completion: @escaping (Result<[String], Error>) -> Void) { let joinedString = topics.joined(separator: "|") diff --git a/Wikipedia/Code/TalkPageViewController.swift b/Wikipedia/Code/TalkPageViewController.swift index e0be192b327..09d51111ef5 100644 --- a/Wikipedia/Code/TalkPageViewController.swift +++ b/Wikipedia/Code/TalkPageViewController.swift @@ -368,9 +368,25 @@ extension TalkPageViewController: TalkPageCellDelegate { } let configuredCellViewModel = viewModel.topics[indexOfConfiguredCell] - configuredCellViewModel.isSubscribed.toggle() + + let shouldSubscribe = !configuredCellViewModel.isSubscribed + cellViewModel.isSubscribed.toggle() cell.configure(viewModel: configuredCellViewModel, linkDelegate: self) - self.handleSubscriptionAlert(isSubscribedToTopic: configuredCellViewModel.isSubscribed) + + viewModel.subscribe(to: configuredCellViewModel.topicName, shouldSubscribe: shouldSubscribe) { result in + switch result { + case let .success(didSubscribe): + self.handleSubscriptionAlert(isSubscribedToTopic: didSubscribe) + case let .failure(error): + cellViewModel.isSubscribed.toggle() + if cell.viewModel?.topicName == cellViewModel.topicName { + cell.configure(viewModel: cellViewModel, linkDelegate: self) + } + DDLogError("Error subscribing to topic: \(error)") + // TODO: Error handling + } + } + } } diff --git a/Wikipedia/Code/TalkPageViewModel.swift b/Wikipedia/Code/TalkPageViewModel.swift index 98aa94c84e9..014bf8e1d1a 100644 --- a/Wikipedia/Code/TalkPageViewModel.swift +++ b/Wikipedia/Code/TalkPageViewModel.swift @@ -76,6 +76,7 @@ final class TalkPageViewModel { let oldViewModels: [TalkPageCellViewModel] = self.topics self.topics.removeAll() self.populateCellData(topics: result.items, oldViewModels: oldViewModels) + self.updateSubscriptionForTopic(topicNames: result.subscribedTopicNames) completion(.success(())) case .failure(let error): DDLogError("Failure fetching talk page: \(error)") @@ -84,18 +85,20 @@ final class TalkPageViewModel { } } } - + func postTopic(topicTitle: String, topicBody: String, completion: @escaping(Result) -> Void) { dataController.postTopic(topicTitle: topicTitle, topicBody: topicBody, completion: completion) } + func postReply(commentId: String, comment: String, completion: @escaping(Result) -> Void) { + dataController.postReply(commentId: commentId, comment: comment, completion: completion) + } + - func updateSubscriptionToTopic(topic: String, shouldSubscribe: Bool, completion: @escaping (Result) -> Void) { - dataController.subscribeToTopic(topicName: topic, shouldSubscribe: shouldSubscribe) { [self] result in + func subscribe(to topic: String, shouldSubscribe: Bool, completion: @escaping (Result) -> Void) { + dataController.subscribeToTopic(topicName: topic, shouldSubscribe: shouldSubscribe) { result in switch result { case let .success(result) : - let topicUpdated = topics.filter { $0.topicTitle == topic} - topicUpdated[0].isSubscribed = result completion(.success(result)) case let .failure(error): completion(.failure(error)) @@ -103,8 +106,14 @@ final class TalkPageViewModel { } } - func postReply(commentId: String, comment: String, completion: @escaping(Result) -> Void) { - dataController.postReply(commentId: commentId, comment: comment, completion: completion) + func updateSubscriptionForTopic(topicNames: [String]) { + for topic in topics { + for id in topicNames { + if topic.topicName == id { + topic.isSubscribed = true + } + } + } } // MARK: - Private @@ -166,8 +175,13 @@ final class TalkPageViewModel { let activeUsersCount = activeUsersCount(topic: topic) - let topicViewModel = TalkPageCellViewModel(id: topic.id, topicTitle: topicTitle, timestamp: firstReply.timestamp, leadComment: leadCommentViewModel, replies: remainingCommentViewModels, activeUsersCount: activeUsersCount, isUserLoggedIn: isUserLoggedIn) - + guard let topicName = topic.name else { + DDLogError("Unable to parse topic name") + continue + } + + let topicViewModel = TalkPageCellViewModel(id: topic.id, topicTitle: topicTitle, timestamp: firstReply.timestamp, topicName: topicName, leadComment: leadCommentViewModel, replies: remainingCommentViewModels, activeUsersCount: activeUsersCount, isUserLoggedIn: isUserLoggedIn) + // Note this is a nested loop, so it will not perform well with many topics. // Talk pages generally have a limited number of topics, so optimize later if we determine it's needed assignExpandedFlag(to: topicViewModel, from: oldViewModels)