diff --git a/Classes/Issues/IssueManagingContextController.swift b/Classes/Issues/IssueManagingContextController.swift index 437c2d34f..2f9ea4eba 100644 --- a/Classes/Issues/IssueManagingContextController.swift +++ b/Classes/Issues/IssueManagingContextController.swift @@ -304,10 +304,23 @@ final class IssueManagingContextController: NSObject, ContextMenuDelegate { Haptic.triggerNotification(.success) } - func didDismiss(selected labels: [RepositoryLabel]) { + func didDismiss(controller: LabelsViewController) { guard let previous = result, - previous.labels.labels != labels + previous.labels.labels != controller.selected else { return } + + if controller.wasDismissedByDone { + self.update(selected: controller.selected, previous: previous) + } else { + // Ask for confirmation + self.showCancelAlert { [weak self] keepChanges in + guard keepChanges else { return } + self?.update(selected: controller.selected, previous: previous) + } + } + } + + private func update(selected labels: [RepositoryLabel], previous: IssueResult) { delegate?.willMutateModel(from: self) client.mutateLabels( previous: previous, @@ -323,10 +336,23 @@ final class IssueManagingContextController: NSObject, ContextMenuDelegate { let selected = controller.selected guard controller.selectionChanged(newValues: selected) else { return } + + if controller.wasDismissedByDone { + self.update(selected: selected, type: controller.type, previous: previous) + } else { + // Ask for confirmation + self.showCancelAlert { [weak self] keepChanges in + guard keepChanges else { return } + self?.update(selected: selected, type: controller.type, previous: previous) + } + } + } + + private func update(selected assignees: [IssueAssigneeViewModel], type: PeopleViewController.PeopleType, previous: IssueResult) { delegate?.willMutateModel(from: self) let mutationType: V3AddPeopleRequest.PeopleType - switch controller.type { + switch type { case .assignee: mutationType = .assignees case .reviewer: mutationType = .reviewers } @@ -337,7 +363,7 @@ final class IssueManagingContextController: NSObject, ContextMenuDelegate { owner: model.owner, repo: model.repo, number: model.number, - people: controller.selected + people: assignees ) } @@ -345,13 +371,26 @@ final class IssueManagingContextController: NSObject, ContextMenuDelegate { guard let previous = result, previous.milestone != controller.selected else { return } + + if controller.wasDismissedByDone { + self.update(selected: controller.selected, previous: previous) + } else { + // Ask for confirmation + self.showCancelAlert { [weak self] keepChanges in + guard keepChanges else { return } + self?.update(selected: controller.selected, previous: previous) + } + } + } + + private func update(selected milestone: Milestone?, previous: IssueResult) { delegate?.willMutateModel(from: self) client.setMilestone( previous: previous, owner: model.owner, repo: model.repo, number: model.number, - milestone: controller.selected + milestone: milestone ) } @@ -363,10 +402,24 @@ final class IssueManagingContextController: NSObject, ContextMenuDelegate { } else if let people = viewController as? PeopleViewController { didDismiss(controller: people) } else if let labels = viewController as? LabelsViewController { - didDismiss(selected: labels.selected) + didDismiss(controller: labels) } } func contextMenuDidDismiss(viewController: UIViewController, animated: Bool) {} + private func showCancelAlert(completion: @escaping (_ keepChanges: Bool) -> Void) { + guard let viewController = self.viewController else { return } + + let title = NSLocalizedString("Are you sure?", comment: "") + let message = NSLocalizedString("Some changes have been made. Are you sure you want to discard them?", comment: "") + let alert = UIAlertController.configured(title: title, message: message, preferredStyle: .alert) + + alert.addActions([ + AlertAction.keep { _ in completion(true) }, + AlertAction.discard { _ in completion(false) } + ]) + + viewController.present(alert, animated: trueUnlessReduceMotionEnabled) + } } diff --git a/Classes/Labels/LabelsViewController.swift b/Classes/Labels/LabelsViewController.swift index 0b6c0a0f6..4c3ef7fbf 100644 --- a/Classes/Labels/LabelsViewController.swift +++ b/Classes/Labels/LabelsViewController.swift @@ -19,6 +19,8 @@ LabelSectionControllerDelegate { private let client: GithubClient private let request: RepositoryLabelsQuery + var wasDismissedByDone = false + init( selected: [RepositoryLabel], client: GithubClient, @@ -102,6 +104,11 @@ LabelSectionControllerDelegate { }) } + override func onMenuDone() { + self.wasDismissedByDone = true + super.onMenuDone() + } + // MARK: BaseListViewControllerDataSource func models(adapter: ListSwiftAdapter) -> [ListSwiftPair] { diff --git a/Classes/Milestones/MilestonesViewController.swift b/Classes/Milestones/MilestonesViewController.swift index b621998ee..3ea587115 100644 --- a/Classes/Milestones/MilestonesViewController.swift +++ b/Classes/Milestones/MilestonesViewController.swift @@ -26,6 +26,8 @@ MilestoneSectionControllerDelegate { private let feedRefresh = FeedRefresh() private var milestones = [Milestone]() + var wasDismissedByDone = false + private let dateFormatter: DateFormatter = { let formatter = DateFormatter() formatter.dateStyle = .long @@ -96,6 +98,11 @@ MilestoneSectionControllerDelegate { } } + override func onMenuDone() { + self.wasDismissedByDone = true + super.onMenuDone() + } + // MARK: BaseListViewControllerDataSource func models(adapter: ListSwiftAdapter) -> [ListSwiftPair] { diff --git a/Classes/People/PeopleViewController.swift b/Classes/People/PeopleViewController.swift index 7c56b81bc..538a118c8 100644 --- a/Classes/People/PeopleViewController.swift +++ b/Classes/People/PeopleViewController.swift @@ -30,6 +30,8 @@ PeopleSectionControllerDelegate { private var owner: String private var repo: String + var wasDismissedByDone = false + init( selections: [String], exclusions: [String], @@ -165,6 +167,11 @@ PeopleSectionControllerDelegate { } } + @objc override func onMenuDone() { + self.wasDismissedByDone = true + super.onMenuDone() + } + // MARK: BaseListViewControllerDataSource func models(adapter: ListSwiftAdapter) -> [ListSwiftPair] { diff --git a/Classes/Utility/AlertAction.swift b/Classes/Utility/AlertAction.swift index c483b84a6..85c92f541 100644 --- a/Classes/Utility/AlertAction.swift +++ b/Classes/Utility/AlertAction.swift @@ -113,6 +113,10 @@ struct AlertAction { return UIAlertAction(title: NSLocalizedString("Discard", comment: ""), style: .destructive, handler: handler) } + static func keep(_ handler: AlertActionBlock? = nil) -> UIAlertAction { + return UIAlertAction(title: NSLocalizedString("Keep", comment: ""), style: .default, handler: handler) + } + static func delete(_ handler: AlertActionBlock? = nil) -> UIAlertAction { return UIAlertAction(title: NSLocalizedString("Delete", comment: ""), style: .destructive, handler: handler) }