diff --git a/DuckDuckGo/ActionMessageView.swift b/DuckDuckGo/ActionMessageView.swift index f0a3ef3f63..ca419635ae 100644 --- a/DuckDuckGo/ActionMessageView.swift +++ b/DuckDuckGo/ActionMessageView.swift @@ -90,6 +90,7 @@ class ActionMessageView: UIView { numberOfLines: Int = 0, actionTitle: String? = nil, presentationLocation: PresentationLocation = .withBottomBar(andAddressBarBottom: false), + duration: TimeInterval = Constants.duration, onAction: @escaping () -> Void = {}, onDidDismiss: @escaping () -> Void = {}) { let messageView = loadFromXib() @@ -99,6 +100,7 @@ class ActionMessageView: UIView { message: message.string, actionTitle: actionTitle, presentationLocation: presentationLocation, + duration: duration, onAction: onAction, onDidDismiss: onDidDismiss) } @@ -106,6 +108,7 @@ class ActionMessageView: UIView { static func present(message: String, actionTitle: String? = nil, presentationLocation: PresentationLocation = .withBottomBar(andAddressBarBottom: false), + duration: TimeInterval = Constants.duration, onAction: @escaping () -> Void = {}, onDidDismiss: @escaping () -> Void = {}) { let messageView = loadFromXib() @@ -114,6 +117,7 @@ class ActionMessageView: UIView { message: message, actionTitle: actionTitle, presentationLocation: presentationLocation, + duration: duration, onAction: onAction, onDidDismiss: onDidDismiss) } @@ -122,6 +126,7 @@ class ActionMessageView: UIView { message: String, actionTitle: String? = nil, presentationLocation: PresentationLocation = .withBottomBar(andAddressBarBottom: false), + duration: TimeInterval = Constants.duration, onAction: @escaping () -> Void = {}, onDidDismiss: @escaping () -> Void = {}) { guard let window = UIApplication.shared.firstKeyWindow else { return } @@ -159,7 +164,7 @@ class ActionMessageView: UIView { messageView?.dismissAndFadeOut() } messageView.dismissWorkItem = workItem - DispatchQueue.main.asyncAfter(deadline: .now() + Constants.duration, execute: workItem) + DispatchQueue.main.asyncAfter(deadline: .now() + duration, execute: workItem) presentedMessages.append(messageView) } diff --git a/DuckDuckGo/SaveLoginView.swift b/DuckDuckGo/SaveLoginView.swift index af16d6e16a..601441e663 100644 --- a/DuckDuckGo/SaveLoginView.swift +++ b/DuckDuckGo/SaveLoginView.swift @@ -88,15 +88,15 @@ struct SaveLoginView: View { AutofillViews.AppIconHeader() Spacer(minLength: Const.Size.contentSpacing) AutofillViews.Headline(title: title) - Spacer(minLength: 8) + Spacer(minLength: Const.Size.headlineToContentSpacing) contentView Spacer(minLength: Const.Size.contentSpacing) if case .newUser = layoutType { - featuresView.padding([.bottom], 16) + featuresView.padding([.bottom], Const.Size.featuresListPadding) } ctaView } - .padding([.bottom], 24.0) + .padding([.bottom], Const.Size.bodyBottomPadding) .fixedSize(horizontal: false, vertical: shouldFixSize) .background(GeometryReader { proxy -> Color in DispatchQueue.main.async { viewModel.contentHeight = proxy.size.height } @@ -117,16 +117,16 @@ struct SaveLoginView: View { if #available(iOS 16.0, *) { useScrollView = AutofillViews.contentHeightExceedsScreenHeight(viewModel.contentHeight) } else { - useScrollView = viewModel.contentHeight > frame.height + Const.Size.ios15scrollOffset + useScrollView = viewModel.contentHeight > frame.height } return useScrollView } @ViewBuilder private func featuresListItem(imageResource: ImageResource, title: String, subtitle: String) -> some View { - HStack(alignment: .top, spacing: 12) { - Image(imageResource).frame(width: 24, height: 24) - VStack(alignment: .leading, spacing: 2) { + HStack(alignment: .top, spacing: Const.Size.featuresListItemHorizontalSpacing) { + Image(imageResource).frame(width: Const.Size.featuresListItemImageWidthHeight, height: Const.Size.featuresListItemImageWidthHeight) + VStack(alignment: .leading, spacing: Const.Size.featuresListItemVerticalSpacing) { Text(title) .daxSubheadSemibold() .foregroundColor(Color(designSystemColor: .textPrimary)) @@ -146,20 +146,19 @@ struct SaveLoginView: View { @ViewBuilder private var featuresView: some View { VStack(alignment: .leading, spacing: 0) { - HStack(alignment: .center, spacing: 10) { + HStack(alignment: .center) { Text(UserText.autofillOnboardingKeyFeaturesTitle) .font(Font.system(size: 12, weight: .semibold)) .multilineTextAlignment(.center) .foregroundColor(Color(designSystemColor: .textSecondary)) .frame(width: 255, alignment: .top) } - .padding(.horizontal, 0) - .padding(.vertical, 12) + .padding(.vertical, Const.Size.featuresListVerticalSpacing) .frame(maxWidth: .infinity, alignment: .center) Rectangle() .fill(Color(designSystemColor: .container)) .frame(height: 1) - VStack(alignment: .leading, spacing: 12) { + VStack(alignment: .leading, spacing: Const.Size.featuresListVerticalSpacing) { featuresListItem( imageResource: .autofillColor24, title: UserText.autofillOnboardingKeyFeaturesSignInsTitle, @@ -176,15 +175,15 @@ struct SaveLoginView: View { subtitle: UserText.autofillOnboardingKeyFeaturesSyncDescription ) } - .padding(.horizontal, 16) - .padding(.top, 12) - .padding(.bottom, 16) + .padding(.horizontal, Const.Size.featuresListPadding) + .padding(.top, Const.Size.featuresListTopPadding) + .padding(.bottom, Const.Size.featuresListPadding) } .padding(0) .frame(maxWidth: .infinity, alignment: .topLeading) - .cornerRadius(8) + .cornerRadius(Const.Size.featuresListBorderCornerRadius) .overlay( - RoundedRectangle(cornerRadius: 8) + RoundedRectangle(cornerRadius: Const.Size.featuresListBorderCornerRadius) .inset(by: 0.5) .stroke(Color(designSystemColor: .container), lineWidth: 1) ) @@ -243,9 +242,17 @@ private enum Const { static let closeButtonOffsetPortraitSmallFrame: CGFloat = 16.0 static let topPadding: CGFloat = 56.0 static let contentSpacing: CGFloat = 24.0 - static let ios15scrollOffset: CGFloat = 80.0 + static let headlineToContentSpacing: CGFloat = 8.0 static let ctaVerticalSpacing: CGFloat = 8.0 + static let bodyBottomPadding: CGFloat = 24.0 static let featureListItemIconGap: CGFloat = 8.0 + static let featuresListItemImageWidthHeight: CGFloat = 24.0 + static let featuresListItemHorizontalSpacing: CGFloat = 12.0 + static let featuresListItemVerticalSpacing: CGFloat = 2.0 + static let featuresListVerticalSpacing: CGFloat = 12.0 + static let featuresListPadding: CGFloat = 16.0 + static let featuresListTopPadding: CGFloat = 12.0 + static let featuresListBorderCornerRadius: CGFloat = 8.0 } } diff --git a/DuckDuckGo/TabViewController.swift b/DuckDuckGo/TabViewController.swift index 60e82409e0..564a671614 100644 --- a/DuckDuckGo/TabViewController.swift +++ b/DuckDuckGo/TabViewController.swift @@ -2806,6 +2806,7 @@ extension TabViewController: SaveLoginViewControllerDelegate { ActionMessageView.present(message: UserText.autofillDisablePromptMessage, actionTitle: UserText.autofillDisablePromptAction, presentationLocation: .withBottomBar(andAddressBarBottom: addressBarBottom), + duration: 4.0, onAction: { [weak self] in Pixel.fire(pixel: .autofillLoginsFillLoginInlineDisableSnackbarOpenSettings) guard let mainVC = self?.view.window?.rootViewController as? MainViewController else { return } diff --git a/DuckDuckGo/UserText.swift b/DuckDuckGo/UserText.swift index b0928e5243..78cfcc532a 100644 --- a/DuckDuckGo/UserText.swift +++ b/DuckDuckGo/UserText.swift @@ -396,7 +396,7 @@ public struct UserText { public static let autofillUpdateUsernameTitle = NSLocalizedString("autofill.update-usernamr.title", value: "Update username?", comment: "Title displayed on modal asking for the user to update the username") public static let autofillSaveLoginMessageNewUser = NSLocalizedString("autofill.save-login.new-user.message", value: "DuckDuckGo Passwords & Autofill stores passwords securely on your device.", comment: "Message displayed on modal asking for the user to save the login for the first time") - public static let autofillSaveLoginNeverPromptCTA = NSLocalizedString("autofill.save-login.never-prompt.CTA", value: "Never for This Website", comment: "CTA displayed on modal asking if the user never wants to be prompted to save a login for this website agin") + public static let autofillSaveLoginNeverPromptCTA = NSLocalizedString("autofill.save-login.never-prompt.CTA", value: "Never for This Site", comment: "CTA displayed on modal asking if the user never wants to be prompted to save a login for this website agin") public static func autofillUpdatePassword(for title: String) -> String { let message = NSLocalizedString("autofill.update-password.title", value: "Update password for\n%@?", comment: "Title displayed on modal asking for the user to update the password") diff --git a/DuckDuckGo/en.lproj/Localizable.strings b/DuckDuckGo/en.lproj/Localizable.strings index b4da063b58..cf91aee21e 100644 --- a/DuckDuckGo/en.lproj/Localizable.strings +++ b/DuckDuckGo/en.lproj/Localizable.strings @@ -576,7 +576,7 @@ "autofill.removed.duck.address.title" = "Private Duck Address username was removed"; /* CTA displayed on modal asking if the user never wants to be prompted to save a login for this website agin */ -"autofill.save-login.never-prompt.CTA" = "Never for This Website"; +"autofill.save-login.never-prompt.CTA" = "Never for This Site"; /* Message displayed on modal asking for the user to save the login for the first time */ "autofill.save-login.new-user.message" = "DuckDuckGo Passwords & Autofill stores passwords securely on your device.";