Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -263,8 +263,6 @@ private extension StoreCreationCoordinator {
name: storeName,
domain: domain,
planToPurchase: planToPurchase)
}, onSkip: {
// TODO-8045: skip to the next step of store creation with an auto-generated domain.
})
navigationController.pushViewController(domainSelector, animated: false)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,14 @@ import SwiftUI
final class DomainSelectorHostingController: UIHostingController<DomainSelectorView> {
private let viewModel: DomainSelectorViewModel
private let onDomainSelection: (String) async -> Void
private let onSkip: () -> Void

/// - Parameters:
/// - viewModel: View model for the domain selector.
/// - onDomainSelection: Called when the user continues with a selected domain name.
/// - onSkip: Called when the user taps to skip domain selection.
init(viewModel: DomainSelectorViewModel,
onDomainSelection: @escaping (String) async -> Void,
onSkip: @escaping () -> Void) {
onDomainSelection: @escaping (String) async -> Void) {
self.viewModel = viewModel
self.onDomainSelection = onDomainSelection
self.onSkip = onSkip
super.init(rootView: DomainSelectorView(viewModel: viewModel))

rootView.onDomainSelection = { [weak self] domain in
Expand All @@ -30,16 +26,11 @@ final class DomainSelectorHostingController: UIHostingController<DomainSelectorV
override func viewDidLoad() {
super.viewDidLoad()

configureSkipButton()
configureNavigationBarAppearance()
}
}

private extension DomainSelectorHostingController {
func configureSkipButton() {
navigationItem.rightBarButtonItem = .init(title: Localization.skipButtonTitle, style: .plain, target: self, action: #selector(skipButtonTapped))
}

/// Shows a transparent navigation bar without a bottom border.
func configureNavigationBarAppearance() {
let appearance = UINavigationBarAppearance()
Expand All @@ -52,18 +43,6 @@ private extension DomainSelectorHostingController {
}
}

private extension DomainSelectorHostingController {
@objc func skipButtonTapped() {
onSkip()
}
}

private extension DomainSelectorHostingController {
enum Localization {
static let skipButtonTitle = NSLocalizedString("Skip", comment: "Navigation bar button on the domain selector screen to skip domain selection.")
}
}

/// Allows the user to search for a domain and then select one to continue.
struct DomainSelectorView: View {
/// Set in the hosting controller.
Expand All @@ -79,88 +58,112 @@ struct DomainSelectorView: View {

@State private var isWaitingForDomainSelectionCompletion: Bool = false

@FocusState private var textFieldIsFocused: Bool

init(viewModel: DomainSelectorViewModel) {
self.viewModel = viewModel
}

var body: some View {
VStack(alignment: .leading, spacing: 0) {
ScrollView {
VStack(alignment: .leading) {
// Header label.
Text(Localization.subtitle)
.foregroundColor(Color(.secondaryLabel))
.bodyStyle()
.padding(.horizontal, Layout.defaultHorizontalPadding)
ScrollView {
VStack(alignment: .leading, spacing: 0) {
// Header label.
Text(Localization.subtitle)
.foregroundColor(Color(.secondaryLabel))
.bodyStyle()
.padding(.horizontal, Layout.defaultHorizontalPadding)
.padding(.top, 16)

// Search text field.
SearchHeader(text: $viewModel.searchTerm,
placeholder: Localization.searchPlaceholder,
customizations: .init(backgroundColor: .clear,
borderColor: .separator,
internalHorizontalPadding: 21,
internalVerticalPadding: 12))
Spacer()
.frame(height: 30)

// Results header.
Text(Localization.suggestionsHeader)
// Search text field.
SearchHeader(text: $viewModel.searchTerm,
placeholder: Localization.searchPlaceholder,
customizations: .init(backgroundColor: .clear,
borderColor: .separator,
internalHorizontalPadding: 21,
internalVerticalPadding: 12,
iconSize: .init(width: 14, height: 14)))
.focused($textFieldIsFocused)

if viewModel.searchTerm.isEmpty {
// Placeholder image when search query is empty.
Spacer()
.frame(height: 30)

HStack {
Spacer()
Image(uiImage: .domainSearchPlaceholderImage)
Spacer()
}
} else if viewModel.isLoadingDomainSuggestions {
// Progress indicator when loading domain suggestions.
Spacer()
.frame(height: 23)

HStack {
Spacer()
ProgressView()
Spacer()
}
} else if let errorMessage = viewModel.errorMessage {
// Error message when there is an error loading domain suggestions.
Spacer()
.frame(height: 23)

Text(errorMessage)
.foregroundColor(Color(.secondaryLabel))
.bodyStyle()
.frame(maxWidth: .infinity, alignment: .center)
.multilineTextAlignment(.center)
.padding(Layout.defaultPadding)
} else {
// Domain suggestions.
Text(Localization.suggestionsHeader)
.foregroundColor(Color(.secondaryLabel))
.footnoteStyle()
.padding(.horizontal, Layout.defaultHorizontalPadding)
.padding(.vertical, insets: .init(top: 14, leading: 0, bottom: 8, trailing: 0))

if viewModel.searchTerm.isEmpty {
// Placeholder image when search query is empty.
HStack {
Spacer()
Image(uiImage: .domainSearchPlaceholderImage)
Spacer()
}
} else if viewModel.isLoadingDomainSuggestions {
// Progress indicator when loading domain suggestions.
HStack {
Spacer()
ProgressView()
Spacer()
}
} else if let errorMessage = viewModel.errorMessage {
// Error message when there is an error loading domain suggestions.
Text(errorMessage)
.padding(Layout.defaultPadding)
} else {
// Domain suggestions.
LazyVStack {
ForEach(viewModel.domains, id: \.self) { domain in
Button {
selectedDomainName = domain
} label: {
VStack(alignment: .leading) {
DomainRowView(viewModel: .init(domainName: domain,
searchQuery: viewModel.searchTerm,
isSelected: domain == selectedDomainName))
Divider()
.frame(height: Layout.dividerHeight)
.padding(.leading, Layout.defaultHorizontalPadding)
}
LazyVStack {
ForEach(viewModel.domains, id: \.self) { domain in
Button {
textFieldIsFocused = false
selectedDomainName = domain
} label: {
VStack(alignment: .leading) {
DomainRowView(viewModel: .init(domainName: domain,
searchQuery: viewModel.searchTerm,
isSelected: domain == selectedDomainName))
Divider()
.frame(height: Layout.dividerHeight)
.padding(.leading, Layout.defaultHorizontalPadding)
}
}
}
}
}
}

}
.safeAreaInset(edge: .bottom) {
// Continue button when a domain is selected.
if let selectedDomainName {
Divider()
.frame(height: Layout.dividerHeight)
.foregroundColor(Color(.separator))
Button(Localization.continueButtonTitle) {
Task { @MainActor in
isWaitingForDomainSelectionCompletion = true
await onDomainSelection(selectedDomainName)
isWaitingForDomainSelectionCompletion = false
VStack {
Divider()
.frame(height: Layout.dividerHeight)
.foregroundColor(Color(.separator))
Button(Localization.continueButtonTitle) {
Task { @MainActor in
isWaitingForDomainSelectionCompletion = true
await onDomainSelection(selectedDomainName)
isWaitingForDomainSelectionCompletion = false
}
}
.buttonStyle(PrimaryLoadingButtonStyle(isLoading: isWaitingForDomainSelectionCompletion))
.padding(Layout.defaultPadding)
}
.buttonStyle(PrimaryLoadingButtonStyle(isLoading: isWaitingForDomainSelectionCompletion))
.padding(Layout.defaultPadding)
.background(Color(.systemBackground))
}
}
.navigationTitle(Localization.title)
Expand All @@ -176,7 +179,6 @@ struct DomainSelectorView: View {

private extension DomainSelectorView {
enum Layout {
static let spacingBetweenTitleAndSubtitle: CGFloat = 16
static let defaultHorizontalPadding: CGFloat = 16
static let dividerHeight: CGFloat = 1
static let defaultPadding: EdgeInsets = .init(top: 10, leading: 16, bottom: 10, trailing: 16)
Expand All @@ -185,7 +187,7 @@ private extension DomainSelectorView {
enum Localization {
static let title = NSLocalizedString("Choose a domain", comment: "Title of the domain selector.")
static let subtitle = NSLocalizedString(
"This is where people will find you on the Internet. Don't worry, you can change it later.",
"This is where people will find you on the Internet. You can add another domain later.",
comment: "Subtitle of the domain selector.")
static let searchPlaceholder = NSLocalizedString("Type to get suggestions", comment: "Placeholder of the search text field on the domain selector.")
static let suggestionsHeader = NSLocalizedString("SUGGESTIONS", comment: "Header label of the domain suggestions on the domain selector.")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ struct SearchHeader: View {
let borderColor: UIColor
let internalHorizontalPadding: CGFloat
let internalVerticalPadding: CGFloat
let iconSize: CGSize
}

// Tracks the scale of the view due to accessibility changes
Expand All @@ -34,7 +35,8 @@ struct SearchHeader: View {
backgroundColor: .searchBarBackground,
borderColor: .clear,
internalHorizontalPadding: Layout.internalPadding,
internalVerticalPadding: Layout.internalPadding
internalVerticalPadding: Layout.internalPadding,
iconSize: Layout.iconSize
)) {
self._text = text
self.placeholder = placeholder
Expand All @@ -47,14 +49,16 @@ struct SearchHeader: View {
Image(uiImage: .searchBarButtonItemImage)
.renderingMode(.template)
.resizable()
.frame(width: Layout.iconSize.width * scale, height: Layout.iconSize.height * scale)
.frame(width: customizations.iconSize.width * scale,
height: customizations.iconSize.height * scale)
.foregroundColor(Color(.listSmallIcon))
.padding([.leading, .trailing], customizations.internalHorizontalPadding)
.accessibilityHidden(true)

// TextField
TextField(placeholder, text: $text)
.padding([.bottom, .top], customizations.internalVerticalPadding)
.padding(.trailing, customizations.internalHorizontalPadding)
.accessibility(addTraits: .isSearchField)
}
.background(Color(customizations.backgroundColor))
Expand Down Expand Up @@ -89,7 +93,7 @@ struct SearchHeaderView_Previews: PreviewProvider {
customizations: .init(backgroundColor: .clear,
borderColor: .separator,
internalHorizontalPadding: 21,
internalVerticalPadding: 12))
internalVerticalPadding: 12, iconSize: .init(width: 14, height: 14)))
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,16 @@
{
"filename" : "domain-search-placeholder.pdf",
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"filename" : "domain-search-placeholder-dark.pdf",
"idiom" : "universal"
}
],
"info" : {
Expand Down
Binary file not shown.