diff --git a/WordPress/Classes/ViewRelated/Me/Me Main/Header/MeHeaderView.h b/WordPress/Classes/ViewRelated/Me/Views/Header/MeHeaderView.h similarity index 100% rename from WordPress/Classes/ViewRelated/Me/Me Main/Header/MeHeaderView.h rename to WordPress/Classes/ViewRelated/Me/Views/Header/MeHeaderView.h diff --git a/WordPress/Classes/ViewRelated/Me/Me Main/Header/MeHeaderView.m b/WordPress/Classes/ViewRelated/Me/Views/Header/MeHeaderView.m similarity index 100% rename from WordPress/Classes/ViewRelated/Me/Me Main/Header/MeHeaderView.m rename to WordPress/Classes/ViewRelated/Me/Views/Header/MeHeaderView.m diff --git a/WordPress/Classes/ViewRelated/Me/Views/Header/MeHeaderViewConfiguration.swift b/WordPress/Classes/ViewRelated/Me/Views/Header/MeHeaderViewConfiguration.swift new file mode 100644 index 000000000000..0380f233acb3 --- /dev/null +++ b/WordPress/Classes/ViewRelated/Me/Views/Header/MeHeaderViewConfiguration.swift @@ -0,0 +1,30 @@ +import UIKit + +struct MeHeaderViewConfiguration { + + let gravatarEmail: String? + let username: String + let displayName: String +} + +extension MeHeaderViewConfiguration { + + init(account: WPAccount) { + self.init( + gravatarEmail: account.email, + username: account.username, + displayName: account.displayName + ) + } +} + +extension MeHeaderView { + + func update(with configuration: Configuration) { + self.gravatarEmail = configuration.gravatarEmail + self.username = configuration.username + self.displayName = configuration.displayName + } + + typealias Configuration = MeHeaderViewConfiguration +} diff --git a/WordPress/Classes/ViewRelated/Site Creation/Shared/UITableView+Header.swift b/WordPress/Classes/ViewRelated/Site Creation/Shared/UITableView+Header.swift index 45ebb7d55665..9e4c28b3b6d5 100644 --- a/WordPress/Classes/ViewRelated/Site Creation/Shared/UITableView+Header.swift +++ b/WordPress/Classes/ViewRelated/Site Creation/Shared/UITableView+Header.swift @@ -42,7 +42,10 @@ extension UITableView { withHorizontalFittingPriority: .required, verticalFittingPriority: .fittingSizeLevel ) - tableHeaderView.frame = CGRect(origin: .zero, size: size) - self.tableHeaderView = tableHeaderView + let newFrame = CGRect(origin: .zero, size: size) + if tableHeaderView.frame.height != newFrame.height { + tableHeaderView.frame = newFrame + self.tableHeaderView = tableHeaderView + } } } diff --git a/WordPress/Classes/ViewRelated/Support/LogOutActionHandler.swift b/WordPress/Classes/ViewRelated/Support/LogOutActionHandler.swift new file mode 100644 index 000000000000..f9fff153f878 --- /dev/null +++ b/WordPress/Classes/ViewRelated/Support/LogOutActionHandler.swift @@ -0,0 +1,38 @@ +import UIKit + +struct LogOutActionHandler { + + func logOut(with viewController: UIViewController) { + let alert = UIAlertController(title: logOutAlertTitle, message: nil, preferredStyle: .alert) + alert.addActionWithTitle(Strings.alertCancelAction, style: .cancel) + alert.addActionWithTitle(Strings.alertLogoutAction, style: .destructive) { [weak viewController] _ in + viewController?.dismiss(animated: true) { + AccountHelper.logOutDefaultWordPressComAccount() + } + } + viewController.present(alert, animated: true) + } + + private var logOutAlertTitle: String { + let context = ContextManager.sharedInstance().mainContext + let count = AbstractPost.countLocalPosts(in: context) + + guard count > 0 else { + return Strings.alertDefaultTitle + } + + let format = count > 1 ? Strings.alertUnsavedTitlePlural : Strings.alertUnsavedTitleSingular + return String(format: format, count) + } + + + private struct Strings { + static let alertDefaultTitle = AppConstants.Logout.alertTitle + static let alertUnsavedTitleSingular = NSLocalizedString("You have changes to %d post that hasn't been uploaded to your site. Logging out now will delete those changes. Log out anyway?", + comment: "Warning displayed before logging out. The %d placeholder will contain the number of local posts (SINGULAR!)") + static let alertUnsavedTitlePlural = NSLocalizedString("You have changes to %d posts that haven’t been uploaded to your site. Logging out now will delete those changes. Log out anyway?", + comment: "Warning displayed before logging out. The %d placeholder will contain the number of local posts (PLURAL!)") + static let alertCancelAction = NSLocalizedString("Cancel", comment: "Verb. A button title. Tapping cancels an action.") + static let alertLogoutAction = NSLocalizedString("Log Out", comment: "Button for confirming logging out from WordPress.com account") + } +} diff --git a/WordPress/Classes/ViewRelated/Support/SupportTableViewController.swift b/WordPress/Classes/ViewRelated/Support/SupportTableViewController.swift index 81cf0f3e595b..f4c992c584d0 100644 --- a/WordPress/Classes/ViewRelated/Support/SupportTableViewController.swift +++ b/WordPress/Classes/ViewRelated/Support/SupportTableViewController.swift @@ -5,6 +5,9 @@ class SupportTableViewController: UITableViewController { // MARK: - Properties + /// Configures the appearance of the support screen. + let configuration: Configuration + var sourceTag: WordPressSupportSourceTag? // If set, the Zendesk views will be shown from this view instead of in the navigation controller. @@ -21,7 +24,8 @@ class SupportTableViewController: UITableViewController { // MARK: - Init - override init(style: UITableView.Style) { + init(configuration: Configuration = .init(), style: UITableView.Style = .grouped) { + self.configuration = configuration super.init(style: style) } @@ -46,6 +50,11 @@ class SupportTableViewController: UITableViewController { ZendeskUtils.fetchUserInformation() } + override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + self.tableView.sizeToFitHeaderView() + } + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) reloadViewModel() @@ -78,7 +87,6 @@ class SupportTableViewController: UITableViewController { dismissTapped?() dismiss(animated: true) } - } // MARK: - Private Extension @@ -107,14 +115,18 @@ private extension SupportTableViewController { NavigationItemRow.self, TextRow.self, HelpRow.self, + DestructiveButtonRow.self, SupportEmailRow.self], tableView: tableView) tableHandler = ImmuTableViewHandler(takeOver: self) reloadViewModel() WPStyleGuide.configureColors(view: view, tableView: tableView) - // remove empty cells - tableView.tableFooterView = UIView() - + tableView.tableFooterView = UIView() // remove empty cells + if let headerConfig = configuration.meHeaderConfiguration { + let headerView = MeHeaderView() + headerView.update(with: headerConfig) + tableView.tableHeaderView = headerView + } registerObservers() } @@ -144,19 +156,34 @@ private extension SupportTableViewController { footerText: LocalizedText.helpFooter) // Information Section - let versionRow = TextRow(title: LocalizedText.version, value: Bundle.main.shortVersionString()) - let switchRow = SwitchRow(title: LocalizedText.extraDebug, - value: userDefaults.bool(forKey: UserDefaultsKeys.extraDebug), - onChange: extraDebugToggled()) - let logsRow = NavigationItemRow(title: LocalizedText.activityLogs, action: activityLogsSelected(), accessibilityIdentifier: "activity-logs-button") + var informationSection: ImmuTableSection? + if configuration.showsLogsSection { + let versionRow = TextRow(title: LocalizedText.version, value: Bundle.main.shortVersionString()) + let switchRow = SwitchRow(title: LocalizedText.extraDebug, + value: userDefaults.bool(forKey: UserDefaultsKeys.extraDebug), + onChange: extraDebugToggled()) + let logsRow = NavigationItemRow(title: LocalizedText.activityLogs, action: activityLogsSelected(), accessibilityIdentifier: "activity-logs-button") + informationSection = ImmuTableSection( + headerText: nil, + rows: [versionRow, switchRow, logsRow], + footerText: LocalizedText.informationFooter + ) + } - let informationSection = ImmuTableSection( - headerText: nil, - rows: [versionRow, switchRow, logsRow], - footerText: LocalizedText.informationFooter) + // Log out Section + var logOutSections: ImmuTableSection? + if configuration.showsLogOutButton { + let logOutRow = DestructiveButtonRow( + title: LocalizedText.logOutButtonTitle, + action: logOutTapped(), + accessibilityIdentifier: "" + ) + logOutSections = .init(headerText: LocalizedText.wpAccount, optionalRows: [logOutRow]) + } // Create and return table - return ImmuTable(sections: [helpSection, informationSection]) + let sections = [helpSection, informationSection, logOutSections].compactMap { $0 } + return ImmuTable(sections: sections) } @objc func refreshNotificationIndicator(_ notification: Foundation.Notification) { @@ -274,6 +301,17 @@ private extension SupportTableViewController { } } + private func logOutTapped() -> ImmuTableAction { + return { [weak self] row in + guard let self else { + return + } + self.tableView.deselectSelectedRowWithAnimation(true) + let actionHandler = LogOutActionHandler() + actionHandler.logOut(with: self) + } + } + // MARK: - ImmuTableRow Struct struct HelpRow: ImmuTableRow { @@ -345,6 +383,8 @@ private extension SupportTableViewController { static let contactEmail = NSLocalizedString("Contact Email", comment: "Support email label.") static let contactEmailAccessibilityHint = NSLocalizedString("Shows a dialog for changing the Contact Email.", comment: "Accessibility hint describing what happens if the Contact Email button is tapped.") static let emailNotSet = NSLocalizedString("Not Set", comment: "Display value for Support email field if there is no user email address.") + static let wpAccount = NSLocalizedString("WordPress.com Account", comment: "WordPress.com sign-out section header title") + static let logOutButtonTitle = NSLocalizedString("Log Out", comment: "Button for confirming logging out from WordPress.com account") } // MARK: - User Defaults Keys diff --git a/WordPress/Classes/ViewRelated/Support/SupportTableViewControllerConfiguration.swift b/WordPress/Classes/ViewRelated/Support/SupportTableViewControllerConfiguration.swift new file mode 100644 index 000000000000..9b2c93160814 --- /dev/null +++ b/WordPress/Classes/ViewRelated/Support/SupportTableViewControllerConfiguration.swift @@ -0,0 +1,37 @@ +import Foundation + +struct SupportTableViewControllerConfiguration { + + // MARK: Properties + + var meHeaderConfiguration: MeHeaderView.Configuration? + var showsLogOutButton: Bool = false + var showsLogsSection: Bool = true + + // MARK: Default Configurations + + static func currentAccountConfiguration() -> Self { + var config = Self.init() + if let account = Self.makeAccount() { + config.meHeaderConfiguration = .init(account: account) + config.showsLogOutButton = true + config.showsLogsSection = false + } + return config + } + + private static func makeAccount() -> WPAccount? { + let context = ContextManager.shared.mainContext + do { + return try WPAccount.lookupDefaultWordPressComAccount(in: context) + } catch { + DDLogError("Account lookup failed with error: \(error)") + return nil + } + } +} + +extension SupportTableViewController { + + typealias Configuration = SupportTableViewControllerConfiguration +} diff --git a/WordPress/Jetpack/Classes/ViewRelated/WordPress-to-Jetpack Migration/Common/MigrationDependencyContainer.swift b/WordPress/Jetpack/Classes/ViewRelated/WordPress-to-Jetpack Migration/Common/MigrationDependencyContainer.swift index f37424fb1a17..e5715b52ce2a 100644 --- a/WordPress/Jetpack/Classes/ViewRelated/WordPress-to-Jetpack Migration/Common/MigrationDependencyContainer.swift +++ b/WordPress/Jetpack/Classes/ViewRelated/WordPress-to-Jetpack Migration/Common/MigrationDependencyContainer.swift @@ -44,12 +44,30 @@ struct MigrationViewControllerFactory { } } - private func makeWelcomeViewModel() -> MigrationWelcomeViewModel { - MigrationWelcomeViewModel(account: makeAccount(), coordinator: coordinator) + // MARK: - View Controllers + + private func makeWelcomeViewModel(handlers: ActionHandlers) -> MigrationWelcomeViewModel { + let primaryHandler = { () -> Void in handlers.primary?() } + let secondaryHandler = { () -> Void in handlers.secondary?() } + + let actions = MigrationActionsViewConfiguration( + step: .welcome, + primaryHandler: primaryHandler, + secondaryHandler: secondaryHandler + ) + + return .init(account: makeAccount(), actions: actions) } private func makeWelcomeViewController() -> UIViewController { - MigrationWelcomeViewController(viewModel: makeWelcomeViewModel()) + let handlers = ActionHandlers() + let viewModel = makeWelcomeViewModel(handlers: handlers) + + let viewController = MigrationWelcomeViewController(viewModel: viewModel) + handlers.primary = { [weak coordinator] in coordinator?.transitionToNextStep() } + handlers.secondary = makeSupportViewControllerRouter(with: viewController) + + return viewController } private func makeNotificationsViewModel() -> MigrationNotificationsViewModel { @@ -67,4 +85,20 @@ struct MigrationViewControllerFactory { private func makeDoneViewController() -> UIViewController { MigrationDoneViewController(viewModel: makeDoneViewModel()) } + + // MARK: - Routers + + private func makeSupportViewControllerRouter(with presenter: UIViewController) -> () -> Void { + return { [weak presenter] in + let destination = SupportTableViewController(configuration: .currentAccountConfiguration(), style: .insetGrouped) + presenter?.present(UINavigationController(rootViewController: destination), animated: true) + } + } + + // MARK: - Types + + private class ActionHandlers { + var primary: (() -> Void)? + var secondary: (() -> Void)? + } } diff --git a/WordPress/Jetpack/Classes/ViewRelated/WordPress-to-Jetpack Migration/Common/Navigation/MigrationNavigationController.swift b/WordPress/Jetpack/Classes/ViewRelated/WordPress-to-Jetpack Migration/Common/Navigation/MigrationNavigationController.swift index ee334108bfb7..a0567d625138 100644 --- a/WordPress/Jetpack/Classes/ViewRelated/WordPress-to-Jetpack Migration/Common/Navigation/MigrationNavigationController.swift +++ b/WordPress/Jetpack/Classes/ViewRelated/WordPress-to-Jetpack Migration/Common/Navigation/MigrationNavigationController.swift @@ -10,6 +10,9 @@ class MigrationNavigationController: UINavigationController { private var cancellable: AnyCancellable? override var supportedInterfaceOrientations: UIInterfaceOrientationMask { + if let presentedViewController { + return presentedViewController.supportedInterfaceOrientations + } if WPDeviceIdentification.isiPhone() { return .portrait } else { @@ -17,8 +20,12 @@ class MigrationNavigationController: UINavigationController { } } + // Force portrait orientation for migration view controllers only override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation { - .portrait + if let presentedViewController { + return presentedViewController.preferredInterfaceOrientationForPresentation + } + return .portrait } init(coordinator: MigrationFlowCoordinator, factory: MigrationViewControllerFactory) { diff --git a/WordPress/Jetpack/Classes/ViewRelated/WordPress-to-Jetpack Migration/Welcome/MigrationWelcomeViewController.swift b/WordPress/Jetpack/Classes/ViewRelated/WordPress-to-Jetpack Migration/Welcome/MigrationWelcomeViewController.swift index a3d20166d9b6..4c214c450697 100644 --- a/WordPress/Jetpack/Classes/ViewRelated/WordPress-to-Jetpack Migration/Welcome/MigrationWelcomeViewController.swift +++ b/WordPress/Jetpack/Classes/ViewRelated/WordPress-to-Jetpack Migration/Welcome/MigrationWelcomeViewController.swift @@ -65,7 +65,9 @@ final class MigrationWelcomeViewController: UIViewController { } private func setupNavigationBar() { - self.navigationItem.rightBarButtonItem = UIBarButtonItem(email: viewModel.gravatarEmail) + self.navigationItem.rightBarButtonItem = UIBarButtonItem(email: viewModel.gravatarEmail) { [weak self] () -> Void in + self?.viewModel.configuration.actionsConfiguration.secondaryHandler?() + } } private func setupBottomSheet() { diff --git a/WordPress/Jetpack/Classes/ViewRelated/WordPress-to-Jetpack Migration/Welcome/MigrationWelcomeViewModel.swift b/WordPress/Jetpack/Classes/ViewRelated/WordPress-to-Jetpack Migration/Welcome/MigrationWelcomeViewModel.swift index 04eb1ffa3a1a..9d63a7dad152 100644 --- a/WordPress/Jetpack/Classes/ViewRelated/WordPress-to-Jetpack Migration/Welcome/MigrationWelcomeViewModel.swift +++ b/WordPress/Jetpack/Classes/ViewRelated/WordPress-to-Jetpack Migration/Welcome/MigrationWelcomeViewModel.swift @@ -4,34 +4,35 @@ final class MigrationWelcomeViewModel { // MARK: - Properties - var gravatarEmail: String? - - let blogListDataSource: BlogListDataSource - + let gravatarEmail: String? let configuration: MigrationStepConfiguration + let blogListDataSource: BlogListDataSource // MARK: - Init - init(account: WPAccount?, coordinator: MigrationFlowCoordinator) { - if let account { - self.gravatarEmail = account.email - } - - self.blogListDataSource = BlogListDataSource() - self.blogListDataSource.loggedIn = true - self.blogListDataSource.account = account - - let headerConfiguration = MigrationHeaderConfiguration(step: .welcome, - multiSite: blogListDataSource.visibleBlogsCount > 1) - - let actionsConfiguration = MigrationActionsViewConfiguration(step: .welcome, - primaryHandler: { [weak coordinator] in - coordinator?.transitionToNextStep() - }, - secondaryHandler: { }) + init(gravatarEmail: String?, blogListDataSource: BlogListDataSource, configuration: MigrationStepConfiguration) { + self.gravatarEmail = gravatarEmail + self.configuration = configuration + self.blogListDataSource = blogListDataSource + } - configuration = MigrationStepConfiguration(headerConfiguration: headerConfiguration, - centerViewConfiguration: nil, - actionsConfiguration: actionsConfiguration) + convenience init(account: WPAccount?, actions: MigrationActionsViewConfiguration) { + let blogsDataSource = BlogListDataSource() + blogsDataSource.loggedIn = true + blogsDataSource.account = account + let header = MigrationHeaderConfiguration( + step: .welcome, + multiSite: blogsDataSource.visibleBlogsCount > 1 + ) + let configuration = MigrationStepConfiguration( + headerConfiguration: header, + centerViewConfiguration: nil, + actionsConfiguration: actions + ) + self.init( + gravatarEmail: account?.email, + blogListDataSource: blogsDataSource, + configuration: configuration + ) } } diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index a57b1f211c5c..d94e1dd03ef9 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -3390,6 +3390,11 @@ F465980C28E66A5B00D5F49A /* white-on-blue-icon-app-83.5@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = F465980728E66A5B00D5F49A /* white-on-blue-icon-app-83.5@2x.png */; }; F4BECD1B288EE5220078391A /* SuggestionsViewModelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4BECD1A288EE5220078391A /* SuggestionsViewModelType.swift */; }; F4BECD1C288EE5220078391A /* SuggestionsViewModelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4BECD1A288EE5220078391A /* SuggestionsViewModelType.swift */; }; + F4CBE3D429258AE1004FFBB6 /* MeHeaderViewConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4FB0ACC292587D500F651F9 /* MeHeaderViewConfiguration.swift */; }; + F4CBE3D6292597E3004FFBB6 /* SupportTableViewControllerConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4CBE3D5292597E3004FFBB6 /* SupportTableViewControllerConfiguration.swift */; }; + F4CBE3D7292597E3004FFBB6 /* SupportTableViewControllerConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4CBE3D5292597E3004FFBB6 /* SupportTableViewControllerConfiguration.swift */; }; + F4CBE3D929265BC8004FFBB6 /* LogOutActionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4CBE3D829265BC8004FFBB6 /* LogOutActionHandler.swift */; }; + F4CBE3DA29265BC8004FFBB6 /* LogOutActionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4CBE3D829265BC8004FFBB6 /* LogOutActionHandler.swift */; }; F4D9AF4F288AD2E300803D40 /* SuggestionViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4D9AF4E288AD2E300803D40 /* SuggestionViewModelTests.swift */; }; F4D9AF51288AE23500803D40 /* SuggestionTableViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4D9AF50288AE23500803D40 /* SuggestionTableViewTests.swift */; }; F4D9AF53288AE2BA00803D40 /* SuggestionsTableViewDelegateMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4D9AF52288AE2BA00803D40 /* SuggestionsTableViewDelegateMock.swift */; }; @@ -3398,6 +3403,7 @@ F4F9D5EC29096CF500502576 /* MigrationHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4F9D5EB29096CF500502576 /* MigrationHeaderView.swift */; }; F4F9D5F2290993D400502576 /* MigrationWelcomeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4F9D5F1290993D400502576 /* MigrationWelcomeViewModel.swift */; }; F4F9D5F42909B7C100502576 /* MigrationWelcomeBlogTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4F9D5F32909B7C100502576 /* MigrationWelcomeBlogTableViewCell.swift */; }; + F4FB0ACD292587D500F651F9 /* MeHeaderViewConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4FB0ACC292587D500F651F9 /* MeHeaderViewConfiguration.swift */; }; F504D2B025D60C5900A2764C /* StoryPoster.swift in Sources */ = {isa = PBXBuildFile; fileRef = F504D2AA25D60C5900A2764C /* StoryPoster.swift */; }; F504D2B125D60C5900A2764C /* StoryMediaLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = F504D2AB25D60C5900A2764C /* StoryMediaLoader.swift */; }; F504D43725D717EF00A2764C /* PostEditor+BlogPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91DCE84321A6A7840062F134 /* PostEditor+BlogPicker.swift */; }; @@ -5940,7 +5946,6 @@ 30EABE0818A5903400B73A9C /* WPBlogTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WPBlogTableViewCell.m; sourceTree = ""; }; 310186691A373B01008F7DF6 /* WPTabBarController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WPTabBarController.h; sourceTree = ""; }; 3101866A1A373B01008F7DF6 /* WPTabBarController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WPTabBarController.m; sourceTree = ""; }; - 315FC2C31A2CB29300E7CDA2 /* MeHeaderView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MeHeaderView.h; sourceTree = ""; }; 315FC2C41A2CB29300E7CDA2 /* MeHeaderView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MeHeaderView.m; sourceTree = ""; }; 316B99031B205AFB007963EF /* WordPress 32.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "WordPress 32.xcdatamodel"; sourceTree = ""; }; 319D6E7F19E44C680013871C /* SuggestionsTableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SuggestionsTableView.h; path = Suggestions/SuggestionsTableView.h; sourceTree = ""; }; @@ -8517,6 +8522,9 @@ F465980628E66A5A00D5F49A /* white-on-blue-icon-app-60@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "white-on-blue-icon-app-60@2x.png"; sourceTree = ""; }; F465980728E66A5B00D5F49A /* white-on-blue-icon-app-83.5@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "white-on-blue-icon-app-83.5@2x.png"; sourceTree = ""; }; F4BECD1A288EE5220078391A /* SuggestionsViewModelType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SuggestionsViewModelType.swift; sourceTree = ""; }; + F4CBE3D329258AD6004FFBB6 /* MeHeaderView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MeHeaderView.h; sourceTree = ""; }; + F4CBE3D5292597E3004FFBB6 /* SupportTableViewControllerConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SupportTableViewControllerConfiguration.swift; sourceTree = ""; }; + F4CBE3D829265BC8004FFBB6 /* LogOutActionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogOutActionHandler.swift; sourceTree = ""; }; F4D9AF4E288AD2E300803D40 /* SuggestionViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SuggestionViewModelTests.swift; sourceTree = ""; }; F4D9AF50288AE23500803D40 /* SuggestionTableViewTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SuggestionTableViewTests.swift; sourceTree = ""; }; F4D9AF52288AE2BA00803D40 /* SuggestionsTableViewDelegateMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SuggestionsTableViewDelegateMock.swift; sourceTree = ""; }; @@ -8525,6 +8533,7 @@ F4F9D5EB29096CF500502576 /* MigrationHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrationHeaderView.swift; sourceTree = ""; }; F4F9D5F1290993D400502576 /* MigrationWelcomeViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrationWelcomeViewModel.swift; sourceTree = ""; }; F4F9D5F32909B7C100502576 /* MigrationWelcomeBlogTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrationWelcomeBlogTableViewCell.swift; sourceTree = ""; }; + F4FB0ACC292587D500F651F9 /* MeHeaderViewConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeHeaderViewConfiguration.swift; sourceTree = ""; }; F504D2AA25D60C5900A2764C /* StoryPoster.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StoryPoster.swift; sourceTree = ""; }; F504D2AB25D60C5900A2764C /* StoryMediaLoader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StoryMediaLoader.swift; sourceTree = ""; }; F50B0E7A246212B8006601DD /* NoticeAnimator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoticeAnimator.swift; sourceTree = ""; }; @@ -10095,6 +10104,7 @@ 31F4F6641A13858F00196A98 /* Me */ = { isa = PBXGroup; children = ( + F4FB0ACB2925878E00F651F9 /* Views */, 3F29EB70240421F6005313DE /* Account Settings */, 3F29EB6E240420C3005313DE /* App Settings */, 3F29EB6F2404218E005313DE /* Help & Support */, @@ -10328,7 +10338,6 @@ children = ( E1A8CACA1C22FF7C0038689E /* MeViewController.swift */, 3F29EB7124042276005313DE /* MeViewController+UIViewControllerRestoration.swift */, - 3F29EB6C24042038005313DE /* Header */, 3F43602D23F31C06001DEE70 /* Presenter */, ); path = "Me Main"; @@ -10337,8 +10346,9 @@ 3F29EB6C24042038005313DE /* Header */ = { isa = PBXGroup; children = ( - 315FC2C31A2CB29300E7CDA2 /* MeHeaderView.h */, 315FC2C41A2CB29300E7CDA2 /* MeHeaderView.m */, + F4FB0ACC292587D500F651F9 /* MeHeaderViewConfiguration.swift */, + F4CBE3D329258AD6004FFBB6 /* MeHeaderView.h */, ); path = Header; sourceTree = ""; @@ -13230,6 +13240,8 @@ isa = PBXGroup; children = ( 98077B592075561800109F95 /* SupportTableViewController.swift */, + F4CBE3D5292597E3004FFBB6 /* SupportTableViewControllerConfiguration.swift */, + F4CBE3D829265BC8004FFBB6 /* LogOutActionHandler.swift */, ); path = Support; sourceTree = ""; @@ -16506,6 +16518,14 @@ path = Views; sourceTree = ""; }; + F4FB0ACB2925878E00F651F9 /* Views */ = { + isa = PBXGroup; + children = ( + 3F29EB6C24042038005313DE /* Header */, + ); + path = Views; + sourceTree = ""; + }; F504D2A925D60C5900A2764C /* Stories */ = { isa = PBXGroup; children = ( @@ -19705,6 +19725,7 @@ 175A650C20B6F7280023E71B /* ReaderSaveForLater+Analytics.swift in Sources */, 4054F4572214E3C800D261AB /* TagsCategoriesStatsRecordValue+CoreDataProperties.swift in Sources */, 9A2B28F52192121400458F2A /* RevisionOperation.swift in Sources */, + F4FB0ACD292587D500F651F9 /* MeHeaderViewConfiguration.swift in Sources */, 984B4EF320742FCC00F87888 /* ZendeskUtils.swift in Sources */, F580C3CB23D8F9B40038E243 /* AbstractPost+Dates.swift in Sources */, 982DDF90263238A6002B3904 /* LikeUser+CoreDataClass.swift in Sources */, @@ -21005,6 +21026,7 @@ E6D2E1691B8AAD9B0000ED14 /* ReaderListStreamHeader.swift in Sources */, 981D092A211259840014ECAF /* NoResultsViewController+MediaLibrary.swift in Sources */, D83CA3B02084CAAF0060E310 /* StockPhotosDataLoader.swift in Sources */, + F4CBE3D929265BC8004FFBB6 /* LogOutActionHandler.swift in Sources */, E66969DA1B9E55AB00EC9C00 /* ReaderTopicToReaderTagTopic37to38.swift in Sources */, 9A4E271A22EF0C78001F6A6B /* ChangeUsernameViewModel.swift in Sources */, 172797D91CE5D0CD00CB8057 /* PlansLoadingIndicatorView.swift in Sources */, @@ -21368,6 +21390,7 @@ 400A2C872217A985000A8A59 /* ReferrerStatsRecordValue+CoreDataProperties.swift in Sources */, 57AA848F228715DA00D3C2A2 /* PostCardCell.swift in Sources */, FE43DAAF26DFAD1C00CFF595 /* CommentContentTableViewCell.swift in Sources */, + F4CBE3D6292597E3004FFBB6 /* SupportTableViewControllerConfiguration.swift in Sources */, 8F22804451E5812433733348 /* TimeZoneSearchHeaderView.swift in Sources */, 8F228F2923045666AE456D2C /* TimeZoneSelectorViewController.swift in Sources */, ); @@ -22579,6 +22602,7 @@ FE4C46FF27FAE61700285F35 /* DashboardPromptsCardCell.swift in Sources */, FABB21972602FC2C00C8785C /* MenusViewController.m in Sources */, FABB21982602FC2C00C8785C /* UIViewController+Notice.swift in Sources */, + F4CBE3D7292597E3004FFBB6 /* SupportTableViewControllerConfiguration.swift in Sources */, FABB21992602FC2C00C8785C /* GutenbergFileUploadProcessor.swift in Sources */, FABB219A2602FC2C00C8785C /* EventLoggingDataProvider.swift in Sources */, FABB219B2602FC2C00C8785C /* PageListSectionHeaderView.swift in Sources */, @@ -23588,6 +23612,7 @@ FABB24BF2602FC2C00C8785C /* EpilogueUserInfoCell.swift in Sources */, FABB24C02602FC2C00C8785C /* MenuItemTypeSelectionView.m in Sources */, FABB24C12602FC2C00C8785C /* WordPressAppDelegate+openURL.swift in Sources */, + F4CBE3DA29265BC8004FFBB6 /* LogOutActionHandler.swift in Sources */, FABB24C22602FC2C00C8785C /* WPSplitViewController.swift in Sources */, FABB24C32602FC2C00C8785C /* CollectionViewContainerRow.swift in Sources */, FABB24C42602FC2C00C8785C /* JetpackConnectionWebViewController.swift in Sources */, @@ -23969,6 +23994,7 @@ FABB25EA2602FC2C00C8785C /* PeopleRoleBadgeLabel.swift in Sources */, FABB25EB2602FC2C00C8785C /* ActivityDetailViewController.swift in Sources */, FABB25EC2602FC2C00C8785C /* BlogListViewController+BlogDetailsFactory.swift in Sources */, + F4CBE3D429258AE1004FFBB6 /* MeHeaderViewConfiguration.swift in Sources */, C32A6A2D2832BF02002E9394 /* SiteDesignCategoryThumbnailSize.swift in Sources */, FABB25ED2602FC2C00C8785C /* WebViewControllerConfiguration.swift in Sources */, FABB25EE2602FC2C00C8785C /* ViewMoreRow.swift in Sources */,