From c70106217471f637932cd1436b5523613b0233d2 Mon Sep 17 00:00:00 2001 From: Aptivi Date: Sat, 30 Mar 2024 17:32:42 +0300 Subject: [PATCH] add - doc - Added language information --- We've added language information --- Type: add Breaking: False Doc Required: True Part: 1/1 --- .../TestFiles/fourVCard4.vcf | 2 + VisualCard/Parsers/VcardConstants.cs | 2 + VisualCard/Parsers/VcardParserTools.cs | 3 + VisualCard/Parts/Enums/PartsArrayEnum.cs | 4 + VisualCard/Parts/Implementations/LangInfo.cs | 174 ++++++++++++++++++ 5 files changed, 185 insertions(+) create mode 100644 VisualCard/Parts/Implementations/LangInfo.cs diff --git a/VisualCard.ShowContacts/TestFiles/fourVCard4.vcf b/VisualCard.ShowContacts/TestFiles/fourVCard4.vcf index d81191d..e936f05 100644 --- a/VisualCard.ShowContacts/TestFiles/fourVCard4.vcf +++ b/VisualCard.ShowContacts/TestFiles/fourVCard4.vcf @@ -29,6 +29,8 @@ TEL;TYPE=voice:078-494-6434 TEL;TYPE=home:348-404-8404 TITLE:Title GENDER:M +LANG;TYPE=home:en +LANG;TYPE=work:de X-ANDROID-CUSTOM:vnd.android.cursor.item/nickname;NVL.N;1 ;;;;;;;;;;;;; END:VCARD diff --git a/VisualCard/Parsers/VcardConstants.cs b/VisualCard/Parsers/VcardConstants.cs index 601433b..70abed6 100644 --- a/VisualCard/Parsers/VcardConstants.cs +++ b/VisualCard/Parsers/VcardConstants.cs @@ -80,6 +80,8 @@ internal static class VcardConstants internal const string _kindSpecifier = "KIND"; internal const string _anniversarySpecifier = "ANNIVERSARY"; internal const string _genderSpecifier = "GENDER"; + internal const string _langSpecifier = "LANG"; internal const string _altIdArgumentSpecifier = "ALTID="; + internal const string _prefArgumentSpecifier = "PREF="; } } diff --git a/VisualCard/Parsers/VcardParserTools.cs b/VisualCard/Parsers/VcardParserTools.cs index f464112..a1c8dcb 100644 --- a/VisualCard/Parsers/VcardParserTools.cs +++ b/VisualCard/Parsers/VcardParserTools.cs @@ -128,6 +128,7 @@ partsArrayEnum switch PartsArrayEnum.Nicknames => cardVersion.Major >= 3, PartsArrayEnum.Labels => cardVersion.Major != 4, PartsArrayEnum.Agents => cardVersion.Major != 4, + PartsArrayEnum.Langs => cardVersion.Major >= 4, _ => throw new InvalidOperationException("Invalid parts array enumeration type to get supported value"), }; @@ -194,6 +195,7 @@ partsArrayEnum switch PartsArrayEnum.Sounds => VcardConstants._soundSpecifier, PartsArrayEnum.Impps => VcardConstants._imppSpecifier, PartsArrayEnum.Categories => VcardConstants._categoriesSpecifier, + PartsArrayEnum.Langs => VcardConstants._langSpecifier, PartsArrayEnum.NonstandardNames => VcardConstants._xSpecifier, _ => throw new NotImplementedException($"String enumeration {partsArrayEnum} is not implemented.") @@ -219,6 +221,7 @@ prefix switch VcardConstants._soundSpecifier => (PartType.PartsArray, PartsArrayEnum.Sounds, typeof(SoundInfo), SoundInfo.FromStringVcardStatic, SoundInfo.FromStringVcardWithTypeStatic), VcardConstants._imppSpecifier => (PartType.PartsArray, PartsArrayEnum.Impps, typeof(ImppInfo), ImppInfo.FromStringVcardStatic, ImppInfo.FromStringVcardWithTypeStatic), VcardConstants._categoriesSpecifier => (PartType.PartsArray, PartsArrayEnum.Categories, typeof(CategoryInfo), CategoryInfo.FromStringVcardStatic, CategoryInfo.FromStringVcardWithTypeStatic), + VcardConstants._langSpecifier => (PartType.PartsArray, PartsArrayEnum.Langs, typeof(LangInfo), LangInfo.FromStringVcardStatic, LangInfo.FromStringVcardWithTypeStatic), VcardConstants._xSpecifier => (PartType.PartsArray, PartsArrayEnum.NonstandardNames, typeof(XNameInfo), XNameInfo.FromStringVcardStatic, XNameInfo.FromStringVcardWithTypeStatic), VcardConstants._revSpecifier => (PartType.Parts, PartsEnum.Revision, typeof(RevisionInfo), RevisionInfo.FromStringVcardStatic, RevisionInfo.FromStringVcardWithTypeStatic), VcardConstants._birthSpecifier => (PartType.Parts, PartsEnum.Birthdate, typeof(BirthDateInfo), BirthDateInfo.FromStringVcardStatic, BirthDateInfo.FromStringVcardWithTypeStatic), diff --git a/VisualCard/Parts/Enums/PartsArrayEnum.cs b/VisualCard/Parts/Enums/PartsArrayEnum.cs index b898f71..d4de1de 100644 --- a/VisualCard/Parts/Enums/PartsArrayEnum.cs +++ b/VisualCard/Parts/Enums/PartsArrayEnum.cs @@ -93,6 +93,10 @@ public enum PartsArrayEnum /// Impps, /// + /// The contact's language list + /// + Langs, + /// /// The contact's extended options (usually starts with X-SOMETHING:Value1;Value2...) /// NonstandardNames, diff --git a/VisualCard/Parts/Implementations/LangInfo.cs b/VisualCard/Parts/Implementations/LangInfo.cs new file mode 100644 index 0000000..cc0cf29 --- /dev/null +++ b/VisualCard/Parts/Implementations/LangInfo.cs @@ -0,0 +1,174 @@ +// +// VisualCard Copyright (C) 2021-2024 Aptivi +// +// This file is part of VisualCard +// +// VisualCard is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// VisualCard is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY, without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using VisualCard.Parsers; + +namespace VisualCard.Parts.Implementations +{ + /// + /// Contact language information + /// + [DebuggerDisplay("Language = {ContactLang}")] + public class LangInfo : BaseCardPartInfo, IEquatable + { + /// + /// The contact's language types + /// + public string[] ContactLangTypes { get; } + /// + /// The contact's preference order + /// + public int ContactLangPreference { get; } + /// + /// The contact's language code + /// + public string ContactLang { get; } + + internal static BaseCardPartInfo FromStringVcardStatic(string value, int altId, Version cardVersion) => + new LangInfo().FromStringVcardInternal(value, altId, cardVersion); + + internal static BaseCardPartInfo FromStringVcardWithTypeStatic(string value, string[] finalArgs, int altId, Version cardVersion) => + new LangInfo().FromStringVcardWithTypeInternal(value, finalArgs, altId, cardVersion); + + internal override string ToStringVcardInternal(Version cardVersion) + { + bool altIdSupported = cardVersion.Major >= 4; + if (altIdSupported) + { + bool installAltId = AltId >= 0 && AltArguments.Length > 0; + return + $"{VcardConstants._langSpecifier};" + + $"{(installAltId ? VcardConstants._altIdArgumentSpecifier + AltId + VcardConstants._fieldDelimiter : "")}" + + $"{VcardConstants._typeArgumentSpecifier}{string.Join(",", ContactLangTypes)}{VcardConstants._fieldDelimiter}" + + $"{VcardConstants._prefArgumentSpecifier}{ContactLangPreference}{VcardConstants._argumentDelimiter}" + + $"{ContactLang}"; + } + else + { + return + $"{VcardConstants._langSpecifier};" + + $"{VcardConstants._typeArgumentSpecifier}{string.Join(",", ContactLangTypes)}{VcardConstants._fieldDelimiter}" + + $"{VcardConstants._prefArgumentSpecifier}{ContactLangPreference}{VcardConstants._argumentDelimiter}" + + $"{ContactLang}"; + } + } + + internal override BaseCardPartInfo FromStringVcardInternal(string value, int altId, Version cardVersion) + { + // Get the value + string langValue = value.Substring(VcardConstants._langSpecifier.Length + 1); + string[] splitLang = langValue.Split(VcardConstants._argumentDelimiter); + + // Populate the fields + return InstallInfo(splitLang, altId); + } + + internal override BaseCardPartInfo FromStringVcardWithTypeInternal(string value, string[] finalArgs, int altId, Version cardVersion) + { + // Get the value + string langValue = value.Substring(VcardConstants._langSpecifier.Length + 1); + string[] splitLang = langValue.Split(VcardConstants._argumentDelimiter); + if (splitLang.Length < 2) + throw new InvalidDataException("Language field must specify exactly two values (Type (must be prepended with TYPE=), and a valid language code)"); + + // Populate the fields + return InstallInfo(splitLang, finalArgs, altId); + } + + private LangInfo InstallInfo(string[] splitLang, int altId) => + InstallInfo(splitLang, [], altId); + + private LangInfo InstallInfo(string[] splitLang, string[] finalArgs, int altId) + { + bool installType = splitLang.Length > 1; + + // Populate the fields + string[] _langTypes = installType ? VcardParserTools.GetTypes(splitLang, "HOME", true) : ["HOME"]; + string _langCode = installType ? splitLang[1] : splitLang[0]; + LangInfo _lang = new(altId, finalArgs, _langTypes, _langCode); + return _lang; + } + + /// + public override bool Equals(object obj) => + base.Equals(obj); + + /// + /// Checks to see if both the parts are equal + /// + /// The target instance to check to see if they equal + /// True if all the part elements are equal. Otherwise, false. + public bool Equals(LangInfo other) => + Equals(this, other); + + /// + /// Checks to see if both the parts are equal + /// + /// The source instance to check to see if they equal + /// The target instance to check to see if they equal + /// True if all the part elements are equal. Otherwise, false. + public bool Equals(LangInfo source, LangInfo target) + { + // We can't perform this operation on null. + if (source is null) + return false; + + // Check all the properties + return + source.ContactLangTypes.SequenceEqual(target.ContactLangTypes) && + source.AltId == target.AltId && + source.ContactLang == target.ContactLang + ; + } + + /// + public override int GetHashCode() + { + int hashCode = 2091849342; + hashCode = hashCode * -1521134295 + AltId.GetHashCode(); + hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(AltArguments); + hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(ContactLangTypes); + hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(ContactLang); + return hashCode; + } + + /// + public static bool operator ==(LangInfo left, LangInfo right) => + EqualityComparer.Default.Equals(left, right); + + /// + public static bool operator !=(LangInfo left, LangInfo right) => + !(left == right); + + internal LangInfo() { } + + internal LangInfo(int altId, string[] altArguments, string[] contactLangTypes, string contactLangCode) + { + AltId = altId; + AltArguments = altArguments; + ContactLangTypes = contactLangTypes; + ContactLang = contactLangCode; + } + } +}