bykovme/nswallet

View on GitHub
src/NSWallet/NSWallet/ViewModel/MainScreen/Fields/ManageFieldViewModel.cs

Summary

Maintainability
F
3 days
Test Coverage
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using NSWallet.Helpers;
using NSWallet.NetStandard.Helpers.FA;
using NSWallet.Shared;
using NSWallet.Shared.Helpers.Logs.AppLog;
using Xamarin.Essentials;
using Xamarin.Forms;

namespace NSWallet
{
    public class ManageFieldViewModel : ViewModel
    {
        // Callbacks
        public Action ClosePopupCommandCallback { get; set; }
        public Action ShowPopupCommandCallback { get; set; }

        // Forms
        INavigation navigation;

        // Variables
        readonly ManageFieldType manageFieldType;
        NSWItem nswItem;
        readonly string updFieldID;
        string fieldType;
        string valueType;

        /// <summary>
        /// Initializes a new instance of the <see cref="T:NSWallet.ManageFieldViewModel"/> class. Use to create the new field.
        /// </summary>
        /// <param name="navigation">Navigation.</param>
        public ManageFieldViewModel(INavigation navigation, NSWItem nswItem)
        {
            ViewMode = false;
            NotViewMode = true;

            IsEdit = false;

            manageFieldType = ManageFieldType.Create;
            Init(navigation, nswItem);
            ClosePopupCommandCallback = () => { };
            ShowPopupCommandCallback = () => { };
        }

        string humanReadableFieldValue = "";

        /// <summary>
        /// Initializes a new instance of the <see cref="T:NSWallet.ManageFieldViewModel"/> class. Use to update the existing field.
        /// </summary>
        /// <param name="navigation">Navigation.</param>
        /// <param name="nswItem">Item.</param>
        /// <param name="updFieldID">Update field identifier.</param>
        public ManageFieldViewModel(INavigation navigation, NSWItem nswItem, string updFieldID, bool viewMode, string fieldValue)
        {
            ViewMode = viewMode;
            NotViewMode = !viewMode;
            humanReadableFieldValue = fieldValue;
            manageFieldType = ManageFieldType.Edit;

            IsEdit = true;

            this.updFieldID = updFieldID;
            Init(navigation, nswItem);
            ClosePopupCommandCallback = () => { };

            if (fieldType != null) {
                switch (fieldType) {
                    case GConsts.FLDTYPE_PHON:
                        IsPhone = true;
                        break;
                    case GConsts.FLDTYPE_MAIL:
                        IsMail = true;
                        break;
                    case GConsts.FLDTYPE_LINK:
                        IsLink = true;
                        break;
                    case GConsts.FLDTYPE_2FAC:
                        Is2FA = true;
                        TwoFASourceCode = DefaultEditorText;
                        break;
                }
            }

            setTOTP();
            startTOTPTimer();
        }

        string TwoFASourceCode;
        Totp totp;

        void setTOTP()
        {
            if (TwoFASourceCode != null) {
                var value = TwoFASourceCode.Replace(" ", "");
                var bytes = Base32Encoding.ToBytes(value);
                totp = new Totp(bytes);
                var code = totp.ComputeTotp();
                DefaultEditorText = code;
            }
        }

        void startTOTPTimer()
        {
            var timer = new System.Timers.Timer();
            timer.Elapsed += TOTPTimerElapsed;
            timer.AutoReset = true;
            timer.Enabled = true;
            timer.Interval = 100;
        }

        void TOTPTimerElapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            var timeRemaining = totp.RemainingSeconds();
            TwoFATimeLeftProgress = (double)timeRemaining / 30.0;
            var code = totp.ComputeTotp();
            DefaultEditorText = code;
        }

        void Init(INavigation navigationParm, NSWItem nswItemParm)
        {
            this.navigation = navigationParm;
            this.nswItem = nswItemParm;
            SetLabelsList();
            SetFirstLabel();
            MaximumPasswordLength = GConsts.MAX_PASS_LEN;
            MinimumPasswordLength = GConsts.MIN_PASS_LEN;
            //ValuePasswordLength = GConsts.DEF_PASS_LEN;
            PasswordLengthText = Settings.PassGenLength.ToString();
        }

        /// <summary>
        /// Sets the labels list.
        /// </summary>
        public void SetLabelsList()
        {
            try {
                var nswLabels = BL.GetLabelsByUsage();
                var nswFormsLabels = new List<NSWFormsLabelModel>();

                foreach (var nswLabel in nswLabels) {
                    nswFormsLabels.Add(new NSWFormsLabelModel(nswLabel));
                }

                LabelsList = nswFormsLabels;
            } catch (Exception ex) {
                log(ex.Message, nameof(SetLabelsList));
            }
        }

        /// <summary>
        /// Sets the first label.
        /// </summary>
        public void SetFirstLabel()
        {
            PrepareScreenViewByType();
        }

        /// <summary>
        /// Sets the updating label.
        /// </summary>
        public void SetUpdatingLabel()
        {
            PrepareScreenViewByType();
        }

        string name;

        void PrepareScreenViewByType(object obj = null)
        {
            try {
                name = "";
                NSWFormsLabelModel nswFormsLabel;

                var nswLabels = BL.GetLabelsByUsage();

                // Preliminary checks to avoid crashes
                if (nswLabels == null)
                    return;
                if (nswItem == null)
                    return;
                if (!nswLabels.Any())
                    return;

                if (obj != null) // obj should be checked first
                {
                    nswFormsLabel = (NSWFormsLabelModel)obj;
                } else if (nswItem.Fields != null && !string.IsNullOrEmpty(updFieldID)) {
                    var nswField = nswItem.Fields.Find((x) => x.FieldID == updFieldID);
                    var nswFieldType = nswField.FieldType;
                    var nswLabel = nswLabels[nswLabels.FindIndex(x => x.FieldType == nswFieldType)];
                    name = nswField.FieldValue;
                    nswFormsLabel = new NSWFormsLabelModel(nswLabel);
                } else // adding new, select the first one
                  {
                    var nswLabel = nswLabels[0];
                    nswFormsLabel = new NSWFormsLabelModel(nswLabel);
                }

                TypeIcon = nswFormsLabel.Icon;
                TypeName = nswFormsLabel.Name;
                fieldType = nswFormsLabel.FieldType;
                valueType = nswFormsLabel.ValueType;

                SetDefaultSettings();

                // Special fields should be precessed before special values
                // to avoid interferring
                if (string.Compare(fieldType, GConsts.FLDTYPE_NOTE) == 0) {
                    SetNoteSettings(name);
                } else if (string.Compare(fieldType, GConsts.FLDTYPE_PASS) == 0) {
                    SetPasswordSettings(name);
                } else if (string.Compare(fieldType, GConsts.FLDTYPE_OLDP) == 0) {
                    SetOldPassSettings(name);
                } // Special values processing starts here
                  else if (string.Compare(valueType, GConsts.VALUETYPE_DATE) == 0) {
                    SetDateSettings(name);
                } else if (string.Compare(valueType, GConsts.VALUETYPE_TIME) == 0) {
                    SetTimeSettings(name);
                } else // Use default entry
                  {
                    DefaultEditorText = name;
                    convertedName = name;
                }

                // if called from popup (entry type is changes)
                if (obj != null) {
                    ClosePopupCommand.Execute(null);
                }
            } catch (Exception ex) {
                log(ex.Message, nameof(PrepareScreenViewByType));
            }
        }

        string convertedName = "";

        void SetDefaultSettings()
        {
            FieldDescription = "";
            IsDefaultLabel = true;
            IsDefaultEnabled = true;
            IsPassword = false;
            IsDateLabel = false;
            IsTimeLabel = false;
            IsNoteLabel = false;
        }

        void SetPasswordSettings(string passValue)
        {
            if (ViewMode) {
                IsPassword = false;
            } else {
                IsPassword = true;
            }
            convertedName = passValue;
            DefaultEditorText = passValue;
            FieldDescription = TR.Tr("clever_password_description");
        }

        void SetDateSettings(string dateValue)
        {
            if (string.IsNullOrEmpty(dateValue)) {
                DateEditorText = DateTime.Now;
            } else {
                DateEditorText = Common.ConvertDate(dateValue);
            }

            IsDateLabel = true;
            IsDefaultLabel = false;
        }

        void SetNoteSettings(string note)
        {
            IsNoteLabel = true;
            IsDefaultLabel = false;
            NoteEditorText = note;
        }

        void SetOldPassSettings(string oldPass)
        {
            FieldDescription = TR.Tr("previous_password_description");
            DefaultEditorText = oldPass;
            IsDefaultEnabled = false;
            IsDefaultLabel = false;
        }

        void SetTimeSettings(string timeValue)
        {
            if (string.IsNullOrEmpty(timeValue)) {
                TimeEditorText = DateTime.Now.TimeOfDay;
            } else {
                TimeSpan.TryParse(timeValue, out TimeSpan time);
                TimeEditorText = time;
            }

            IsTimeLabel = true;
            IsDefaultLabel = false;
            IsDefaultEnabled = false;
        }

        List<NSWFormsLabelModel> labelsList;
        public List<NSWFormsLabelModel> LabelsList {
            get { return labelsList; }
            set {
                if (labelsList == value)
                    return;
                labelsList = value;
                OnPropertyChanged("LabelsList");
            }
        }

        object selectedNSWLabel;
        public object SelectedNSWLabel {
            get { return selectedNSWLabel; }
            set {
                if (selectedNSWLabel == value)
                    return;
                selectedNSWLabel = value;
                if (selectedNSWLabel != null)
                    SelectedNSWLabelCommand.Execute(selectedNSWLabel);
                OnPropertyChanged("SelectedNSWLabel");
            }
        }

        Command createLabelCommand;
        public Command CreateLabelCommand {
            get {
                return createLabelCommand ?? (createLabelCommand = new Command(ExecuteCreateLabelCommand));
            }
        }

        protected void ExecuteCreateLabelCommand()
        {
            LM.StartCreatingLabel(navigation, SuccessCreateLabelCommand);
        }

        Command successCreateLabelCommand;
        public Command SuccessCreateLabelCommand {
            get {
                return successCreateLabelCommand ?? (successCreateLabelCommand = new Command(ExecuteSuccessCreateLabelCommand));
            }
        }

        protected void ExecuteSuccessCreateLabelCommand(object obj)
        {
            if (obj != null) {
                var label = BL.GetLabels().FirstOrDefault(x => x.FieldType == obj.ToString());
                Device.BeginInvokeOnMainThread(() => AppPages.ClosePage(navigation));
                SetLabelsList();
                PrepareScreenViewByType(new NSWFormsLabelModel(label));
            }
        }

        Command closePopupCommand;
        public Command ClosePopupCommand {
            get {
                return closePopupCommand ?? (closePopupCommand = new Command(ExecuteClosePopupCommand));
            }
        }

        protected void ExecuteClosePopupCommand()
        {
            ClosePopupCommandCallback.Invoke();
        }

        Command selectedNSWLabelCommand;
        public Command SelectedNSWLabelCommand {
            get {
                return selectedNSWLabelCommand ?? (selectedNSWLabelCommand = new Command(ExecuteSelectedNSWLabelCommand));
            }
        }

        protected void ExecuteSelectedNSWLabelCommand(object obj)
        {
            try {
                PrepareScreenViewByType(obj);

            } catch (Exception ex) {
                log(ex.Message, nameof(ExecuteSelectedNSWLabelCommand));
            }
        }

        Command passGenCommand;
        public Command PasswordGenerateCommand {
            get {
                return passGenCommand ?? (passGenCommand = new Command(GeneratePassword));
            }
        }

        protected void GeneratePassword()
        {
            if (!IsLowerCase && !IsUpperCase && !IsDigits && !IsSpecial) {
                PlatformSpecific.DisplayShortMessage(TR.Tr("manage_password_no_chosen"));
            } else {

                var length = Convert.ToInt32(PasswordLengthText);
                DefaultEditorText = Security.GeneratePassword(IsLowerCase, IsUpperCase, IsDigits, IsSpecial, length);
            }
        }

        Command cleverGenCommand;
        public Command CleverGenerateCommand {
            get {
                return cleverGenCommand ?? (cleverGenCommand = new Command(CleverGeneratePassword));
            }
        }

        protected void CleverGeneratePassword()
        {
            DefaultEditorText = Security.GenerateCleverPassword(DefaultEditorText);
        }

        Command saveFieldCommand;
        public Command SaveFieldCommand {
            get {
                return saveFieldCommand ?? (saveFieldCommand = new Command(ExecuteSaveFieldCommand));
            }
        }

        protected void ExecuteSaveFieldCommand()
        {
            try {
                string updText = null;

                if (string.Compare(valueType, GConsts.VALUETYPE_DATE) == 0) {
                    updText = Common.ConvertFromDate(DateEditorText);
                } else if (string.Compare(valueType, GConsts.VALUETYPE_TIME) == 0) {
                    updText = TimeEditorText.ToString("c");
                } else if (string.Compare(fieldType, GConsts.FLDTYPE_NOTE) == 0) {
                    updText = NoteEditorText;
                } else {
                    updText = DefaultEditorText;
                    /*
                    if (!string.IsNullOrEmpty(DefaultEditorText))
                    {
                        
                    }
                    else
                    {
                        success = false;
                    }
                    */
                }

                //if (success)
                //{
                if (nswItem != null) {
                    //int weight = 100;

                    if (manageFieldType.Equals(ManageFieldType.Create)) {
                        if (fieldType == GConsts.FLDTYPE_OLDP) {
                            var currentItem = BL.GetCurrentItem();
                            var field = currentItem.Fields.Find(x => x.FieldType == GConsts.FLDTYPE_OLDP);
                            if (field != null) {
                                PlatformSpecific.DisplayShortMessage(TR.Tr("previous_password_duplicate"));
                                return;
                            }
                        }

                        BL.AddField(fieldType, updText);
                    }

                    if (manageFieldType.Equals(ManageFieldType.Edit)) {
                        BL.UpdateField(updFieldID, updText, DataAccessLayer.DO_NOT_CHANGE_SORT);
                    }
                }

                MessagingCenter.Send(this, "/reloaditems");
                AppPages.CloseModalPage(navigation);
                //}
            } catch (Exception ex) {
                log(ex.Message, nameof(ExecuteSaveFieldCommand));
            }
        }

        Command showPopupCommand;
        public Command ShowPopupCommand {
            get {
                return showPopupCommand ?? (showPopupCommand = new Command(ExecuteShowPopupCommand));
            }
        }

        protected void ExecuteShowPopupCommand()
        {
            if (!manageFieldType.Equals(ManageFieldType.Edit))
                ShowPopupCommandCallback.Invoke();
        }

        Command plusCommand;
        public Command PlusCommand {
            get {
                return plusCommand ?? (plusCommand = new Command(ExecutePlusCommand));
            }
        }

        protected void ExecutePlusCommand()
        {
            var length = Convert.ToInt32(PasswordLengthText);
            if (MaximumPasswordLength != length) {
                length++;
                PasswordLengthText = length.ToString();
                Settings.PassGenLength = length;
            }
        }

        Command minusCommand;
        public Command MinusCommand {
            get {
                return minusCommand ?? (minusCommand = new Command(ExecuteMinusCommand));
            }
        }

        protected void ExecuteMinusCommand()
        {
            var length = Convert.ToInt32(PasswordLengthText);
            if (MinimumPasswordLength != length) {
                length--;
                PasswordLengthText = length.ToString();
                Settings.PassGenLength = length;
            }
        }

        ImageSource typeIcon;
        public ImageSource TypeIcon {
            get { return typeIcon; }
            set {
                if (typeIcon == value)
                    return;
                typeIcon = value;
                OnPropertyChanged("TypeIcon");
            }
        }

        double twoFATimeLeftProgress;
        public double TwoFATimeLeftProgress {
            get { return twoFATimeLeftProgress; }
            set {
                if (twoFATimeLeftProgress == value)
                    return;
                twoFATimeLeftProgress = value;
                OnPropertyChanged("TwoFATimeLeftProgress");
            }
        }

        string typeName;
        public string TypeName {
            get { return typeName; }
            set {
                if (typeName == value)
                    return;
                typeName = value;
                OnPropertyChanged("TypeName");
            }
        }

        bool isDateLabel;
        public bool IsDateLabel {
            get { return isDateLabel; }
            set {
                if (isDateLabel == value)
                    return;
                isDateLabel = value;
                OnPropertyChanged("IsDateLabel");
            }
        }

        bool isDefaultEnabled;
        public bool IsDefaultEnabled {
            get { return isDefaultEnabled; }
            set {
                if (isDefaultEnabled == value)
                    return;
                isDefaultEnabled = value;
                OnPropertyChanged("IsDefaultEnabled");
            }
        }

        bool isTimeLabel;
        public bool IsTimeLabel {
            get { return isTimeLabel; }
            set {
                if (isTimeLabel == value)
                    return;
                isTimeLabel = value;
                OnPropertyChanged("IsTimeLabel");
            }
        }

        bool isNoteLabel;
        public bool IsNoteLabel {
            get { return isNoteLabel; }
            set {
                if (isNoteLabel == value)
                    return;
                isNoteLabel = value;
                OnPropertyChanged("IsNoteLabel");
            }
        }

        bool isPassword;
        public bool IsPassword {
            get { return isPassword; }
            set {
                if (isPassword == value)
                    return;
                isPassword = value;
                OnPropertyChanged("IsPassword");

            }
        }

        bool isDefaultLabel;
        public bool IsDefaultLabel {
            get { return isDefaultLabel; }
            set {
                if (isDefaultLabel == value)
                    return;
                isDefaultLabel = value;
                OnPropertyChanged("IsDefaultLabel");
            }
        }

        string noteEditorText;
        public string NoteEditorText {
            get { return noteEditorText; }
            set {
                if (noteEditorText == value)
                    return;
                noteEditorText = value;
                OnPropertyChanged("NoteEditorText");
            }
        }

        string fieldDescription;
        public string FieldDescription {
            get { return fieldDescription; }
            set {
                if (fieldDescription == value)
                    return;
                fieldDescription = value;
                OnPropertyChanged("FieldDescription");
            }
        }

        DateTime dateEditorText;
        public DateTime DateEditorText {
            get { return dateEditorText; }
            set {
                if (dateEditorText == value)
                    return;
                dateEditorText = value;
                OnPropertyChanged("DateEditorText");
            }
        }

        bool is2FA;
        public bool Is2FA {
            get { return is2FA; }
            set {
                if (is2FA == value)
                    return;
                is2FA = value;
                OnPropertyChanged("Is2FA");
            }
        }

        bool isLink;
        public bool IsLink {
            get { return isLink; }
            set {
                if (isLink == value)
                    return;
                isLink = value;
                OnPropertyChanged("IsLink");
            }
        }

        bool isMail;
        public bool IsMail {
            get { return isMail; }
            set {
                if (isMail == value)
                    return;
                isMail = value;
                OnPropertyChanged("IsMail");
            }
        }

        bool isPhone;
        public bool IsPhone {
            get { return isPhone; }
            set {
                if (isPhone == value)
                    return;
                isPhone = value;
                OnPropertyChanged("IsPhone");
            }
        }

        TimeSpan timeEditorText;
        public TimeSpan TimeEditorText {
            get { return timeEditorText; }
            set {
                if (timeEditorText == value)
                    return;
                timeEditorText = value;
                OnPropertyChanged("TimeEditorText");
            }
        }

        string defaultEditorText;
        public string DefaultEditorText {
            get { return defaultEditorText; }
            set {
                if (defaultEditorText == value)
                    return;
                defaultEditorText = value;
                OnPropertyChanged("DefaultEditorText");
            }
        }

        public bool IsCreate {
            get {
                if (manageFieldType.Equals(ManageFieldType.Create))
                    return true;

                return false;
            }
        }

        bool isEdit;
        public bool IsEdit {
            get {
                return isEdit;
            }
            set {
                if (isEdit == value)
                    return;
                isEdit = value;
                OnPropertyChanged("IsEdit");
            }
        }

        int maximumPasswordLength;
        public int MaximumPasswordLength {
            get { return maximumPasswordLength; }
            set {
                if (maximumPasswordLength == value)
                    return;
                maximumPasswordLength = value;
                OnPropertyChanged("MaximumPasswordLength");
            }
        }

        int minimumPasswordLength;
        public int MinimumPasswordLength {
            get { return minimumPasswordLength; }
            set {
                if (minimumPasswordLength == value)
                    return;
                minimumPasswordLength = value;
                OnPropertyChanged("MinimumPasswordLength");
            }
        }

        /*
        int valuePasswordLength;
        public int ValuePasswordLength
        {
            get { return valuePasswordLength; }
            set
            {
                if (valuePasswordLength == value)
                    return;
                valuePasswordLength = value;
                PasswordLengthText = valuePasswordLength.ToString();
                OnPropertyChanged("ValuePasswordLength");
            }
        }
        */

        string passwordLengthText;
        public string PasswordLengthText {
            get { return passwordLengthText; }
            set {
                if (passwordLengthText == value)
                    return;
                passwordLengthText = value;
                OnPropertyChanged("PasswordLengthText");
            }
        }

        bool isUpperCase;
        public bool IsUpperCase {
            get { return Settings.ManageUpperCase; }
            set {
                if (isUpperCase == value)
                    return;
                isUpperCase = value;
                Settings.ManageUpperCase = value;
                OnPropertyChanged("IsUpperCase");
            }
        }

        bool isLowerCase;
        public bool IsLowerCase {
            get { return Settings.ManageLowerCase; }
            set {
                if (isLowerCase == value)
                    return;
                isLowerCase = value;
                Settings.ManageLowerCase = value;
                OnPropertyChanged("IsLowerCase");
            }
        }

        bool isDigits;
        public bool IsDigits {
            get { return Settings.ManageDigits; }
            set {
                if (isDigits == value)
                    return;
                isDigits = value;
                Settings.ManageDigits = value;
                OnPropertyChanged("IsDigits");
            }
        }

        bool isSpecial;
        public bool IsSpecial {
            get { return Settings.ManageSpecialSymbols; }
            set {
                if (isSpecial == value)
                    return;
                isSpecial = value;
                Settings.ManageSpecialSymbols = value;
                OnPropertyChanged("IsSpecial");
            }
        }

        bool viewMode;
        public bool ViewMode {
            get { return viewMode; }
            set {
                if (viewMode == value)
                    return;
                viewMode = value;
                OnPropertyChanged("ViewMode");
                NotViewMode = !viewMode;
            }
        }

        bool notViewMode;
        public bool NotViewMode {
            get { return notViewMode; }
            set {
                if (notViewMode == value)
                    return;
                notViewMode = value;
                OnPropertyChanged("NotViewMode");
            }
        }

        Command editCommand;
        public Command EditCommand {
            get {
                return editCommand ?? (editCommand = new Command(ExecuteEditCommand));
            }
        }

        private void ExecuteEditCommand()
        {
            ViewMode = !ViewMode;
            IsLink = false;
            IsMail = false;
            IsPhone = false;

            IsEdit = false;

            if (fieldType == GConsts.FLDTYPE_PASS) {
                if (ViewMode) {
                    IsPassword = false;
                } else {
                    IsPassword = true;
                }
            }
        }

        Command copyClipCommand;
        public Command CopyClipCommand {
            get {
                return copyClipCommand ?? (copyClipCommand = new Command(ExecuteCopyClipCommand));
            }
        }

        private void ExecuteCopyClipCommand()
        {
            if (humanReadableFieldValue != null) {
                PlatformSpecific.CopyToClipboard(humanReadableFieldValue);
                PlatformSpecific.DisplayShortMessage(TR.Tr("field_clipboard_copied"));
                AppPages.CloseModalPage(navigation);
            }
        }

        Command copyLocallyCommand;
        public Command CopyLocallyCommand {
            get {
                return copyLocallyCommand ?? (copyLocallyCommand = new Command(ExecuteCopyLocallyCommand));
            }
        }

        private void ExecuteCopyLocallyCommand()
        {
            Device.BeginInvokeOnMainThread(async () => {
                var res = await Application.Current.MainPage.DisplayActionSheet(null, "cancel", null, "Copy to clipboard", "Copy locally");

                if (res == "Copy to clipboard") {

                    CopyClipCommand.Execute(null);
                }

                if (res == "Copy locally") {
                    StateHandler.CopyFieldLocallyActivated = true;
                    AppPages.CloseModalPage(navigation);
                }
            });
        }

        Command deleteFieldCommand;
        public Command DeleteFieldCommand {
            get {
                return deleteFieldCommand ?? (deleteFieldCommand = new Command(ExecuteDeleteFieldCommand));
            }
        }

        private void ExecuteDeleteFieldCommand()
        {
            StateHandler.DeleteFieldActivated = true;
            AppPages.CloseModalPage(navigation);
        }

        bool isPhoneNumber(string number)
        {
            return Regex.Match(number, @"^\+?(\d[\d-. ]+)?(\([\d-. ]+\))?[\d-. ]+\d$").Success;
        }

        Command dialCommand;
        public Command DialCommand {
            get {
                return dialCommand ?? (dialCommand = new Command(ExecuteDialCommand));
            }
        }

        void ExecuteDialCommand()
        {
            var fieldValue = humanReadableFieldValue;
            if (isPhoneNumber(fieldValue)) {
                PlatformSpecific.OpenPhoneDialer(fieldValue);

            }
        }

        Command mailCommand;
        public Command MailCommand {
            get {
                return mailCommand ?? (mailCommand = new Command(ExecuteMailCommand));
            }
        }

        void ExecuteMailCommand()
        {
            var fieldValue = humanReadableFieldValue;
            //Device.OpenUri(new Uri(String.Format("mailto:{0}", fieldValue)));
            try {
                List<string> recipients = new List<string> {
                    fieldValue
                };
                var message = new EmailMessage {
                    //Subject = subject,
                    //Body = body,
                    To = recipients,
                    //Cc = ccRecipients,
                    //Bcc = bccRecipients
                };
                Email.ComposeAsync(message);
            } catch (FeatureNotSupportedException fbsEx) {
                log(fbsEx.Message);
            } catch (Exception ex) {
                log(ex.Message);
            }
        }

        Command linkCommand;
        public Command LinkCommand {
            get {
                return linkCommand ?? (linkCommand = new Command(ExecuteLinkCommand));
            }
        }

        void ExecuteLinkCommand()
        {
            var fieldValue = humanReadableFieldValue;
            if (!(fieldValue.ToLower().StartsWith("http://", StringComparison.Ordinal) ||
                fieldValue.ToLower().StartsWith("https://", StringComparison.Ordinal))) {
                fieldValue = "http://" + fieldValue;
            }
            Browser.OpenAsync(new Uri(fieldValue), BrowserLaunchMode.SystemPreferred);
            //Device.OpenUri();
        }

        void log(string message, string method = null)
        {
            AppLogs.Log(message, method, nameof(ManageFieldViewModel));
        }
    }
}