using System; using System.Collections.Generic; using System.Threading.Tasks; using System.Threading; using System.Linq; using Xamarin.Forms; using InABox.Core; using InABox.Clients; using System.IO; using InABox.Mobile; using Syncfusion.XForms.SignaturePad; using Comal.Classes; using PRSClasses; namespace PRS.Mobile { public class QAFormViewer : Grid, IDFRenderer { #region Fields public Dictionary pairs = new Dictionary(); public Dictionary results = new Dictionary(); public Dictionary propertyResults = new Dictionary(); Dictionary loadData = new Dictionary(); public Dictionary> dfLayoutLookupFieldLookupOptions = new Dictionary>(); DFLayout dfLayout = null; public IDigitalFormDataModel model = null; const string nullOrInvalidType = "Null or Invalid Type"; int rbGroup; private Guid userID; bool isRequired = false; bool readOnly = false; bool isSecure = false; bool loadRetainedForm = false; List useSavedSignatures = new List(); public List errors = new List(); public bool isRequiredEmpty { get; set; } public string isRequiredMessage { get; set; } InABox.Core.Location location = new InABox.Core.Location(); Guid digitalFormID = Guid.Empty; Color isRequiredColor = Color.DarkOrange; public string FormData = ""; public DateTime FormCompleted = DateTime.MinValue; public Guid JobID = Guid.Empty; DateTime timeStarted = DateTime.MinValue; List headersToCollapse = new List(); int collapsedHeaderCount = 1; #endregion #region Constructor public QAFormViewer() { } public QAFormViewer(IDigitalFormDataModel _model, DFLayout _dfLayout, bool newForm, bool _readOnly, Guid _jobid = default(Guid)) : this() { Load(_model, _dfLayout, newForm, _readOnly, _jobid); } public void Load(IDigitalFormDataModel _model, DFLayout _dfLayout, bool newForm, bool _readOnly, Guid _jobid = default(Guid)) { GetLocation(); timeStarted = DateTime.Now; userID = ClientFactory.UserGuid; model = _model; dfLayout = _dfLayout; dfLayout.Renderer = this; readOnly = _readOnly; isRequiredEmpty = false; loadRetainedForm = false; isRequiredMessage = ""; JobID = _jobid; if (RetainedResults.IsFormRetained) { loadRetainedForm = true; } if (newForm) { LoadForm(); } else if (!newForm) { loadData.Clear(); Dictionary data = DigitalForm.DeserializeFormData(model.Instance); if (data != null) { foreach (KeyValuePair keyValuePair in data) { loadData.Add(keyValuePair.Key, keyValuePair.Value.ToString()); } } LoadForm(); } } #endregion #region Location private async void GetLocation() { await Task.Run(() => { LocationServices locationServices = new LocationServices(); locationServices.OnLocationFound += LocationFound; locationServices.OnLocationError += LocationError; locationServices.GetLocation(); }); } private async void LocationFound(LocationServices sender) { location.Latitude = sender.Latitude; location.Longitude = sender.Longitude; } private async void LocationError(LocationServices sender, Exception error) { errors.Add("Location error: " + error.Message); } #endregion Location #region Load Form Layout private async void LoadForm() { { LoadRowsAndColumns(); LoadElements(); } } private void LoadRowsAndColumns() { LoadRows(); LoadColumns(); } private void LoadRows() { foreach (var row in dfLayout.RowHeights) { RowDefinition def = new RowDefinition { Height = new GridLength(1, GridUnitType.Auto) }; if (int.TryParse(row, out int rowHeight)) { def = new RowDefinition { Height = new GridLength(rowHeight, GridUnitType.Absolute) }; if (def.Height.Value < 60) { def.SetValue(RowDefinition.HeightProperty, 60); } } else if (row.Contains("*")) { if (int.TryParse(row.Substring(0, row.IndexOf("*")), out int result)) { def = new RowDefinition { Height = new GridLength(result, GridUnitType.Star) }; } else def = new RowDefinition { Height = new GridLength(1, GridUnitType.Star) }; } Device.BeginInvokeOnMainThread(() => { RowDefinitions.Add(def); }); } } private void LoadColumns() { foreach (var col in dfLayout.ColumnWidths) { ColumnDefinition def = new ColumnDefinition { Width = new GridLength(1, GridUnitType.Auto) }; if (int.TryParse(col, out int colWidth)) def = new ColumnDefinition { Width = new GridLength(colWidth, GridUnitType.Absolute) }; else if (col.Contains("*")) { if (int.TryParse(col.Substring(0, col.IndexOf("*")), out int result)) { def = new ColumnDefinition { Width = new GridLength(result, GridUnitType.Star) }; } else def = new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) }; } Device.BeginInvokeOnMainThread(() => { ColumnDefinitions.Add(def); }); } } private void LoadElements() { rbGroup = 0; //used for customboolean - has to be outside of foreach loop foreach (DFLayoutControl element in dfLayout.Elements) { if (!string.IsNullOrEmpty(element.Description)) { LoadViewAccordingToElement(element); } } Task.Run(() => { Thread.Sleep(1000); foreach (var header in headersToCollapse) { Device.BeginInvokeOnMainThread(() => { AdjustHeaderSection(header, false); header.Collapse(); }); } }); } #endregion #region Load Element Methods private void LoadViewAccordingToElement(DFLayoutControl element) { isSecure = false; if (element is DFLayoutBooleanField) { var tuple = LoadCustomBoolean(element); FormatAndAddView(tuple.Item1, element, tuple.Item2); } else if (element is DFLayoutLabel) { var tuple = LoadLabel(element); FormatAndAddView(tuple.Item1, element, tuple.Item2); } else if (element is DFLayoutStringField || element is DFLayoutIntegerField || element is DFLayoutDoubleField) { var tuple = LoadEditor(element); FormatAndAddView(tuple.Item1, element, tuple.Item2); } else if (element is DFLayoutDateField) { var tuple = LoadDatePicker(element); FormatAndAddView(tuple.Item1, element, tuple.Item2); } else if (element is DFLayoutTimeField) { var tuple = LoadTimePicker(element); FormatAndAddView(tuple.Item1, element, tuple.Item2); } else if (element is DFLayoutOptionField) { var tuple = LoadOptionPicker(element); FormatAndAddView(tuple.Item1, element, tuple.Item2); } else if (element is DFLayoutImage) { var tuple = LoadImage(element); FormatAndAddView(tuple.Item1, element, tuple.Item2); } else if (element is DFLayoutLookupField) { var tuple = LoadLookupPicker(element); FormatAndAddView(tuple.Item1, element, tuple.Item2); } else if (element is DFLayoutSignaturePad) { var tuple = LoadSignaturePad(element); FormatAndAddView(tuple.Item1, element, tuple.Item2); } else if (element is DFLayoutEmbeddedImage) { var tuple = LoadEmbeddedImage(element); FormatAndAddView(tuple.Item1, element, tuple.Item2); } else if (element is DFLayoutMultiImage) { var tuple = LoadMultiImage(element); FormatAndAddView(tuple.Item1, element, tuple.Item2); } else if (element is DFLayoutMultiSignaturePad) { var tuple = LoadMultiSignaturePad(element); FormatAndAddView(tuple.Item1, element, tuple.Item2); } else if (element is DFLayoutAddTaskField) { var tuple = LoadAddTaskField(element); FormatAndAddView(tuple.Item1, element, tuple.Item2); } else if (element is DFLayoutHeader) { FormatAndAddView(LoadHeader(element), element, false); } else if (element is DFLayoutVideoField) { var tuple = LoadVideoField(element); FormatAndAddView(tuple.Item1, element, tuple.Item2); } } private View LoadHeader(DFLayoutControl element) { DFLayoutHeader dFLayoutHeader = (DFLayoutHeader)element; DigitalFormsHeader header = new DigitalFormsHeader(dFLayoutHeader.Collapsed); header.SetHeaderStyle(dFLayoutHeader); if (dFLayoutHeader.Collapsed) header = AddNumberToHeader(header); header.SetHeaderValue(dFLayoutHeader.Header); header.OnTapped += (bCollapsed) => { AdjustHeaderSection(header, bCollapsed); }; return header; } private DigitalFormsHeader AddNumberToHeader(DigitalFormsHeader header) { header.Number = collapsedHeaderCount; collapsedHeaderCount++; return header; } private void AdjustHeaderSection(DigitalFormsHeader header, bool collapsed) { try { var thisHeaderRow = GetRow(header); var headerRows = GetOtherHeaders(thisHeaderRow); if (headerRows.Any()) AdjustHeightsToNextHeader(headerRows, thisHeaderRow, collapsed); else AdjustHeightsBelowHeader(headerRows, thisHeaderRow, collapsed); } catch { } } private List GetOtherHeaders(int thisHeaderRow) { List headerRows = new List(); foreach (var child in Children) { if (child is DigitalFormsHeader) { var dfheader = (DigitalFormsHeader)child; if (GetRow(dfheader) > thisHeaderRow) { headerRows.Add(GetRow(dfheader)); } } } return headerRows; } private void AdjustHeightsToNextHeader(List headerRows, int thisHeaderRow, bool collapsed) { headerRows.Sort(); int nextHeaderRow = headerRows[0]; for (int i = thisHeaderRow + 1; i < nextHeaderRow; i++) { AdjustHeight(i, collapsed); } } private void AdjustHeightsBelowHeader(List headerRows, int thisHeaderRow, bool collapsed) { for (int i = thisHeaderRow + 1; i < RowDefinitions.Count; i++) { AdjustHeight(i, collapsed); } } private void AdjustHeight(int i, bool collapsed) { var rowdef = RowDefinitions[i]; if (collapsed) { rowdef.Height = 60; //AnimateChildren(i, 0, 250); } else { //AnimateChildren(i, -60, 500); rowdef.Height = 0; } } private async void AnimateChildren(int i, int movement, int length) { foreach (var child in Children) { if (GetRow(child) == i) { await child.TranslateTo(0, movement, 250); } } } private Tuple LoadCustomBoolean(DFLayoutControl element) { string value = ""; rbGroup++; CustomBoolean item = new CustomBoolean(rbGroup); DFLayoutBooleanField dfLayoutBooleanField = element as DFLayoutBooleanField; if (!string.IsNullOrWhiteSpace(dfLayoutBooleanField.Properties.TrueValue)) item.trueBtn.Content = dfLayoutBooleanField.Properties.TrueValue; if (!string.IsNullOrWhiteSpace(dfLayoutBooleanField.Properties.FalseValue)) item.falseBtn.Content = dfLayoutBooleanField.Properties.FalseValue; if (loadData.TryGetValue(dfLayoutBooleanField.Name, out value)) { if (!string.IsNullOrWhiteSpace(value)) { item.Value = bool.Parse(value); if (bool.Parse(value) == false) item.SetFalseValue(); } } if (loadRetainedForm) { if (RetainedResults.Results.TryGetValue(dfLayoutBooleanField.Name, out value)) { item.Value = bool.Parse(value); } } if (dfLayoutBooleanField.Properties.Required) { item.trueBtn.BackgroundColor = isRequiredColor; item.falseBtn.BackgroundColor = isRequiredColor; } item.OnCustomBooleanValueChanged += (boolvalue) => { dfLayout.ChangeField(dfLayoutBooleanField.Name); }; return new Tuple(item, dfLayoutBooleanField.Properties.Required); } private Tuple LoadLabel(DFLayoutControl element) { DFLayoutLabel label = element as DFLayoutLabel; Label item = new Label(); item.Text = label.Caption; item.TextColor = Color.Black; item.LineBreakMode = label.Style.TextWrapping == true ? LineBreakMode.WordWrap : LineBreakMode.NoWrap; item.VerticalOptions = LayoutOptions.FillAndExpand; item.MinimumHeightRequest = 60; item.BackgroundColor = label.Style.BackgroundColour; item.FontAttributes = label.Style.IsBold ? FontAttributes.Bold : label.Style.IsItalic ? FontAttributes.Italic : FontAttributes.None; item.TextDecorations = label.Style.Underline == UnderlineType.Single || label.Style.Underline == UnderlineType.Double ? TextDecorations.Underline : TextDecorations.None; item.FontSize = label.Style.FontSize > 5 && label.Style.FontSize < 37 ? label.Style.FontSize : Device.GetNamedSize(NamedSize.Medium, item); item.TextColor = label.Style.ForegroundColour; if (ColumnDefinitions.Count == 1) { item.HorizontalOptions = LayoutOptions.CenterAndExpand; item.HorizontalTextAlignment = TextAlignment.Center; } item.HorizontalTextAlignment = label.Style.HorizontalTextAlignment == DFLayoutAlignment.Start ? TextAlignment.Start : label.Style.HorizontalTextAlignment == DFLayoutAlignment.Middle ? TextAlignment.Center : label.Style.HorizontalTextAlignment == DFLayoutAlignment.End ? TextAlignment.End : item.HorizontalTextAlignment; item.VerticalTextAlignment = label.Style.VerticalTextAlignment == DFLayoutAlignment.Start ? TextAlignment.Start : label.Style.HorizontalTextAlignment == DFLayoutAlignment.Middle ? TextAlignment.Center : label.Style.HorizontalTextAlignment == DFLayoutAlignment.End ? TextAlignment.End : TextAlignment.Center; return new Tuple(item, false); } private Tuple LoadEditor(DFLayoutControl element) { string value = ""; View view = null; Editor item = new Editor(); item.AutoSize = EditorAutoSizeOption.TextChanges; var isrequired = false; var issecure = false; if (element is DFLayoutStringField) { DFLayoutStringField dfLayoutStringField = element as DFLayoutStringField; item.TextColor = Color.Black; item.Placeholder = "Enter answer"; isrequired = dfLayoutStringField.Properties.Required; issecure = dfLayoutStringField.Properties.Secure; DataButtonControl button = new DataButtonControl(); button.Clicked += (s, e) => { PopupEditor edt = new PopupEditor(button.Data); edt.OnPopupEdtSaved += (text) => { button.Data = text; button.Text = text.Length > 25 ? text.Substring(0, 25) + "..." : text; dfLayout.ChangeField(dfLayoutStringField.Name); }; Navigation.PushAsync(edt); }; button.Text = "Edit"; if (loadData.TryGetValue(dfLayoutStringField.Name, out value)) { if (!string.IsNullOrWhiteSpace(value)) { item.Text = value; button.Text = value.Length > 25 ? value.Substring(0, 25) + "..." : value; } } if (loadRetainedForm) { if (RetainedResults.Results.TryGetValue(dfLayoutStringField.Name, out value)) { item.Text = value; button.Text = value.Length > 25 ? value.Substring(0, 25) + "..." : value; } } item.TextChanged += (object sender, TextChangedEventArgs e) => { dfLayout.ChangeField(dfLayoutStringField.Name); }; if (dfLayoutStringField.Properties.PopupEditor) view = button; else view = item; } else if (element is DFLayoutIntegerField) { DFLayoutIntegerField dfLayoutIntegerField = element as DFLayoutIntegerField; item.TextColor = Color.Black; item.Placeholder = "Enter number"; item.Keyboard = Keyboard.Numeric; isrequired = dfLayoutIntegerField.Properties.Required; issecure = dfLayoutIntegerField.Properties.Secure; if (loadData.TryGetValue(dfLayoutIntegerField.Name, out value)) { if (!string.IsNullOrWhiteSpace(value)) { item.Text = value; } } if (loadRetainedForm) { if (RetainedResults.Results.TryGetValue(dfLayoutIntegerField.Name, out value)) { item.Text = value; } } item.TextChanged += (object sender, TextChangedEventArgs e) => { dfLayout.ChangeField(dfLayoutIntegerField.Name); }; view = item; } else if (element is DFLayoutDoubleField) { DFLayoutDoubleField dfLayoutDoubleField = element as DFLayoutDoubleField; item.TextColor = Color.Black; item.Placeholder = "Enter number"; item.Keyboard = Keyboard.Numeric; isrequired = dfLayoutDoubleField.Properties.Required; issecure = dfLayoutDoubleField.Properties.Secure; if (loadData.TryGetValue(dfLayoutDoubleField.Name, out value)) { if (!string.IsNullOrWhiteSpace(value)) { item.Text = value; } } if (loadRetainedForm) { if (RetainedResults.Results.TryGetValue(dfLayoutDoubleField.Name, out value)) { item.Text = value; } } item.TextChanged += (object sender, TextChangedEventArgs e) => { dfLayout.ChangeField(dfLayoutDoubleField.Name); }; view = item; } if (isrequired) view.BackgroundColor = isRequiredColor; if (readOnly || issecure) { Label label = new Label(); label.Text = item.Text; label.FontSize = Device.GetNamedSize(NamedSize.Medium, item); label.TextColor = Color.DarkGray; label.LineBreakMode = LineBreakMode.WordWrap; label.MaxLines = 5; label.VerticalTextAlignment = TextAlignment.Center; label.HorizontalTextAlignment = TextAlignment.Center; label.MinimumHeightRequest = 60; label.VerticalOptions = LayoutOptions.FillAndExpand; label.Margin = 9; view = label; } return new Tuple(view, isrequired); } private Tuple LoadDatePicker(DFLayoutControl element) { string value = ""; DFLayoutDateField dfLayoutDateField = element as DFLayoutDateField; DatePicker item = new DatePicker(); item.Format = "dd-MM-yyyy"; if (dfLayoutDateField.Properties.Required) item.BackgroundColor = isRequiredColor; item.HorizontalOptions = LayoutOptions.CenterAndExpand; if (loadData.TryGetValue(dfLayoutDateField.Name, out value)) { if (!string.IsNullOrWhiteSpace(value)) { try { item.Date = DateTime.Parse(value); } catch { } } } if (loadRetainedForm) { if (RetainedResults.Results.TryGetValue(dfLayoutDateField.Name, out value)) { item.Date = DateTime.Parse(value); } } item.DateSelected += (object sender, DateChangedEventArgs e) => { dfLayout.ChangeField(dfLayoutDateField.Name); }; return new Tuple(item, dfLayoutDateField.Properties.Required); } private Tuple LoadTimePicker(DFLayoutControl element) { string value = ""; DFLayoutTimeField dfLayoutTimeField = element as DFLayoutTimeField; TimePicker item = new TimePicker(); if (dfLayoutTimeField.Properties.Required) item.BackgroundColor = isRequiredColor; item.HorizontalOptions = LayoutOptions.Center; if (loadData.TryGetValue(dfLayoutTimeField.Name, out value)) { if (!string.IsNullOrWhiteSpace(value)) { item.Time = DateTime.Parse(value).TimeOfDay; } } if (loadRetainedForm) { if (RetainedResults.Results.TryGetValue(dfLayoutTimeField.Name, out value)) { item.Time = DateTime.Parse(value).TimeOfDay; } } item.PropertyChanged += (object sender, System.ComponentModel.PropertyChangedEventArgs e) => { if (e.PropertyName == "Time") dfLayout.ChangeField(dfLayoutTimeField.Name); }; return new Tuple(item, dfLayoutTimeField.Properties.Required); } private Tuple LoadOptionPicker(DFLayoutControl element) { View view = null; try { string value = ""; var isrequired = false; DFLayoutOptionField dfLayoutOptionField = element as DFLayoutOptionField; isrequired = dfLayoutOptionField.Properties.Required; if (Device.RuntimePlatform.Equals(Device.iOS)) { CustomPickeriOS item = new CustomPickeriOS(); string s = dfLayoutOptionField.Properties.Options; string[] substrings = s.Split(','); var optionList = substrings.ToList(); item.AddItems(optionList); if (!string.IsNullOrEmpty(dfLayoutOptionField.Properties.Default)) { int index = optionList.IndexOf(dfLayoutOptionField.Properties.Default); item.SelectedIndex = index; item.SelectedItem = optionList[index]; item.SetDefault(optionList[index]); } if (loadData.TryGetValue(dfLayoutOptionField.Name, out value)) { if (!string.IsNullOrWhiteSpace(value)) { int index = optionList.IndexOf(value); item.SelectedIndex = index; item.SelectedItem = optionList[index]; item.SetDefault(optionList[index]); } } if (loadRetainedForm) { if (RetainedResults.Results.TryGetValue(dfLayoutOptionField.Name, out value)) { int index = optionList.IndexOf(value); item.SelectedIndex = index; item.SelectedItem = optionList[index]; item.SetDefault(optionList[index]); } } if (isrequired) { item.BackgroundColor = isRequiredColor; item.SetBackGroundColor(isRequiredColor); } item.CustomPickeriOSValueChanged += () => { dfLayout.ChangeField(dfLayoutOptionField.Name); }; view = item; } else { Picker picker = new Picker(); picker.Title = "Select an option"; picker.VerticalTextAlignment = TextAlignment.Center; picker.HorizontalTextAlignment = TextAlignment.Center; string s = dfLayoutOptionField.Properties.Options; string[] substrings = s.Split(','); var optionList = substrings.ToList(); picker.ItemsSource = optionList; if (!string.IsNullOrEmpty(dfLayoutOptionField.Properties.Default)) { int index = optionList.IndexOf(dfLayoutOptionField.Properties.Default); picker.SelectedIndex = index; picker.SelectedItem = optionList[index]; } if (loadData.TryGetValue(dfLayoutOptionField.Name, out value)) { if (!string.IsNullOrWhiteSpace(value)) { int index = optionList.IndexOf(value); picker.SelectedIndex = index; picker.SelectedItem = optionList[index]; } } if (loadRetainedForm) { if (RetainedResults.Results.TryGetValue(dfLayoutOptionField.Name, out value)) { int index = optionList.IndexOf(value); picker.SelectedIndex = index; picker.SelectedItem = optionList[index]; } } if (isrequired) { picker.BackgroundColor = isRequiredColor; } picker.SelectedIndexChanged += (object sender, EventArgs e) => { dfLayout.ChangeField(dfLayoutOptionField.Name); }; view = picker; } return new Tuple(view, isrequired); } catch { return new Tuple(view, false); } } private Tuple LoadImage(DFLayoutControl element) { View view = null; DFLayoutImage dfLayoutImage = element as DFLayoutImage; Image img = new Image(); CoreTable table = new Client().Query( new Filter(x => x.ID).IsEqualTo(dfLayoutImage.Image.ID), null, null); if (table.Rows.Any()) { CoreRow row = table.Rows.FirstOrDefault(); byte[] data = row.Get(x => x.Data); ImageSource src = ImageSource.FromStream(() => new MemoryStream(data)); img.MinimumHeightRequest = 150; img.MinimumWidthRequest = 150; img.Aspect = Aspect.AspectFit; img.Source = src; img.HorizontalOptions = LayoutOptions.FillAndExpand; img.VerticalOptions = LayoutOptions.FillAndExpand; img.GestureRecognizers.Add(new TapGestureRecognizer { Command = new Command(OnTap), CommandParameter = src, NumberOfTapsRequired = 1 }); if (img != null) { view = img; } } return new Tuple(view, false); } private void OnTap(object obj) { ImageViewerPage viewer = new ImageViewerPage(obj as ImageSource); Navigation.PushAsync(viewer); } private Tuple LoadLookupPicker(DFLayoutControl element) { View view = null; string value = ""; DFLayoutLookupField dfLayoutLookupField = element as DFLayoutLookupField; var isrequired = dfLayoutLookupField.Properties.Required; Dictionary lookupFieldOptions = new Dictionary(); string type = dfLayoutLookupField.Properties.LookupType; Type lookuptype = CoreUtils.GetEntityOrNull(type); if (lookuptype == typeof(DrawingTemplate)) view = LoadDrawingTemplateLookupButton(lookuptype, dfLayoutLookupField, lookupFieldOptions, element); else if (!string.IsNullOrWhiteSpace(dfLayoutLookupField.Properties.Filter)) view = LoadGenericLookupButton(lookuptype, dfLayoutLookupField, lookupFieldOptions, element); else if (lookuptype == typeof(Product)) view = LoadProductLookupPicker(view, dfLayoutLookupField, value); else if (lookuptype != null) view = LoadGenericLookupButton(lookuptype, dfLayoutLookupField, lookupFieldOptions, element); else if (lookuptype == null) view = new Label { Text = "Null lookup selected", HorizontalOptions = LayoutOptions.Center, HorizontalTextAlignment = TextAlignment.Center }; return new Tuple(view, isrequired); } private View LoadGenericLookupButton(Type lookuptype, DFLayoutLookupField dfLayoutLookupField, Dictionary lookupFieldOptions, DFLayoutControl element) { string value = ""; CoreTable table = new CoreTable(); var client = ClientFactory.CreateClient(lookuptype); var columns = LookupFactory.DefineColumns(lookuptype); var sort = LookupFactory.DefineSort(lookuptype); var filter = LookupFactory.DefineFilter(lookuptype); foreach (var property in dfLayoutLookupField.Properties.AdditionalPropertiesList) { columns.Add(property); } if (!string.IsNullOrWhiteSpace(dfLayoutLookupField.Properties.Filter)) filter = ReturnFilter(dfLayoutLookupField, lookuptype); if (lookuptype == typeof(ProductStyle) && JobID != Guid.Empty) table = ReturnJobStyleProducts(table, client, columns, sort); if (table.Rows.Count == 0) table = client.Query(filter, columns, sort); // do generic query if a specific one hasn't already been done Dictionary> additionalPropertyValues = new Dictionary>(); foreach (var row in table.Rows) { Guid id = row.Get("ID"); Dictionary values = row.ToDictionary(new string[] { "ID" }); additionalPropertyValues.Add(id, values); string display = LookupFactory.FormatLookup(lookuptype, values, new string[] { }); lookupFieldOptions[id] = display; } dfLayoutLookupFieldLookupOptions[element as DFLayoutLookupField] = lookupFieldOptions; List itemList = lookupFieldOptions.Values.ToList(); DataButtonControl button = new DataButtonControl() { Text = "Choose Option", Margin = 0, ExtraData = additionalPropertyValues, LookupFieldOptions = lookupFieldOptions }; button.Clicked += (object sender, EventArgs eventArgs) => { ListSelectionPage selectionPage = new ListSelectionPage(lookupFieldOptions); selectionPage.OnSimpleListTapped += (s) => { button.Data = s; button.Text = s; dfLayout.ChangeField(dfLayoutLookupField.Name); }; selectionPage.OnDictionaryItemTapped += (id, s) => { button.Data = s; button.Text = s; button.ChosenID = id; dfLayout.ChangeField(dfLayoutLookupField.Name); }; Navigation.PushAsync(selectionPage); }; if (loadData.TryGetValue(dfLayoutLookupField.Name, out value)) { if (!string.IsNullOrWhiteSpace(value)) { button.Data = value; button.Text = value; } } if (loadRetainedForm) { if (RetainedResults.Results.TryGetValue(dfLayoutLookupField.Name, out value)) { button.Data = value; button.Text = value; } } if (isRequired) { button.BackgroundColor = isRequiredColor; } return button; } private View LoadDrawingTemplateLookupButton(Type lookuptype, DFLayoutLookupField dfLayoutLookupField, Dictionary lookupFieldOptions, DFLayoutControl element) { string value = ""; var columns = new Columns(x => x.Code, x => x.Document.ID); CoreTable table = new Client().Query(null, columns); Dictionary dictionary = new Dictionary(); foreach (var row in table.Rows) { List list = row.Values; if (list[0] != null && list[1] != null) dictionary.Add(list[0].ToString(), Guid.Parse(list[1].ToString())); } DataButtonControl button = new DataButtonControl() { Text = "Choose Option", }; button.Clicked += (object sender, EventArgs eventArgs) => { ListSelectionPage selectionPage = new ListSelectionPage(dictionary); selectionPage.OnSimpleListTapped += (s) => { button.Data = s; button.Text = s; dfLayout.ChangeField(dfLayoutLookupField.Name); }; Navigation.PushAsync(selectionPage); }; if (loadData.TryGetValue(dfLayoutLookupField.Name, out value)) { if (!string.IsNullOrWhiteSpace(value)) { button.Data = value; button.Text = value; } } if (loadRetainedForm) { if (RetainedResults.Results.TryGetValue(dfLayoutLookupField.Name, out value)) { button.Data = value; button.Text = value; } } if (isRequired) { button.BackgroundColor = isRequiredColor; } return button; } private IFilter ReturnFilter(DFLayoutLookupField dfLayoutLookupField, Type lookuptype) { var propertyFilter = dfLayoutLookupField.Properties.Filter; var filtertype = typeof(Filter<>).MakeGenericType(lookuptype); var deserialised = Serialization.Deserialize(filtertype, propertyFilter); IFilter filter = deserialised as IFilter; return filter; } private CoreTable ReturnJobStyleProducts(CoreTable table, IClient client, IColumns columns, ISortOrder sort) { CoreTable jobStyleTable = new Client().Query(new Filter(x => x.Job.ID).IsEqualTo(JobID), new Columns(x => x.Style.ID)); if (jobStyleTable.Rows.Any()) { Guid firstID = Guid.Parse(jobStyleTable.Rows.FirstOrDefault().Values[0].ToString()); var stylefilter = new Filter(x => x.ID).IsEqualTo(firstID); foreach (CoreRow jobStyleRow in jobStyleTable.Rows) { if (jobStyleRow != jobStyleTable.Rows.FirstOrDefault()) { stylefilter = stylefilter.Or(x => x.ID).IsEqualTo(Guid.Parse(jobStyleRow.Values[0].ToString())); } } table = client.Query(stylefilter, columns, sort); } return table; } private View LoadProductLookupPicker(View view, DFLayoutLookupField dfLayoutLookupField, string value) { FrameButton framebutton = new FrameButton(); if (loadData.TryGetValue(dfLayoutLookupField.Name, out value)) { framebutton.SetButtonText(value); framebutton.Data = value + "," + (App.Data.Products.Items.FirstOrDefault(x => x.Code == value)).ID.ToString(); //CoreTable productTable = new Client().Query(new Filter(x => x.Code).IsEqualTo(value), // new Columns(x => x.Image.ID)); //if (productTable.Rows.Any()) //{ // CoreTable imageTable1 = new Client().Query(new Filter(x => x.ID).IsEqualTo(Guid.Parse(productTable.Rows.First().Values[0].ToString())), // new Columns(x => x.Data)); // CoreRow docrow = imageTable1.Rows.FirstOrDefault(); // if (docrow != null) // { // byte[] data = docrow.Get(x => x.Data); // ImageSource src = ImageSource.FromStream(() => new MemoryStream(data)); // if (src != null) // { // framebutton.SetImage(src); // } // } //} } framebutton.OnFrameButtonClicked += (() => { ProductList2 productList = new ProductList2(App.Data.Products.Items.ToList(), true); productList.OnProductSelected += () => { framebutton.SetButtonText(productList.SelectedProduct.Code); framebutton.Data = productList.SelectedProduct.Code + "," + productList.SelectedProduct.ID.ToString(); //CoreTable imageTable = new Client().Query(new Filter(x => x.ID).IsEqualTo(productList.SelectedProduct.ImageID), // new Columns(x => x.Data)); //CoreRow docrow = imageTable.Rows.FirstOrDefault(); //if (docrow != null) //{ // byte[] data = docrow.Get(x => x.Data); // ImageSource src = ImageSource.FromStream(() => new MemoryStream(data)); // if (src != null) // { // framebutton.SetImage(src); // } //} dfLayout.ChangeField(dfLayoutLookupField.Name); }; Navigation.PushAsync(productList); }); view = framebutton; return view; } private Tuple LoadSignaturePad(DFLayoutControl element) { string value = ""; View view = null; DFLayoutSignaturePad dFLayoutSignaturePad = element as DFLayoutSignaturePad; var isrequired = dFLayoutSignaturePad.Properties.Required; if (loadData.TryGetValue(dFLayoutSignaturePad.Name, out value)) { if (!string.IsNullOrWhiteSpace(value)) { EmbeddedImageCapture embeddedImageCapture = new EmbeddedImageCapture(); byte[] data = Convert.FromBase64String(value); embeddedImageCapture.DataToImage(data); view = embeddedImageCapture; view.IsEnabled = false; } } else { SfSignaturePad signaturePad = new SfSignaturePad(); EmbeddedImageCapture hiddenEmbeddedImageCapture = new EmbeddedImageCapture() { HeightRequest = 200, IsVisible = false, IsEnabled = false }; if (isrequired) signaturePad.BackgroundColor = isRequiredColor; signaturePad.MinimumHeightRequest = 200; signaturePad.MinimumStrokeWidth = 0.2; signaturePad.MaximumStrokeWidth = 17; Button clearButton = new Button() { Text = "Clear", HorizontalOptions = LayoutOptions.FillAndExpand, VerticalOptions = LayoutOptions.End, Margin = 0, BackgroundColor = Color.FromHex("#15C7C1"), FontAttributes = FontAttributes.Bold, TextColor = Color.White, CornerRadius = 5, Padding = 1 }; clearButton.Clicked += (object sender, EventArgs e) => { signaturePad.IsVisible = true; hiddenEmbeddedImageCapture.IsVisible = false; useSavedSignatures.Remove(dFLayoutSignaturePad.Name); signaturePad.Clear(); }; Grid.SetColumn(clearButton, 2); Button signNowButton = new Button() { Text = "Apply Saved", HorizontalOptions = LayoutOptions.FillAndExpand, VerticalOptions = LayoutOptions.End, Margin = 0, BackgroundColor = Color.FromHex("#15C7C1"), FontAttributes = FontAttributes.Bold, TextColor = Color.White, CornerRadius = 5, Padding = 1 }; signNowButton.Clicked += (object sender, EventArgs e) => { if (Application.Current.Properties.ContainsKey("SavedSignature")) { Task.Run(() => { hiddenEmbeddedImageCapture.DataToImage((Application.Current.Properties["SavedSignature"]) as byte[]); }); Thread.Sleep(1000); signaturePad.IsVisible = false; hiddenEmbeddedImageCapture.IsVisible = true; if (!useSavedSignatures.Contains(dFLayoutSignaturePad.Name)) useSavedSignatures.Add(dFLayoutSignaturePad.Name); } }; Grid.SetColumn(signNowButton, 1); Button createSignatureButton = new Button() { Text = "Save New", HorizontalOptions = LayoutOptions.FillAndExpand, VerticalOptions = LayoutOptions.End, Margin = 0, BackgroundColor = Color.FromHex("#15C7C1"), FontAttributes = FontAttributes.Bold, TextColor = Color.White, CornerRadius = 5, Padding = 1 }; createSignatureButton.Clicked += (object sender, EventArgs e) => { SignatureSaver saver = new SignatureSaver(); saver.OnSignatureSaved += () => { Task.Run(() => { hiddenEmbeddedImageCapture.DataToImage((Application.Current.Properties["SavedSignature"]) as byte[]); }); Thread.Sleep(1000); signaturePad.IsVisible = false; hiddenEmbeddedImageCapture.IsVisible = true; if (!useSavedSignatures.Contains(dFLayoutSignaturePad.Name)) useSavedSignatures.Add(dFLayoutSignaturePad.Name); }; Navigation.PushAsync(saver); }; Grid.SetColumn(createSignatureButton, 0); Grid buttonsGrid = new Grid { Margin = 0, Padding = 0, VerticalOptions = LayoutOptions.End }; buttonsGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) }); buttonsGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) }); buttonsGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) }); buttonsGrid.Children.Add(createSignatureButton); buttonsGrid.Children.Add(signNowButton); buttonsGrid.Children.Add(clearButton); Grid grid = new Grid() { Margin = 0, Padding = 0 }; grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(200, GridUnitType.Absolute) }); Grid.SetRow(signaturePad, 0); Grid.SetRow(hiddenEmbeddedImageCapture, 0); grid.Children.Add(hiddenEmbeddedImageCapture); grid.Children.Add(signaturePad); grid.Children.Add(buttonsGrid); view = grid; } return new Tuple(view, isrequired); } private Tuple LoadEmbeddedImage(DFLayoutControl element) { string value = ""; bool disableLibrary = false; DFLayoutEmbeddedImage dfLayoutEmbeddedImage = element as DFLayoutEmbeddedImage; try { disableLibrary = dfLayoutEmbeddedImage.Properties.DisableLibrary; } catch { } EmbeddedImageCapture embeddedImageCapture = new EmbeddedImageCapture(disableLibrary); if (disableLibrary) embeddedImageCapture.LibraryButton.BackgroundColor = Color.LightGray; if (loadData.TryGetValue(dfLayoutEmbeddedImage.Name, out value)) { if (!string.IsNullOrWhiteSpace(value)) { byte[] data = Convert.FromBase64String(value); embeddedImageCapture.DataToImage(data); } } else { if (dfLayoutEmbeddedImage.Properties.Required) { embeddedImageCapture.CameraButton.BackgroundColor = isRequiredColor; embeddedImageCapture.CameraButton.BorderWidth = 1; embeddedImageCapture.CameraButton.BorderColor = Color.Black; if (!disableLibrary) { embeddedImageCapture.LibraryButton.BackgroundColor = isRequiredColor; embeddedImageCapture.LibraryButton.BorderWidth = 1; embeddedImageCapture.LibraryButton.BorderColor = Color.Black; } } } return new Tuple(embeddedImageCapture, dfLayoutEmbeddedImage.Properties.Required); } private Tuple LoadVideoField(DFLayoutControl element) { string value = ""; bool disableLibrary = false; DFLayoutVideoField vidField = element as DFLayoutVideoField; EmbeddedImageCapture embeddedImageCapture = new EmbeddedImageCapture(false, true); embeddedImageCapture.VideoQuality = vidField.Properties.Quality == DFLayoutVideoFieldProperties.VideoQuality.Low ? Plugin.Media.Abstractions.VideoQuality.Low : vidField.Properties.Quality == DFLayoutVideoFieldProperties.VideoQuality.Medium ? Plugin.Media.Abstractions.VideoQuality.Medium : vidField.Properties.Quality == DFLayoutVideoFieldProperties.VideoQuality.High ? Plugin.Media.Abstractions.VideoQuality.High : vidField.Properties.Quality == DFLayoutVideoFieldProperties.VideoQuality.Default ? Plugin.Media.Abstractions.VideoQuality.Medium : Plugin.Media.Abstractions.VideoQuality.Medium; embeddedImageCapture.VideoLength = vidField.Properties.MaximumVideoLength == 0 ? new TimeSpan(0, 0, 20) : new TimeSpan(0, 0, vidField.Properties.MaximumVideoLength); if (loadData.TryGetValue(vidField.Name, out value)) { byte[] data = Convert.FromBase64String(value); } else { if (vidField.Properties.Required) { embeddedImageCapture.CameraButton.BackgroundColor = isRequiredColor; embeddedImageCapture.CameraButton.BorderWidth = 1; embeddedImageCapture.CameraButton.BorderColor = Color.Black; if (!disableLibrary) { embeddedImageCapture.LibraryButton.BackgroundColor = isRequiredColor; embeddedImageCapture.LibraryButton.BorderWidth = 1; embeddedImageCapture.LibraryButton.BorderColor = Color.Black; } } } return new Tuple(embeddedImageCapture, vidField.Properties.Required); } private Tuple LoadMultiImage(DFLayoutControl element) { string value = ""; bool disableLibrary = false; DFLayoutMultiImage dfLayoutMultiEmbeddedImage = element as DFLayoutMultiImage; try { disableLibrary = dfLayoutMultiEmbeddedImage.Properties.DisableLibrary; } catch { } MultiImageCapture multiImageCapture = new MultiImageCapture(disableLibrary); if (loadData.TryGetValue(dfLayoutMultiEmbeddedImage.Name, out value)) { List values = Serialization.Deserialize>(value); foreach (string s in values) { byte[] data = Convert.FromBase64String(s); multiImageCapture.DataToImage(data); } } return new Tuple(multiImageCapture, dfLayoutMultiEmbeddedImage.Properties.Required); } private Tuple LoadMultiSignaturePad(DFLayoutControl element) { string value = ""; DFLayoutMultiSignaturePad dfLayoutMultiSignaturePad = element as DFLayoutMultiSignaturePad; DataButtonControl button = new DataButtonControl { Text = "Add Signatures", }; if (loadData.TryGetValue(dfLayoutMultiSignaturePad.Name, out value)) { button.Data = value; } MultiSignaturePad multiSignaturePad = new MultiSignaturePad(button.Data); multiSignaturePad.OnMultiSignatureSaved += (result) => { button.Data = result; }; button.Clicked += (object sender, EventArgs e) => { Navigation.PushAsync(multiSignaturePad); }; return new Tuple(button, dfLayoutMultiSignaturePad.Properties.Required); } private Tuple LoadAddTaskField(DFLayoutControl element) { string value = ""; DFLayoutAddTaskField field = element as DFLayoutAddTaskField; DFCreateTaskView taskView = new DFCreateTaskView(); taskView.OnAddTaskButtonClicked += () => { AddEditTask addEditTask = new AddEditTask(Guid.Empty, "New task from Digital Form"); if (field.Properties.TaskType != null) { addEditTask.kanban.Type.ID = field.Properties.TaskType.ID; try { addEditTask.kanban.Type.Description = new Client().Query (new Filter(x => x.ID).IsEqualTo(field.Properties.TaskType.ID), new Columns(x => x.Description)).Rows.FirstOrDefault().Values[0].ToString(); } catch { } addEditTask.UpdateScreen(true); } addEditTask.OnTaskSaved += (taskNumber) => { taskView.DisableButton(); taskView.TaskNumber = taskNumber.ToString(); }; Navigation.PushAsync(addEditTask); }; if (loadData.TryGetValue(field.Name, out value)) { taskView.TaskNumber = value; taskView.DisableButton(); } return new Tuple(taskView, field.Properties.Required); } private void FormatAndAddView(View view, DFLayoutControl element, bool isrequired) { try { if (element is DFLayoutField) { pairs[element as DFLayoutField] = view; if (isSecure || readOnly || !string.IsNullOrWhiteSpace((element as DFLayoutField).GetPropertyValue("Expression"))) view.IsEnabled = false; Frame frame = new Frame { Content = view, BorderColor = Color.FromHex("#15C7C1"), BackgroundColor = Color.Default, CornerRadius = 5, Padding = 2, HasShadow = false, }; if (readOnly || isSecure) { frame.BorderColor = Color.Gray; frame.BackgroundColor = Color.LightGray; frame.VerticalOptions = LayoutOptions.FillAndExpand; frame.MinimumHeightRequest = 60; } if (isrequired) { frame.BackgroundColor = isRequiredColor; } view = frame; } if (element.Row > 0) SetRow(view, element.Row - 1); //rows and columns coming in from the desktop designer start from 1, not 0 (most of the time??) else if (element.Row == 0) SetRow(view, dfLayout.RowHeights.Count + 1); if (element.RowSpan > 0) SetRowSpan(view, element.RowSpan); else if (element.RowSpan == 0) SetRowSpan(view, 1); if (element.Column > 0) SetColumn(view, element.Column - 1); //rows and columns coming in from the desktop designer start from 1, not 0 (most of the time??) if (element.ColumnSpan > 0) SetColumnSpan(view, element.ColumnSpan); if (element.ColumnSpan > 1) { view.HorizontalOptions = LayoutOptions.FillAndExpand; if (view is Label) { view.HorizontalOptions = LayoutOptions.CenterAndExpand; Label lblView = view as Label; lblView.HorizontalTextAlignment = TextAlignment.Center; view = lblView; } } else if (element.ColumnSpan == 0) SetColumnSpan(view, 1); view.SetValue(Grid.MarginProperty, 0.01); if (element is DFLayoutSignaturePad) view.Margin = new Thickness(25, 0, 25, 0); Device.BeginInvokeOnMainThread(() => { Children.Add(view); }); if (element is DFLayoutHeader) if ((element as DFLayoutHeader).Collapsed) headersToCollapse.Add(view as DigitalFormsHeader); } catch { } } #endregion #region Save public void SaveData(bool saveForLater) { try { results.Clear(); propertyResults.Clear(); isRequiredEmpty = false; isRequiredMessage = ""; foreach (DFLayoutField field in pairs.Keys) { View view = pairs[field]; String userInput = AddResultsToDictionary(field, view); if (isRequiredEmpty) { if (!saveForLater) return; } AddPropertyToDictionary(field, userInput); } UpdateInstanceAndModel(saveForLater); } catch (Exception ex) { } } #region Adding Results to dictionaries private string AddResultsToDictionary(DFLayoutField field, View view, bool AddToDictionary = true) //"results" dictionary is the data to be saved in Form.Data { string userInput = ""; if (field is DFLayoutStringField || field is DFLayoutIntegerField || field is DFLayoutDoubleField) { if (field is DFLayoutStringField && (field as DFLayoutStringField).Properties.PopupEditor) userInput = (view as DataButtonControl).Data; else userInput = (view as Editor).Text; } else if (field is DFLayoutBooleanField) { if ((view as CustomBoolean).ValueChanged) { userInput = (view as CustomBoolean).Value.ToString(); } } else if (field is DFLayoutDateField) { userInput = ((view as DatePicker).Date).ToString("dd-MM-yyyy"); } else if (field is DFLayoutTimeField) { userInput = ((view as TimePicker).Time).ToString("c"); } else if (field is DFLayoutOptionField) { userInput = GetStringFromOptionField(view); } else if (field is DFLayoutLookupField) { if (view is DataButtonControl) { var button = view as DataButtonControl; userInput = FindIDForDesignLookupField(button); //userinput is used to set guid later on for properties, but will not get added to form data only for lookupfields results.Add(field.Name, button.Data); if (RetainedResults.IsFormRetained) if ((field as DFLayoutLookupField).Properties.Retain) RetainedResults.Results.Add(field.Name, button.Data); } else if (view is FrameButton) //currently only used for Products - we already have the Product.ID in Framebutton.Data (saved as Code,ID) { FrameButton framebutton = view as FrameButton; if (!string.IsNullOrWhiteSpace(framebutton.Data)) { string[] buttonData = framebutton.Data.Split(','); if (AddToDictionary) results.Add(field.Name, buttonData[0]); //[0] is product.code userInput = buttonData[1]; //[1] is product id as string if (RetainedResults.IsFormRetained) if ((field as DFLayoutLookupField).Properties.Retain) RetainedResults.Results.Add(field.Name, buttonData[0]); } } } else if (field is DFLayoutSignaturePad) { string value = ""; var grid = view as Grid; var signaturePad = grid.Children.OfType().FirstOrDefault(); DFLayoutSignaturePad dFLayoutSignaturePad = field as DFLayoutSignaturePad; if (loadData.TryGetValue(dFLayoutSignaturePad.Name, out value)) { userInput = value; } else { if (useSavedSignatures.Contains(dFLayoutSignaturePad.Name)) { ImageSource src = ImageSource.FromStream(() => new MemoryStream((Application.Current.Properties["SavedSignature"]) as byte[])); userInput = ImageSourceToBase64(src); } else { signaturePad.Save(); if (signaturePad.ImageSource != null) { userInput = ImageSourceToBase64(signaturePad.ImageSource); } } } } else if (field is DFLayoutEmbeddedImage) { var embeddedImage = view as EmbeddedImageCapture; if (embeddedImage.Image.Source != null) { try { userInput = ImageSourceToBase64(embeddedImage.Image.Source); } catch (Exception e) { userInput = ""; } } } else if (field is DFLayoutVideoField) { var embeddedImage = view as EmbeddedImageCapture; if (embeddedImage.bytes != null) { if (embeddedImage.bytes.Length > 0) { try { userInput = BytesToBase64(embeddedImage.bytes); } catch (Exception e) { userInput = ""; } } } } else if (field is DFLayoutMultiImage) { var multiImage = view as MultiImageCapture; if (multiImage.Images.Count > 0) { try { userInput = ImagesToBase64(multiImage.Images); } catch (Exception e) { userInput = ""; } } } else if (field is DFLayoutAddTaskField) { var addTaskButton = view as DFCreateTaskView; if (!string.IsNullOrWhiteSpace(addTaskButton.TaskNumber)) { userInput = addTaskButton.TaskNumber; } } else if (field is DFLayoutMultiSignaturePad) { var databutton = view as DataButtonControl; if (!string.IsNullOrWhiteSpace(databutton.Data)) userInput = databutton.Data; } //add the field name and input to 'results' dictionary for processing outside of QAFormViewer if (!String.IsNullOrWhiteSpace(userInput) && AddToDictionary) { if (field is DFLayoutLookupField) { /*do nothing as results have already been added*/ } else { try { results.Add(field.Name, userInput); } catch (Exception e) { errors.Add(e.Message); } if (RetainedResults.IsFormRetained) { AddRetainedToDictionary(field, userInput); } } } else CheckRequired(field); return userInput; } private void AddPropertyToDictionary(DFLayoutField field, String userInput) { if (!string.IsNullOrWhiteSpace(userInput)) { try { string property = ""; if (field is DFLayoutStringField) property = (field as DFLayoutStringField).Properties.Property; else if (field is DFLayoutIntegerField) property = (field as DFLayoutIntegerField).Properties.Property; else if (field is DFLayoutDoubleField) property = (field as DFLayoutDoubleField).Properties.Property; else if (field is DFLayoutBooleanField) property = (field as DFLayoutBooleanField).Properties.Property; else if (field is DFLayoutDateField) property = (field as DFLayoutDateField).Properties.Property; else if (field is DFLayoutTimeField) property = (field as DFLayoutTimeField).Properties.Property; else if (field is DFLayoutOptionField) property = (field as DFLayoutOptionField).Properties.Property; else if (field is DFLayoutLookupField) property = (field as DFLayoutLookupField).Properties.Property; //'propertyResults' dictionary for processing outside of QAFormViewer if (!string.IsNullOrWhiteSpace(property)) propertyResults.Add(property, userInput); } catch (Exception e) { errors.Add(e.Message); return; } } } private async void AddRetainedToDictionary(DFLayoutField field, string userInput) { await Task.Run(() => { try { if (field is DFLayoutStringField) { if ((field as DFLayoutStringField).Properties.Retain) RetainedResults.Results.Add(field.Name, userInput); } else if (field is DFLayoutIntegerField) { if ((field as DFLayoutIntegerField).Properties.Retain) RetainedResults.Results.Add(field.Name, userInput); } else if (field is DFLayoutDoubleField) { if ((field as DFLayoutDoubleField).Properties.Retain) RetainedResults.Results.Add(field.Name, userInput); } else if (field is DFLayoutBooleanField) { if ((field as DFLayoutBooleanField).Properties.Retain) RetainedResults.Results.Add(field.Name, userInput); } else if (field is DFLayoutDateField) { if ((field as DFLayoutDateField).Properties.Retain) RetainedResults.Results.Add(field.Name, userInput); } else if (field is DFLayoutTimeField) { if ((field as DFLayoutTimeField).Properties.Retain) RetainedResults.Results.Add(field.Name, userInput); } else if (field is DFLayoutOptionField) { if ((field as DFLayoutOptionField).Properties.Retain) RetainedResults.Results.Add(field.Name, userInput); } } catch (Exception e) { errors.Add("Retained results error: " + e.Message); } }); } #endregion #region Checks / Custom methods private void CheckRequired(DFLayoutField field) { if (field is DFLayoutStringField) { if ((field as DFLayoutStringField).Properties.Required) { isRequiredEmpty = true; isRequiredMessage = (field as DFLayoutStringField).Description; } } else if (field is DFLayoutIntegerField) { if ((field as DFLayoutIntegerField).Properties.Required) { isRequiredEmpty = true; isRequiredMessage = (field as DFLayoutIntegerField).Description; } } else if (field is DFLayoutDoubleField) { if ((field as DFLayoutDoubleField).Properties.Required) { { isRequiredEmpty = true; isRequiredMessage = (field as DFLayoutIntegerField).Description; } } } else if (field is DFLayoutBooleanField) { if ((field as DFLayoutBooleanField).Properties.Required) { { isRequiredEmpty = true; isRequiredMessage = (field as DFLayoutBooleanField).Description; } } } else if (field is DFLayoutDateField) { if ((field as DFLayoutDateField).Properties.Required) { { isRequiredEmpty = true; isRequiredMessage = (field as DFLayoutDateField).Description; } } } else if (field is DFLayoutTimeField) { if ((field as DFLayoutTimeField).Properties.Required) { { isRequiredEmpty = true; isRequiredMessage = (field as DFLayoutTimeField).Description; } } } else if (field is DFLayoutOptionField) { if ((field as DFLayoutOptionField).Properties.Required) { { isRequiredEmpty = true; isRequiredMessage = (field as DFLayoutOptionField).Description; } } } else if (field is DFLayoutLookupField) { if ((field as DFLayoutLookupField).Properties.Required) { { isRequiredEmpty = true; isRequiredMessage = (field as DFLayoutLookupField).Description; } } } else if (field is DFLayoutSignaturePad) { if ((field as DFLayoutSignaturePad).Properties.Required) { { isRequiredEmpty = true; isRequiredMessage = (field as DFLayoutSignaturePad).Description; } } } else if (field is DFLayoutEmbeddedImage) { if ((field as DFLayoutEmbeddedImage).Properties.Required) { { isRequiredEmpty = true; isRequiredMessage = (field as DFLayoutEmbeddedImage).Description; } } } else if (field is DFLayoutMultiImage) { if ((field as DFLayoutMultiImage).Properties.Required) { { isRequiredEmpty = true; isRequiredMessage = (field as DFLayoutMultiImage).Description; } } } else if (field is DFLayoutMultiSignaturePad) { if ((field as DFLayoutMultiSignaturePad).Properties.Required) { { isRequiredEmpty = true; isRequiredMessage = (field as DFLayoutMultiSignaturePad).Description; } } } } private string ImagesToBase64(List images) { List strings = new List(); foreach (Image image in images) { strings.Add(ImageSourceToBase64(image.Source)); } return Serialization.Serialize(strings); } private string ImageSourceToBase64(ImageSource source) { StreamImageSource streamImageSource = (StreamImageSource)source; System.Threading.CancellationToken cancellationToken = System.Threading.CancellationToken.None; Task task = streamImageSource.Stream(cancellationToken); Stream stream = task.Result; byte[] bytes = new byte[stream.Length]; stream.Read(bytes, 0, bytes.Length); string s = Convert.ToBase64String(bytes, Base64FormattingOptions.InsertLineBreaks); return s; } private string BytesToBase64(byte[] bytes) { string s = Convert.ToBase64String(bytes, Base64FormattingOptions.InsertLineBreaks); return s; } private string FindIDForDesignLookupField(DataButtonControl button) { try { string userInputValue = button.Data; string guidString = ""; if (userInputValue != nullOrInvalidType) { foreach (KeyValuePair> pair in dfLayoutLookupFieldLookupOptions) { foreach (KeyValuePair innerPair in pair.Value) { if (innerPair.Value == userInputValue) { guidString = innerPair.Key.ToString(); } } } } return guidString; } catch { return ""; } } #endregion #region Save Completion //point of determination for whether or not QA form gets completed or saved for later private void UpdateInstanceAndModel(bool saveForLater) { if (results.Count != 0) { if (!saveForLater) { CompleteForm(); } model.Instance.FormCompletedBy.ID = userID; if (digitalFormID != Guid.Empty) model.Instance.Form.ID = digitalFormID; DigitalForm.SerializeFormData(model.Instance, QueryVariables(model.Instance), results.ToDictionary(x => x.Key, x => x.Value as object)); FormData = model.Instance.FormData; if (model.Instance.FormStarted == DateTime.MinValue) { model.Instance.FormStarted = timeStarted; } TimeSpan span = DateTime.Now - timeStarted; model.Instance.FormOpen = model.Instance.FormOpen + span; model.Update(null); } } public List QueryVariables(IDigitalFormInstance form) { List variables = new List(); var table = new Client().Query( new Filter(x => x.Form.ID).IsEqualTo(form.Form.ID), new Columns(x => x.Code, x => x.Parameters, x => x.Description, x => x.VariableType), null ); foreach (CoreRow coreRow in table.Rows) { var variable = coreRow.ToObject(); variables.Add(variable); } return variables; } private void CompleteForm() { model.Instance.FormCompleted = DateTime.Now; FormCompleted = model.Instance.FormCompleted; model.Instance.Location.Longitude = location.Longitude; model.Instance.Location.Latitude = location.Latitude; model.Instance.Location.Timestamp = model.Instance.FormCompleted; } #endregion #endregion #region Expressions public object GetFieldValue(string field) { try { Tuple tuple = FindView(field); return GetValueFromView(tuple.Item1, tuple.Item2); } catch { return ""; } } public void SetFieldValue(string field, object value) { try { Tuple tuple = FindView(field); SetValueOfView(tuple.Item1, tuple.Item2, value); } catch { } } private void SetValueOfView(DFLayoutField field, View view, object value) { if (field is DFLayoutBooleanField) (view as CustomBoolean).Value = (bool)value; else if (field is DFLayoutStringField || field is DFLayoutIntegerField || field is DFLayoutDoubleField) { if (field is DFLayoutStringField && (field as DFLayoutStringField).Properties.PopupEditor) { (view as DataButtonControl).Data = value.ToString(); (view as DataButtonControl).Text = value.ToString(); } else (view as Editor).Text = value.ToString(); } else if (field is DFLayoutDateField) (view as DatePicker).Date = (DateTime)(value as DateTime?); else if (field is DFLayoutDateTimeField) (view as TimePicker).Time = (TimeSpan)(value as TimeSpan?); else if (field is DFLayoutOptionField) AssignPickerOption(view, field as DFLayoutOptionField, value as string); else if (field is DFLayoutLookupField) AssignLookupOption(view, value as string); else if (field is DFLayoutEmbeddedImage) AssignImage(view, value as byte[]); } private void AssignImage(View view, byte[] bytes) { var imageCapture = view as EmbeddedImageCapture; imageCapture.DataToImage(bytes); } private void AssignLookupOption(View view, string value) { if (view is DataButtonControl) { (view as DataButtonControl).Text = value; (view as DataButtonControl).Data = value; } else if (view is FrameButton) //currently only used for Products - we already have the Product.ID in Framebutton.Data (saved as Code,ID) { (view as FrameButton).SetButtonText(value); (view as FrameButton).Data = value + "," + Guid.Empty.ToString(); } } private Tuple FindView(string field) { DFLayoutField dflayoutfield = pairs.Keys.FirstOrDefault(x => x.Name == field); View view = pairs[dflayoutfield]; return new Tuple(dflayoutfield, view); } private void AssignPickerOption(View view, DFLayoutOptionField field, string value) { string s = field.Properties.Options; string[] substrings = s.Split(','); var optionList = substrings.ToList(); if (Device.RuntimePlatform == Device.iOS) { var iOSPicker = view as CustomPickeriOS; iOSPicker.SelectedIndex = optionList.IndexOf(value); } else { var picker = view as Picker; picker.SelectedIndex = optionList.IndexOf(value); } } private object GetValueFromView(DFLayoutField field, View view) { if (field is DFLayoutBooleanField) return (view as CustomBoolean).Value; if (field is DFLayoutStringField) { if ((field as DFLayoutStringField).Properties.PopupEditor) return (view as DataButtonControl).Data; else return (view as Editor).Text; } else if (field is DFLayoutIntegerField) return int.Parse((view as Editor).Text); else if (field is DFLayoutDoubleField) return double.Parse((view as Editor).Text); else if (field is DFLayoutDateField) return (view as DatePicker).Date; else if (field is DFLayoutDateTimeField) return (view as TimePicker).Time; else if (field is DFLayoutOptionField) return GetStringFromOptionField(view); else if (field is DFLayoutLookupField) return GetStringFromLookupField(view); else if (field is DFLayoutSignaturePad) return GetByteArrayFromSignaturePad(view, field.Name); else if (field is DFLayoutEmbeddedImage) return GetByteArrayFromEmbeddedImage(view); else if (field is DFLayoutMultiImage) return GetByteArrayListFromMultiImage(view); else return ""; } private object GetByteArrayListFromMultiImage(View view) { List list = new List(); var multiImage = view as MultiImageCapture; if (multiImage.Images.Count > 0) { foreach (Image image in multiImage.Images) { string base64 = ImageSourceToBase64(image.Source); list.Add(Convert.FromBase64String(base64)); } } return list; } private object GetByteArrayFromEmbeddedImage(View view) { var embeddedImage = view as EmbeddedImageCapture; if (embeddedImage.Image.Source != null) { string base64 = ImageSourceToBase64(embeddedImage.Image.Source); return Convert.FromBase64String(base64); } else return null; } private byte[] GetByteArrayFromSignaturePad(View view, string name) { var grid = view as Grid; var signaturePad = grid.Children.OfType().FirstOrDefault(); if (useSavedSignatures.Contains(name)) { return Application.Current.Properties["SavedSignature"] as byte[]; } else { signaturePad.Save(); if (signaturePad.ImageSource != null) { string base64 = ImageSourceToBase64(signaturePad.ImageSource); return Convert.FromBase64String(base64); } else return null; } } private object GetStringFromLookupField(View view) { string value = ""; if (view is DataButtonControl) { var button = view as DataButtonControl; value = FindIDForDesignLookupField(button); //userinput is used to set guid later on for properties, but will not get added to form data only for lookupfields } else if (view is FrameButton) //currently only used for Products - we already have the Product.ID in Framebutton.Data (saved as Code,ID) { FrameButton framebutton = view as FrameButton; if (!string.IsNullOrWhiteSpace(framebutton.Data)) { string[] buttonData = framebutton.Data.Split(','); value = buttonData[1]; //[1] is product id as string } } return value; } private string GetStringFromOptionField(View view) { if (Device.RuntimePlatform == Device.iOS) { var iOSPicker = view as CustomPickeriOS; if (iOSPicker.SelectedIndex != -1) { return iOSPicker.SelectedItem.ToString(); } else return ""; } else { var picker = view as Picker; if (picker.SelectedIndex != -1) { return picker.SelectedItem.ToString(); } else return ""; } } public object GetFieldData(string fieldName, string dataField) { Tuple tuple = FindView(fieldName); try { if (tuple.Item1 is DFLayoutLookupField) { DFLayoutLookupField field = tuple.Item1 as DFLayoutLookupField; string type = field.Properties.LookupType; Type lookuptype = CoreUtils.GetEntityOrNull(type); if (lookuptype == typeof(Product)) { var framebutton = tuple.Item2 as FrameButton; string[] buttonData = framebutton.Data.Split(','); string id = buttonData[1]; //[1] is product id as string CoreTable table = new Client().Query(new Filter(x => x.ID).IsEqualTo(Guid.Parse(id)), new Columns(x => x.Image.ID)); if (table.Rows.Any()) { Guid returnid = table.Rows.FirstOrDefault().Get(x => x.Image.ID); return returnid; } else return null; } else { var button = tuple.Item2 as DataButtonControl; Dictionary dict = button.ExtraData[button.ChosenID]; return dict[dataField]; } } else return null; } catch { return null; } } public void SetFieldColour(string field, System.Drawing.Color? colour = null) { if (colour != null) { try { System.Drawing.Color color = (System.Drawing.Color)colour; FindView(field).Item2.BackgroundColor = Color.FromRgba( Convert.ToDouble(color.R), Convert.ToDouble(color.G), Convert.ToDouble(color.B), Convert.ToDouble(color.A)); } catch { } } } #endregion } }