Skip to content

Commit

Permalink
add - brk|doc - Added property grouping for vCard
Browse files Browse the repository at this point in the history
---

We've made a breaking addition that adds property grouping for vCard contacts, while breaking the existing API to add a new property to the base card part info so that you can easily determine which part is from which group.

---

Type: add
Breaking: True
Doc Required: True
Backport Required: False
Part: 1/1
  • Loading branch information
AptiviCEO committed Sep 30, 2024
1 parent 6b25ca1 commit df1ab05
Show file tree
Hide file tree
Showing 44 changed files with 308 additions and 269 deletions.
8 changes: 4 additions & 4 deletions VisualCard.Extras/Misc/CardGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -113,12 +113,12 @@ public static Card[] GenerateCards(int cards, string namePrefix = "", string nam

// Now, convert generated parts to actual VisualCard parts
var card = new Card(new(2, 1));
card.AddPartToArray(PartsArrayEnum.Names, new NameInfo(0, [], [], "", firstName, lastName, [], [], []));
card.AddPartToArray(PartsArrayEnum.FullName, new FullNameInfo(0, [], [], "", $"{firstName} {lastName}"));
card.AddPartToArray(PartsArrayEnum.Names, new NameInfo(0, [], [], "", "", firstName, lastName, [], [], []));
card.AddPartToArray(PartsArrayEnum.FullName, new FullNameInfo(0, [], [], "", "", $"{firstName} {lastName}"));
foreach (var telephone in telephones)
card.AddPartToArray(PartsArrayEnum.Telephones, new TelephoneInfo(0, [], [telephone.Key], "", telephone.Value));
card.AddPartToArray(PartsArrayEnum.Telephones, new TelephoneInfo(0, [], [telephone.Key], "", "", telephone.Value));
foreach (var email in emails)
card.AddPartToArray(PartsArrayEnum.Mails, new EmailInfo(0, [], [email.Key], "", email.Value));
card.AddPartToArray(PartsArrayEnum.Mails, new EmailInfo(0, [], [email.Key], "", "", email.Value));
string cardString = card.ToString();

// Verify the generated card and add it to the list of cards
Expand Down
60 changes: 30 additions & 30 deletions VisualCard.ShowContacts/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,71 +93,71 @@ static void Main(string[] args)
// List names
foreach (var fullName in Contact.GetPartsArray<FullNameInfo>())
{
TextWriterColor.Write("Name: {0}", fullName.FullName ?? "");
TextWriterColor.Write("ALTID: {0}", fullName.AltId);
TextWriterColor.Write("Name: {0} [G: {1}]", fullName.FullName ?? "", fullName.Group);
TextWriterColor.Write("ALTID: {0} [G: {1}]", fullName.AltId, fullName.Group);
}

// List names
foreach (var name in Contact.GetPartsArray<NameInfo>())
{
TextWriterColor.Write("First name: {0}", name.ContactFirstName ?? "");
TextWriterColor.Write("Last name: {0}", name.ContactLastName ?? "");
TextWriterColor.Write("ALTID: {0}", name.AltId);
TextWriterColor.Write("First name: {0} [G: {1}]", name.ContactFirstName ?? "", name.Group);
TextWriterColor.Write("Last name: {0} [G: {1}]", name.ContactLastName ?? "", name.Group);
TextWriterColor.Write("ALTID: {0} [G: {1}]", name.AltId, name.Group);
}

// List titles
foreach (var title in Contact.GetPartsArray<TitleInfo>())
{
TextWriterColor.Write("Title or Job: {0}", title.ContactTitle ?? "");
TextWriterColor.Write("ALTID: {0}", title.AltId);
TextWriterColor.Write("Title or Job: {0} [G: {1}]", title.ContactTitle ?? "", title.Group);
TextWriterColor.Write("ALTID: {0} [G: {1}]", title.AltId, title.Group);
}

// List addresses
foreach (var Address in Contact.GetPartsArray<AddressInfo>())
{
TextWriterColor.Write("P.O. Box: {0}", Address.PostOfficeBox ?? "");
TextWriterColor.Write("Extended Address: {0}", Address.ExtendedAddress ?? "");
TextWriterColor.Write("Street Address: {0}", Address.StreetAddress ?? "");
TextWriterColor.Write("Region: {0}", Address.Region ?? "");
TextWriterColor.Write("Locality: {0}", Address.Locality ?? "");
TextWriterColor.Write("Postal Code: {0}", Address.PostalCode ?? "");
TextWriterColor.Write("Country: {0}", Address.Country ?? "");
TextWriterColor.Write("P.O. Box: {0} [G: {1}]", Address.PostOfficeBox ?? "", Address.Group);
TextWriterColor.Write("Extended Address: {0} [G: {1}]", Address.ExtendedAddress ?? "", Address.Group);
TextWriterColor.Write("Street Address: {0} [G: {1}]", Address.StreetAddress ?? "", Address.Group);
TextWriterColor.Write("Region: {0} [G: {1}]", Address.Region ?? "", Address.Group);
TextWriterColor.Write("Locality: {0} [G: {1}]", Address.Locality ?? "", Address.Group);
TextWriterColor.Write("Postal Code: {0} [G: {1}]", Address.PostalCode ?? "", Address.Group);
TextWriterColor.Write("Country: {0} [G: {1}]", Address.Country ?? "", Address.Group);
}

// List e-mails
foreach (var Email in Contact.GetPartsArray<EmailInfo>())
{
TextWriterColor.Write("Email address: {0}", Email.ContactEmailAddress ?? "");
TextWriterColor.Write("Email address: {0} [G: {1}]", Email.ContactEmailAddress ?? "", Email.Group);
}

// List organizations
foreach (var Organization in Contact.GetPartsArray<OrganizationInfo>())
{
TextWriterColor.Write("Organization Name: {0}", Organization.Name ?? "");
TextWriterColor.Write("Organization Unit: {0}", Organization.Unit ?? "");
TextWriterColor.Write("Organization Unit Role: {0}", Organization.Role ?? "");
TextWriterColor.Write("Organization Name: {0} [G: {1}]", Organization.Name ?? "", Organization.Group);
TextWriterColor.Write("Organization Unit: {0} [G: {1}]", Organization.Unit ?? "", Organization.Group);
TextWriterColor.Write("Organization Unit Role: {0} [G: {1}]", Organization.Role ?? "", Organization.Group);
}

// List telephones
foreach (var Telephone in Contact.GetPartsArray<TelephoneInfo>())
{
TextWriterColor.Write("Phone number: {0}", Telephone.ContactPhoneNumber ?? "");
TextWriterColor.Write("Phone number: {0} [G: {1}]", Telephone.ContactPhoneNumber ?? "", Telephone.Group);
}

// List photos
foreach (var Photo in Contact.GetPartsArray<PhotoInfo>())
{
TextWriterColor.Write("Photo encoding: {0}", Photo.Encoding ?? "");
TextWriterColor.Write("Photo value type: {0}", string.Join(",", Photo.ElementTypes));
TextWriterColor.Write("ALTID: {0}", Photo.AltId);
TextWriterColor.Write("Photo data [blob: {0}]: \n{1}", true, Photo.IsBlob, Photo.PhotoEncoded ?? "");
TextWriterColor.Write("Photo encoding: {0} [G: {1}]", Photo.Encoding ?? "", Photo.Group);
TextWriterColor.Write("Photo value type: {0} [G: {1}]", string.Join(",", Photo.ElementTypes), Photo.Group);
TextWriterColor.Write("ALTID: {0} [G: {1}]", Photo.AltId, Photo.Group);
TextWriterColor.Write("Photo data [blob: {0}, group: {1}]: \n{2}", true, Photo.IsBlob, Photo.Group, Photo.PhotoEncoded ?? "");
}

// List roles
foreach (var Role in Contact.GetPartsArray<RoleInfo>())
{
TextWriterColor.Write("Role: {0}", Role.ContactRole ?? "");
TextWriterColor.Write("ALTID: {0}", Role.AltId);
TextWriterColor.Write("Role: {0} [G: {1}]", Role.ContactRole ?? "", Role.Group);
TextWriterColor.Write("ALTID: {0} [G: {1}]", Role.AltId, Role.Group);
}

// List remaining
Expand All @@ -167,15 +167,15 @@ static void Main(string[] args)
var url = Contact.GetPartsArray<UrlInfo>();
var note = Contact.GetPartsArray<NoteInfo>();
if (birth.Length > 0)
TextWriterColor.Write("Contact birthdate: {0}", birth[0].BirthDate);
TextWriterColor.Write("Contact birthdate: {0} [G: {1}]", birth[0].BirthDate, birth[0].Group);
if (wedding.Length > 0)
TextWriterColor.Write("Contact wedding date: {0}", wedding[0].Anniversary);
TextWriterColor.Write("Contact wedding date: {0} [G: {1}]", wedding[0].Anniversary, wedding[0].Group);
if (gender.Length > 0)
TextWriterColor.Write("Contact gender {0} [{1}]", gender[0].Gender.ToString(), gender[0].GenderDescription ?? "");
TextWriterColor.Write("Contact gender {0} [{1}] [G: {2}]", gender[0].Gender.ToString(), gender[0].GenderDescription ?? "", gender[0].Group);
if (url.Length > 0)
TextWriterColor.Write("Contact URL: {0}", url[0].Url ?? "");
TextWriterColor.Write("Contact URL: {0} [G: {1}]", url[0].Url ?? "", url[0].Group);
if (note.Length > 0)
TextWriterColor.Write("Contact Note: {0}", note[0].Note ?? "");
TextWriterColor.Write("Contact Note: {0} [G: {1}]", note[0].Note ?? "", note[0].Group);
TextWriterColor.Write("Card kind: {0}", Contact.CardKind);

// Print VCard
Expand Down
6 changes: 5 additions & 1 deletion VisualCard.ShowContacts/Properties/launchSettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
"commandName": "Project",
"commandLineArgs": "TestFiles/fourVCard4.vcf"
},
"vCard 4.0 test (Property grouping)": {
"commandName": "Project",
"commandLineArgs": "TestFiles/VCard4GroupProps.vcf"
},
"vCard 5.0 test": {
"commandName": "Project",
"commandLineArgs": "TestFiles/fourVCard5.vcf"
Expand All @@ -37,4 +41,4 @@
"commandLineArgs": "TestFiles/fourVCard5NestedAgents.vcf"
}
}
}
}
18 changes: 18 additions & 0 deletions VisualCard.ShowContacts/TestFiles/VCard4GroupProps.vcf
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
BEGIN:VCARD
VERSION:4.0
UID:urn:uuid:136c1090-d7d3-4399-9f59-8f7a7b6e2ef1
ADR;TYPE=home:;;New York\, USA;;;;
A.EMAIL;TYPE=HOME:sarah.s@gmail.com
B.EMAIL;TYPE=WORK:sarah.s@sso.org
FN:Sarah Santos
N:Santos;Sarah;;;
ORG:Support Scammer Outcry Organization
A.TEL;TYPE=cell:589-210-1059
B.TEL;TYPE=cell:589-210-1058
TITLE:Chief Executive Officer
URL:https://sso.org/
X-SIP-SIP:sip test
ANNIVERSARY:20230406
GENDER:F;grrrl
DRESSCODE:CASUAL
END:VCARD
10 changes: 7 additions & 3 deletions VisualCard/Parsers/VcardParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ public Card Parse()
List<string> finalArgs = [];
int altId = -1;

// Extract the group name
string group = prefix.Contains(".") ? prefix.Substring(0, prefix.IndexOf(".")) : "";
prefix = prefix.RemovePrefix($"{group}.");

// Get the part type
bool xNonstandard = prefix.StartsWith(VcardConstants._xSpecifier);
bool specifierRequired = CardVersion.Major >= 3;
Expand Down Expand Up @@ -191,7 +195,7 @@ public Card Parse()
}

// Set the string for real
card.SetString(stringType, finalValue);
card.SetString(stringType, finalValue, group);
}
break;
case PartType.PartsArray:
Expand All @@ -206,7 +210,7 @@ public Card Parse()

// Now, get the part info
string finalValue = partsArrayType is PartsArrayEnum.NonstandardNames or PartsArrayEnum.IanaNames ? _value : value;
var partInfo = fromString(finalValue, [.. finalArgs], altId, elementTypes, values, CardVersion);
var partInfo = fromString(finalValue, [.. finalArgs], altId, elementTypes, group, values, CardVersion);

// Set the array for real
card.AddPartToArray(partsArrayType, partInfo);
Expand Down Expand Up @@ -261,7 +265,7 @@ private bool ValidateComponent<TComponent>(ref string[] expectedFields, out stri
{
case PartType.Strings:
{
string value = component.GetString((StringsEnum)enumeration);
string value = component.GetString((StringsEnum)enumeration).value;
bool exists = !string.IsNullOrEmpty(value);
if (exists)
actualFieldList.Add(expectedFieldName);
Expand Down
2 changes: 1 addition & 1 deletion VisualCard/Parsers/VcardParserTools.cs
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ internal static (PartsArrayEnum, PartCardinality) GetPartsArrayEnumFromType(Type
return (PartsArrayEnum.IanaNames, PartCardinality.Any);
}

internal static (PartType type, object enumeration, Type? enumType, Func<string, string[], int, string[], string, Version, BaseCardPartInfo>? fromStringFunc, string defaultType, string defaultValue, string[] allowedExtraTypes) GetPartType(string prefix) =>
internal static (PartType type, object enumeration, Type? enumType, Func<string, string[], int, string[], string, string, Version, BaseCardPartInfo>? fromStringFunc, string defaultType, string defaultValue, string[] allowedExtraTypes) GetPartType(string prefix) =>
prefix switch
{
VcardConstants._nameSpecifier => (PartType.PartsArray, PartsArrayEnum.Names, typeof(NameInfo), NameInfo.FromStringVcardStatic, "", "", []),
Expand Down
14 changes: 11 additions & 3 deletions VisualCard/Parts/BaseCardPartInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ public abstract class BaseCardPartInfo : IEquatable<BaseCardPartInfo>
/// </summary>
public virtual string ValueType { get; internal set; } = "";

/// <summary>
/// Property group
/// </summary>
public virtual string Group { get; internal set; } = "";

/// <summary>
/// Is this part preferred?
/// </summary>
Expand Down Expand Up @@ -125,6 +130,7 @@ public bool Equals(BaseCardPartInfo source, BaseCardPartInfo target)
source.ElementTypes.SequenceEqual(target.ElementTypes) &&
source.AltId == target.AltId &&
source.ValueType == target.ValueType &&
source.Group == target.Group &&
EqualsInternal(source, target)
;
}
Expand All @@ -136,11 +142,12 @@ public override bool Equals(object obj) =>
/// <inheritdoc/>
public override int GetHashCode()
{
int hashCode = 936749766;
int hashCode = 975087586;
hashCode = hashCode * -1521134295 + EqualityComparer<string[]>.Default.GetHashCode(Arguments);
hashCode = hashCode * -1521134295 + AltId.GetHashCode();
hashCode = hashCode * -1521134295 + EqualityComparer<string[]>.Default.GetHashCode(ElementTypes);
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(ValueType);
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(Group);
return hashCode;
}

Expand All @@ -155,19 +162,20 @@ public override int GetHashCode()
internal virtual bool EqualsInternal(BaseCardPartInfo source, BaseCardPartInfo target) =>
true;

internal abstract BaseCardPartInfo FromStringVcardInternal(string value, string[] finalArgs, int altId, string[] elementTypes, string valueType, Version cardVersion);
internal abstract BaseCardPartInfo FromStringVcardInternal(string value, string[] finalArgs, int altId, string[] elementTypes, string group, string valueType, Version cardVersion);

internal abstract string ToStringVcardInternal(Version cardVersion);

internal BaseCardPartInfo()
{ }

internal BaseCardPartInfo(string[] arguments, int altId, string[] elementTypes, string valueType)
internal BaseCardPartInfo(string[] arguments, int altId, string[] elementTypes, string valueType, string group)
{
Arguments = arguments;
AltId = altId;
ElementTypes = elementTypes;
ValueType = valueType;
Group = group;
}
}
}
Loading

0 comments on commit df1ab05

Please sign in to comment.