Signed-off-by: Matt Bruce <mbrucedogs@gmail.com>
This commit is contained in:
parent
1080590fde
commit
4145f73bc9
@ -81,6 +81,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Add Contact Fields" : {
|
||||
|
||||
},
|
||||
"Add note" : {
|
||||
|
||||
@ -176,9 +179,6 @@
|
||||
},
|
||||
"Contact" : {
|
||||
|
||||
},
|
||||
"Contact Fields" : {
|
||||
|
||||
},
|
||||
"Country" : {
|
||||
|
||||
@ -249,6 +249,9 @@
|
||||
},
|
||||
"Developer" : {
|
||||
|
||||
},
|
||||
"Drag to reorder. Swipe to delete." : {
|
||||
|
||||
},
|
||||
"e.g. MBA, CPA, PhD" : {
|
||||
|
||||
@ -733,6 +736,9 @@
|
||||
},
|
||||
"Write down a memorable reminder about your contact" : {
|
||||
|
||||
},
|
||||
"Your Contact Fields" : {
|
||||
|
||||
},
|
||||
"ZIP Code" : {
|
||||
|
||||
|
||||
@ -50,6 +50,10 @@ struct CardEditorView: View {
|
||||
// Photo editor state - just one variable!
|
||||
@State private var editingImageType: ImageType?
|
||||
|
||||
// Contact field editor state
|
||||
@State private var selectedFieldTypeForAdd: ContactFieldType?
|
||||
@State private var fieldToEdit: AddedContactField?
|
||||
|
||||
@State private var showingPreview = false
|
||||
|
||||
enum ImageType: String, Identifiable {
|
||||
@ -196,11 +200,34 @@ struct CardEditorView: View {
|
||||
Text("Card Label")
|
||||
}
|
||||
|
||||
// Contact & social fields manager
|
||||
// Current contact fields (reorderable list)
|
||||
if !contactFields.isEmpty {
|
||||
Section {
|
||||
ForEach(contactFields) { field in
|
||||
ContactFieldRowView(field: field) {
|
||||
fieldToEdit = field
|
||||
}
|
||||
}
|
||||
.onMove { from, to in
|
||||
contactFields.move(fromOffsets: from, toOffset: to)
|
||||
}
|
||||
.onDelete { indexSet in
|
||||
contactFields.remove(atOffsets: indexSet)
|
||||
}
|
||||
} header: {
|
||||
Text("Your Contact Fields")
|
||||
} footer: {
|
||||
Text("Drag to reorder. Swipe to delete.")
|
||||
}
|
||||
}
|
||||
|
||||
// Add new contact fields
|
||||
Section {
|
||||
ContactFieldsManagerView(fields: $contactFields)
|
||||
ContactFieldPickerView { fieldType in
|
||||
selectedFieldTypeForAdd = fieldType
|
||||
}
|
||||
} header: {
|
||||
Text("Contact Fields")
|
||||
Text("Add Contact Fields")
|
||||
}
|
||||
|
||||
// Bio section
|
||||
@ -244,6 +271,29 @@ struct CardEditorView: View {
|
||||
editingImageType = nil
|
||||
}
|
||||
}
|
||||
.sheet(item: $selectedFieldTypeForAdd) { fieldType in
|
||||
ContactFieldEditorSheet(
|
||||
fieldType: fieldType,
|
||||
initialValue: "",
|
||||
initialTitle: fieldType.titleSuggestions.first ?? "",
|
||||
onSave: { value, title in
|
||||
addContactField(fieldType: fieldType, value: value, title: title)
|
||||
}
|
||||
)
|
||||
}
|
||||
.sheet(item: $fieldToEdit) { field in
|
||||
ContactFieldEditorSheet(
|
||||
fieldType: field.fieldType,
|
||||
initialValue: field.value,
|
||||
initialTitle: field.title,
|
||||
onSave: { value, title in
|
||||
updateContactField(id: field.id, value: value, title: title)
|
||||
},
|
||||
onDelete: {
|
||||
deleteContactField(id: field.id)
|
||||
}
|
||||
)
|
||||
}
|
||||
.onAppear { loadCardData() }
|
||||
.sheet(isPresented: $showingPreview) {
|
||||
CardPreviewSheet(card: buildPreviewCard())
|
||||
@ -524,6 +574,54 @@ private struct ProfilePhotoView: View {
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Contact Field Row View
|
||||
|
||||
private struct ContactFieldRowView: View {
|
||||
let field: AddedContactField
|
||||
let onTap: () -> Void
|
||||
|
||||
var body: some View {
|
||||
Button(action: onTap) {
|
||||
HStack(spacing: Design.Spacing.medium) {
|
||||
// Drag handle
|
||||
Image(systemName: "line.3.horizontal")
|
||||
.font(.subheadline)
|
||||
.foregroundStyle(Color.Text.tertiary)
|
||||
.accessibilityHidden(true)
|
||||
|
||||
// Icon
|
||||
Circle()
|
||||
.fill(field.fieldType.iconColor)
|
||||
.frame(width: Design.CardSize.avatarSize, height: Design.CardSize.avatarSize)
|
||||
.overlay(
|
||||
field.fieldType.iconImage()
|
||||
.font(.title3)
|
||||
.foregroundStyle(.white)
|
||||
)
|
||||
|
||||
// Content
|
||||
VStack(alignment: .leading, spacing: Design.Spacing.xxSmall) {
|
||||
Text(field.value.isEmpty ? field.fieldType.valuePlaceholder : field.shortDisplayValue)
|
||||
.font(.subheadline)
|
||||
.foregroundStyle(field.value.isEmpty ? Color.Text.secondary : Color.Text.primary)
|
||||
.lineLimit(1)
|
||||
|
||||
Text(field.title.isEmpty ? field.fieldType.displayName : field.title)
|
||||
.font(.caption)
|
||||
.foregroundStyle(Color.Text.secondary)
|
||||
.lineLimit(1)
|
||||
}
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.contentShape(.rect)
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.accessibilityLabel("\(field.fieldType.displayName): \(field.shortDisplayValue)")
|
||||
.accessibilityHint(String.localized("Tap to edit, drag to reorder"))
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Accreditations Row
|
||||
|
||||
private struct AccreditationsRow: View {
|
||||
@ -828,6 +926,35 @@ private extension CardEditorView {
|
||||
return previewCard
|
||||
}
|
||||
|
||||
// MARK: - Contact Field Operations
|
||||
|
||||
func addContactField(fieldType: ContactFieldType, value: String, title: String) {
|
||||
guard !value.isEmpty else { return }
|
||||
withAnimation {
|
||||
let newField = AddedContactField(
|
||||
fieldType: fieldType,
|
||||
value: value,
|
||||
title: title
|
||||
)
|
||||
contactFields.append(newField)
|
||||
}
|
||||
}
|
||||
|
||||
func updateContactField(id: UUID, value: String, title: String) {
|
||||
if let index = contactFields.firstIndex(where: { $0.id == id }) {
|
||||
withAnimation {
|
||||
contactFields[index].value = value
|
||||
contactFields[index].title = title
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func deleteContactField(id: UUID) {
|
||||
withAnimation {
|
||||
contactFields.removeAll { $0.id == id }
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Contact Fields Sync
|
||||
|
||||
/// Saves the contactFields array to the BusinessCard model
|
||||
|
||||
Loading…
Reference in New Issue
Block a user