Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show the "Verify Your Email" view on no sites view #24211

Closed
wants to merge 10 commits into from
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@ class WelcomeSplitViewContent: SplitViewDisplayable {
init(addSite: @escaping (AddSiteMenuViewModel.Selection) -> Void) {
supplementary = UINavigationController(rootViewController: UnifiedPrologueViewController())

let addSiteViewModel = AddSiteMenuViewModel(context: .shared, onSelection: addSite)
let noSitesViewModel = NoSitesViewModel(appUIType: JetpackFeaturesRemovalCoordinator.currentAppUIType, account: nil)
let noSiteView = NoSitesView(addSiteViewModel: addSiteViewModel, viewModel: noSitesViewModel)
let noSitesVC = UIHostingController(rootView: noSiteView)
noSitesVC.view.backgroundColor = .systemBackground
secondary = UINavigationController(rootViewController: noSitesVC)
if let account = try? WPAccount.lookupDefaultWordPressComAccount(in: ContextManager.shared.mainContext) {
let noSiteView = NoSitesView(account: account, appUIType: JetpackFeaturesRemovalCoordinator.currentAppUIType, onSelection: addSite)
let noSitesVC = UIHostingController(rootView: noSiteView)
noSitesVC.view.backgroundColor = .systemBackground
secondary = UINavigationController(rootViewController: noSitesVC)
} else {
// This branch should never execute, because we only show the "Welcome" screen when the WP.com account does not have any sites.
secondary = UINavigationController()
}
}

func displayed(in splitVC: UISplitViewController) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,25 +131,7 @@ final class MySiteViewController: UIViewController, UIScrollViewDelegate, NoSite
private var noSitesScrollView: UIScrollView?
private var noSitesRefreshControl: UIRefreshControl?

private lazy var noSitesViewController: UIHostingController = {
let addSiteViewModel = AddSiteMenuViewModel { [weak self] in
switch $0 {
case .dotCom:
self?.launchSiteCreationFromNoSites()
RootViewCoordinator.shared.isSiteCreationActive = true
case .selfHosted:
self?.launchLoginForSelfHostedSite()
}
}
let noSitesViewModel = NoSitesViewModel(
appUIType: JetpackFeaturesRemovalCoordinator.currentAppUIType,
account: self.viewModel.defaultAccount
)
let noSiteView = NoSitesView(addSiteViewModel: addSiteViewModel, viewModel: noSitesViewModel)
let hostingVC = UIHostingController(rootView: noSiteView)
hostingVC.view.backgroundColor = .clear
return hostingVC
}()
private var noSitesViewController: UIHostingController<NoSitesView>?

private var isNavigationBarHidden = false

Expand Down Expand Up @@ -178,6 +160,10 @@ final class MySiteViewController: UIViewController, UIScrollViewDelegate, NoSite
}

configureNavBarAppearance(animated: animated)

if let account = self.viewModel.defaultAccount {
AccountService(coreDataStack: ContextManager.shared).updateUserDetails(for: account, success: nil, failure: nil)
}
}

override func viewWillDisappear(_ animated: Bool) {
Expand Down Expand Up @@ -228,7 +214,7 @@ final class MySiteViewController: UIViewController, UIScrollViewDelegate, NoSite

private func subscribeToWillEnterForeground() {
NotificationCenter.default.addObserver(self,
selector: #selector(displayOverlayIfNeeded),
selector: #selector(willEnterForeground),
name: UIApplication.willEnterForegroundNotification,
object: nil)
}
Expand Down Expand Up @@ -460,6 +446,8 @@ final class MySiteViewController: UIViewController, UIScrollViewDelegate, NoSite
// MARK: - No Sites UI logic

private func hideNoSites() {
guard let noSitesViewController else { return }

// Only track if the no sites view is currently visible
if noSitesViewController.view.superview != nil {
WPAnalytics.track(.mySiteNoSitesViewHidden)
Expand All @@ -473,23 +461,50 @@ final class MySiteViewController: UIViewController, UIScrollViewDelegate, NoSite
}

private func showNoSites() {
guard AccountHelper.isLoggedIn else {
guard let account = self.viewModel.defaultAccount else {
WordPressAppDelegate.shared?.windowManager.showFullscreenSignIn()
return
}

guard noSitesViewController.view.superview == nil else {
if let noSitesViewController, noSitesViewController.rootView.account.objectID != self.viewModel.defaultAccount?.objectID {
self.hideNoSites()
}

let viewController: UIHostingController<NoSitesView>
if let noSitesViewController, noSitesViewController.rootView.account == self.viewModel.defaultAccount?.objectID {
viewController = noSitesViewController
} else {
let view = NoSitesView(account: account, appUIType: JetpackFeaturesRemovalCoordinator.currentAppUIType) { [weak self] in
switch $0 {
case .dotCom:
if self?.viewModel.defaultAccount?.needsEmailVerification == true {
self?.presentNeedsEmailVerificationAlert()
return
}

self?.launchSiteCreationFromNoSites()
RootViewCoordinator.shared.isSiteCreationActive = true
case .selfHosted:
self?.launchLoginForSelfHostedSite()
}
}
viewController = UIHostingController(rootView: view)
viewController.view.backgroundColor = .clear
self.noSitesViewController = viewController
}

guard viewController.view.superview == nil else {
return
}

makeNoSitesScrollView()
configureNoSitesView()
addNoSitesViewAndConfigureConstraints()
configureNoSitesView(viewController)
addNoSitesViewAndConfigureConstraints(viewController)
createButtonCoordinator?.removeCreateButton()
}

private func trackNoSitesVisibleIfNeeded() {
guard noSitesViewController.view.superview != nil else {
guard let noSitesViewController, noSitesViewController.view.superview != nil else {
return
}

Expand All @@ -512,11 +527,11 @@ final class MySiteViewController: UIViewController, UIScrollViewDelegate, NoSite
noSitesScrollView = scrollView
}

private func configureNoSitesView() {
private func configureNoSitesView(_ noSitesViewController: UIHostingController<NoSitesView>) {
noSitesViewController.rootView.delegate = self
}

private func addNoSitesViewAndConfigureConstraints() {
private func addNoSitesViewAndConfigureConstraints(_ noSitesViewController: UIHostingController<NoSitesView>) {
guard let scrollView = noSitesScrollView else {
return
}
Expand Down Expand Up @@ -560,6 +575,7 @@ final class MySiteViewController: UIViewController, UIScrollViewDelegate, NoSite
bottomAnchor: view.safeAreaLayoutGuide.bottomAnchor)

if let blog,
let noSitesViewController,
noSitesViewController.view.superview == nil {
createButtonCoordinator?.showCreateButton(for: blog)
}
Expand Down Expand Up @@ -597,6 +613,16 @@ final class MySiteViewController: UIViewController, UIScrollViewDelegate, NoSite
})
}

private func presentNeedsEmailVerificationAlert() {
let alert = UIAlertController(
title: NSLocalizedString("noSites.verifyEmail.title", value: "Verify Your Email", comment: "Title for email verification alert"),
message: NSLocalizedString("noSites.verifyEmail.message", value: "You need to verify your email to create a new site.", comment: "Message for email verification alert"),
preferredStyle: .alert
)
alert.addAction(UIAlertAction(title: SharedStrings.Button.close, style: .cancel, handler: nil))
present(alert, animated: true)
}

@objc
private func showAddSelfHostedSite() {
WordPressAuthenticator.showLoginForSelfHostedSite(self)
Expand Down Expand Up @@ -880,6 +906,14 @@ extension MySiteViewController: BlogDetailsPresentationDelegate {
// MARK: Jetpack Features Removal

private extension MySiteViewController {
@objc func willEnterForeground() {
displayOverlayIfNeeded()

if let account = self.viewModel.defaultAccount {
AccountService(coreDataStack: ContextManager.shared).updateUserDetails(for: account, success: nil, failure: nil)
}
}

@objc func displayOverlayIfNeeded() {
if isViewOnScreen() && !RootViewCoordinator.shared.isSiteCreationActive {
let didReloadUI = RootViewCoordinator.shared.reloadUIIfNeeded(blog: self.blog)
Expand Down
43 changes: 30 additions & 13 deletions WordPress/Classes/ViewRelated/Blog/My Site/NoSitesView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ protocol NoSitesViewDelegate: AnyObject {
}

struct NoSitesView: View {
let addSiteViewModel: AddSiteMenuViewModel
let viewModel: NoSitesViewModel
@ObservedObject var account: WPAccount

let appUIType: RootViewCoordinator.AppUIType?
let onSelection: (AddSiteMenuViewModel.Selection) -> Void
weak var delegate: NoSitesViewDelegate?

@Environment(\.horizontalSizeClass) var horizontalSizeClass
Expand All @@ -19,8 +21,22 @@ struct NoSitesView: View {
emptyStateView
.frame(maxHeight: .infinity, alignment: .center)

if account.verificationStatus != .verified {
Group {
VerifyEmailView(fillVerticalSpace: false)
.background(
RoundedRectangle(cornerRadius: 8)
.fill(.white)
)
.frame(maxWidth: .infinity, alignment: .leading)
}
.padding(.horizontal, .DS.Padding.medium)
.padding(.bottom, .DS.Padding.medium)
}

let viewModel = NoSitesViewModel(appUIType: appUIType, account: account)
if viewModel.isShowingAccountAndSettings, horizontalSizeClass == .compact {
accountAndSettingsButton
accountAndSettingsButton(viewModel: viewModel)
.padding(.horizontal, .DS.Padding.large)
.padding(.bottom, .DS.Padding.medium)
}
Expand All @@ -36,12 +52,13 @@ struct NoSitesView: View {
Text(Strings.description)
} actions: {
VStack(spacing: 20) {
ForEach(addSiteViewModel.actions) { action in
let actions = AddSiteMenuViewModel(onSelection: onSelection).actions
ForEach(actions, id: \.id) { action in
let button = Button(action.title) {
WPAnalytics.track(.mySiteNoSitesViewActionTapped)
action.handler()
}
if action.id == addSiteViewModel.actions.first?.id {
WPAnalytics.track(.mySiteNoSitesViewActionTapped)
action.handler()
}
if action.id == actions.first?.id {
button.buttonStyle(.primary)
} else {
button
Expand All @@ -51,13 +68,13 @@ struct NoSitesView: View {
}
}

private var accountAndSettingsButton: some View {
private func accountAndSettingsButton(viewModel: NoSitesViewModel) -> some View {
Button {
delegate?.didTapAccountAndSettingsButton()
} label: {
HStack(alignment: .center, spacing: .DS.Padding.double) {
makeGravatarIcon(size: 40)
accountAndSettingsStackView
makeGravatarIcon(size: 40, viewModel: viewModel)
accountAndSettingsStackView(viewModel: viewModel)
Spacer()
Image(systemName: "chevron.forward")
.tint(.secondary)
Expand All @@ -69,7 +86,7 @@ struct NoSitesView: View {
}
}

private var accountAndSettingsStackView: some View {
private func accountAndSettingsStackView(viewModel: NoSitesViewModel) -> some View {
VStack(alignment: .leading) {
Text(viewModel.displayName)
.foregroundColor(.primary)
Expand All @@ -84,7 +101,7 @@ struct NoSitesView: View {
}
}

private func makeGravatarIcon(size: CGFloat) -> some View {
private func makeGravatarIcon(size: CGFloat, viewModel: NoSitesViewModel) -> some View {
AsyncImage(url: viewModel.gravatarURL) { phase in
switch phase {
case .success(let image):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,11 @@ struct AddSiteMenuViewModel {
}

struct Action: Identifiable {
let id = UUID()
var id: Selection {
selection
}

let selection: Selection
let title: String
let handler: () -> Void

Expand All @@ -85,14 +89,14 @@ struct AddSiteMenuViewModel {
let canAddSelfHostedSite = AppConfiguration.showAddSelfHostedSiteButton

var actions: [Action] = []
if defaultAccount != nil {
actions.append(Action(title: Strings.createDotComSite) {
if let defaultAccount {
actions.append(Action(selection: .dotCom, title: Strings.createDotComSite) {
onSelection(.dotCom)
})
}

if canAddSelfHostedSite {
actions.append(Action(title: Strings.addSelfHostedSite) {
actions.append(Action(selection: .selfHosted, title: Strings.addSelfHostedSite) {
onSelection(.selfHosted)
})
}
Expand Down
22 changes: 18 additions & 4 deletions WordPress/Classes/ViewRelated/Me/Me Main/MeViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class MeViewController: UITableViewController {
}

ImmuTable.registerRows([
VerifyEmailRow.self,
NavigationItemRow.self,
IndicatorNavigationItemRow.self,
ButtonRow.self,
Expand All @@ -47,6 +48,7 @@ class MeViewController: UITableViewController {
WPStyleGuide.configureAutomaticHeightRows(for: tableView)

NotificationCenter.default.addObserver(self, selector: #selector(MeViewController.accountDidChange), name: NSNotification.Name.WPAccountDefaultWordPressComAccountChanged, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(MeViewController.refreshAccountDetailsAndSettings), name: UIApplication.didBecomeActiveNotification, object: nil)

WPStyleGuide.configureColors(view: view, tableView: tableView)
tableView.accessibilityIdentifier = "Me Table"
Expand Down Expand Up @@ -114,9 +116,13 @@ class MeViewController: UITableViewController {

fileprivate func tableViewModel(with account: WPAccount?) -> ImmuTable {
let accessoryType: UITableViewCell.AccessoryType = .disclosureIndicator

let loggedIn = account != nil

var verificationSection: ImmuTableSection?
if let account, account.verificationStatus == .unverified {
verificationSection = ImmuTableSection(rows: [VerifyEmailRow()])
}

let myProfile = NavigationItemRow(
title: RowTitles.myProfile,
icon: UIImage(named: "site-menu-people")?.withRenderingMode(.alwaysTemplate),
Expand Down Expand Up @@ -162,7 +168,14 @@ class MeViewController: UITableViewController {

let shouldShowQRLoginRow = AppConfiguration.qrLoginEnabled && !(account?.settings?.twoStepEnabled ?? false)

var sections: [ImmuTableSection] = [
var sections: [ImmuTableSection] = []

// Add verification section first if it exists
if let verificationSection {
sections.append(verificationSection)
}

sections.append(contentsOf: [
ImmuTableSection(rows: {
var rows: [ImmuTableRow] = [appSettingsRow]
if loggedIn {
Expand All @@ -176,7 +189,7 @@ class MeViewController: UITableViewController {
return rows
}()),
ImmuTableSection(rows: [helpAndSupportIndicator]),
]
])

#if IS_JETPACK
if RemoteFeatureFlag.domainManagement.enabled() && loggedIn && !isSidebarModeEnabled {
Expand Down Expand Up @@ -405,6 +418,7 @@ class MeViewController: UITableViewController {
}
return false
}

guard let sections = handler?.viewModel.sections,
let section = sections.firstIndex(where: { $0.rows.contains(where: matchRow) }),
let row = sections[section].rows.firstIndex(where: matchRow) else {
Expand Down Expand Up @@ -432,7 +446,7 @@ class MeViewController: UITableViewController {
return try? WPAccount.lookupDefaultWordPressComAccount(in: ContextManager.shared.mainContext)
}

fileprivate func refreshAccountDetailsAndSettings() {
@objc fileprivate func refreshAccountDetailsAndSettings() {
guard let account = defaultAccount(), let api = account.wordPressComRestApi else {
reloadViewModel()
return
Expand Down
Loading