/// <summary> /// Initializes a new instance of the <see cref="SensusUI.ScriptRunnerPage"/> class. /// </summary> /// <param name="scriptRunner">Script runner to display.</param> public ScriptRunnerPage(ScriptRunner scriptRunner) { Title = "Script"; StackLayout contentLayout = new StackLayout { Orientation = StackOrientation.Vertical, VerticalOptions = LayoutOptions.FillAndExpand }; foreach (StackLayout stack in UiProperty.GetPropertyStacks(scriptRunner)) contentLayout.Children.Add(stack); Button editPromptsButton = new Button { Text = "Edit Prompts", FontSize = 20, HorizontalOptions = LayoutOptions.FillAndExpand }; editPromptsButton.Clicked += async (o, e) => { await Navigation.PushAsync(new PromptsPage(scriptRunner.Script.Prompts)); }; contentLayout.Children.Add(editPromptsButton); Button editTriggersButton = new Button { Text = "Edit Triggers", FontSize = 20, HorizontalOptions = LayoutOptions.FillAndExpand }; editTriggersButton.Clicked += async (o, e) => { await Navigation.PushAsync(new ScriptTriggersPage(scriptRunner)); }; contentLayout.Children.Add(editTriggersButton); Content = new ScrollView { Content = contentLayout }; }
/// <summary> /// Initializes a new instance of the <see cref="SensusUI.ScriptTriggersPage"/> class. /// </summary> /// <param name="scriptRunner">Script runner to display.</param> public ScriptTriggersPage(ScriptRunner scriptRunner) { Title = "Script Triggers"; ListView triggerList = new ListView(); triggerList.ItemTemplate = new DataTemplate(typeof(TextCell)); triggerList.ItemTemplate.SetBinding(TextCell.TextProperty, new Binding(".", stringFormat: "{0}")); triggerList.ItemsSource = scriptRunner.Triggers; triggerList.ItemTapped += async (o, e) => { if (triggerList.SelectedItem == null) return; SensusService.Probes.User.Trigger selectedTrigger = triggerList.SelectedItem as SensusService.Probes.User.Trigger; string selectedAction = await DisplayActionSheet(selectedTrigger.ToString(), "Cancel", null, "Delete"); if (selectedAction == "Delete") { if (await DisplayAlert("Confirm Delete", "Are you sure you want to delete the selected trigger?", "Yes", "Cancel")) { scriptRunner.Triggers.Remove(selectedTrigger); triggerList.SelectedItem = null; // must reset this, since it isn't reset automatically } } }; Content = triggerList; ToolbarItems.Add(new ToolbarItem(null, "plus.png", async () => { if (scriptRunner.Probe.Protocol.Probes.Where(p => p != scriptRunner.Probe && p.Enabled).Count() > 0) await Navigation.PushAsync(new AddScriptTriggerPage(scriptRunner)); else SensusServiceHelper.Get().FlashNotificationAsync("You must enable other probes before adding triggers."); })); }
/// <summary> /// Initializes a new instance of the <see cref="SensusUI.AddScriptTriggerPage"/> class. /// </summary> /// <param name="scriptRunner">Script runner to add trigger to.</param> public AddScriptTriggerPage(ScriptRunner scriptRunner) { _scriptRunner = scriptRunner; Title = "Add Trigger"; List<Probe> enabledProbes = _scriptRunner.Probe.Protocol.Probes.Where(p => p != _scriptRunner.Probe && p.Enabled).ToList(); if (enabledProbes.Count == 0) { Content = new Label { Text = "No enabled probes. Please enable them before creating triggers.", FontSize = 20 }; return; } StackLayout contentLayout = new StackLayout { Orientation = StackOrientation.Vertical, VerticalOptions = LayoutOptions.FillAndExpand }; Label probeLabel = new Label { Text = "Probe:", FontSize = 20 }; Picker probePicker = new Picker { Title = "Select Probe", HorizontalOptions = LayoutOptions.FillAndExpand }; foreach (Probe enabledProbe in enabledProbes) probePicker.Items.Add(enabledProbe.DisplayName); contentLayout.Children.Add(new StackLayout { Orientation = StackOrientation.Horizontal, HorizontalOptions = LayoutOptions.FillAndExpand, Children = { probeLabel, probePicker } }); StackLayout triggerDefinitionLayout = new StackLayout { Orientation = StackOrientation.Vertical, VerticalOptions = LayoutOptions.FillAndExpand }; contentLayout.Children.Add(triggerDefinitionLayout); Switch changeSwitch = new Switch(); Switch regexSwitch = new Switch(); Switch fireRepeatedlySwitch = new Switch(); Switch ignoreFirstDatumSwitch = new Switch(); TimePicker startTimePicker = new TimePicker { HorizontalOptions = LayoutOptions.FillAndExpand }; TimePicker endTimePicker = new TimePicker { HorizontalOptions = LayoutOptions.FillAndExpand }; probePicker.SelectedIndexChanged += (o, e) => { _selectedProbe = null; _selectedDatumProperty = null; _conditionValue = null; triggerDefinitionLayout.Children.Clear(); if (probePicker.SelectedIndex < 0) return; _selectedProbe = enabledProbes[probePicker.SelectedIndex]; PropertyInfo[] datumProperties = _selectedProbe.DatumType.GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(p => p.GetCustomAttributes<ProbeTriggerProperty>().Count() > 0).ToArray(); if(datumProperties.Length == 0) return; #region datum property picker Label datumPropertyLabel = new Label { Text = "Property:", FontSize = 20 }; Picker datumPropertyPicker = new Picker { Title = "Select Datum Property", HorizontalOptions = LayoutOptions.FillAndExpand }; foreach (PropertyInfo datumProperty in datumProperties) { ProbeTriggerProperty triggerProperty = datumProperty.GetCustomAttributes<ProbeTriggerProperty>().First(); datumPropertyPicker.Items.Add(triggerProperty.Name ?? datumProperty.Name); } triggerDefinitionLayout.Children.Add(new StackLayout { Orientation = StackOrientation.Horizontal, HorizontalOptions = LayoutOptions.FillAndExpand, Children = { datumPropertyLabel, datumPropertyPicker } }); #endregion #region condition picker (same for all datum types) Label conditionLabel = new Label { Text = "Condition:", FontSize = 20 }; Picker conditionPicker = new Picker { Title = "Select Condition", HorizontalOptions = LayoutOptions.FillAndExpand }; TriggerValueCondition[] conditions = Enum.GetValues(typeof(TriggerValueCondition)) as TriggerValueCondition[]; foreach (TriggerValueCondition condition in conditions) conditionPicker.Items.Add(condition.ToString()); conditionPicker.SelectedIndexChanged += (oo, ee) => { if (conditionPicker.SelectedIndex < 0) return; _selectedCondition = conditions[conditionPicker.SelectedIndex]; }; triggerDefinitionLayout.Children.Add(new StackLayout { Orientation = StackOrientation.Horizontal, HorizontalOptions = LayoutOptions.FillAndExpand, Children = { conditionLabel, conditionPicker } }); #endregion #region condition value for comparison, based on selected datum property -- includes change calculation (for double datum) and regex (for string datum) StackLayout conditionValueStack = new StackLayout { Orientation = StackOrientation.Vertical, HorizontalOptions = LayoutOptions.FillAndExpand }; triggerDefinitionLayout.Children.Add(conditionValueStack); datumPropertyPicker.SelectedIndexChanged += (oo, ee) => { _selectedDatumProperty = null; _conditionValue = null; conditionValueStack.Children.Clear(); if (datumPropertyPicker.SelectedIndex < 0) return; _selectedDatumProperty = datumProperties[datumPropertyPicker.SelectedIndex]; ProbeTriggerProperty datumTriggerAttribute = _selectedDatumProperty.GetCustomAttribute<ProbeTriggerProperty>(); View conditionValueStackView = null; bool allowChangeCalculation = false; bool allowRegularExpression = false; if (datumTriggerAttribute is ListProbeTriggerProperty) { Picker conditionValuePicker = new Picker { Title = "Select Condition Value", HorizontalOptions = LayoutOptions.FillAndExpand }; object[] items = (datumTriggerAttribute as ListProbeTriggerProperty).Items; foreach (object item in items) conditionValuePicker.Items.Add(item.ToString()); conditionValuePicker.SelectedIndexChanged += (ooo, eee) => { if (conditionValuePicker.SelectedIndex < 0) return; _conditionValue = items[conditionValuePicker.SelectedIndex]; }; conditionValueStackView = conditionValuePicker; } else if (datumTriggerAttribute is NumberProbeTriggerProperty) { Entry entry = new Entry { Keyboard = Keyboard.Numeric, HorizontalOptions = LayoutOptions.FillAndExpand }; entry.TextChanged += (ooo, eee) => { double value; if (double.TryParse(eee.NewTextValue, out value)) _conditionValue = value; }; conditionValueStackView = entry; allowChangeCalculation = true; } else if (datumTriggerAttribute is TextProbeTriggerProperty) { Entry entry = new Entry { Keyboard = Keyboard.Default, HorizontalOptions = LayoutOptions.FillAndExpand }; entry.TextChanged += (ooo, eee) => _conditionValue = eee.NewTextValue; conditionValueStackView = entry; allowRegularExpression = true; } else if (datumTriggerAttribute is BooleanProbeTriggerProperty) { Switch booleanSwitch = new Switch(); booleanSwitch.Toggled += (ooo, eee) => _conditionValue = eee.Value; conditionValueStackView = booleanSwitch; } Label conditionValueStackLabel = new Label { Text = "Value:", FontSize = 20 }; conditionValueStack.Children.Add(new StackLayout { Orientation = StackOrientation.Horizontal, HorizontalOptions = LayoutOptions.FillAndExpand, Children = { conditionValueStackLabel, conditionValueStackView } }); #region change calculation if (allowChangeCalculation) { Label changeLabel = new Label { Text = "Change:", FontSize = 20 }; changeSwitch.IsToggled = false; conditionValueStack.Children.Add(new StackLayout { Orientation = StackOrientation.Horizontal, HorizontalOptions = LayoutOptions.FillAndExpand, Children = { changeLabel, changeSwitch } }); } #endregion #region regular expression if (allowRegularExpression) { Label regexLabel = new Label { Text = "Regular Expression:", FontSize = 20 }; regexSwitch.IsToggled = false; conditionValueStack.Children.Add(new StackLayout { Orientation = StackOrientation.Horizontal, HorizontalOptions = LayoutOptions.FillAndExpand, Children = { regexLabel, regexSwitch } }); } #endregion }; datumPropertyPicker.SelectedIndex = 0; #endregion #region fire repeatedly Label fireRepeatedlyLabel = new Label { Text = "Fire Repeatedly:", FontSize = 20 }; fireRepeatedlySwitch.IsToggled = false; triggerDefinitionLayout.Children.Add(new StackLayout { Orientation = StackOrientation.Horizontal, HorizontalOptions = LayoutOptions.FillAndExpand, Children = { fireRepeatedlyLabel, fireRepeatedlySwitch } }); #endregion #region ignore first datum Label ignoreFirstDatumLabel = new Label { Text = "Ignore First Datum:", FontSize = 20 }; ignoreFirstDatumSwitch.IsToggled = false; triggerDefinitionLayout.Children.Add(new StackLayout { Orientation = StackOrientation.Horizontal, HorizontalOptions = LayoutOptions.FillAndExpand, Children = { ignoreFirstDatumLabel, ignoreFirstDatumSwitch } }); #endregion #region start/end times Label startTimeLabel = new Label { Text = "Start Time:", FontSize = 20 }; startTimePicker.Time = new TimeSpan(8, 0, 0); triggerDefinitionLayout.Children.Add(new StackLayout { Orientation = StackOrientation.Horizontal, HorizontalOptions = LayoutOptions.FillAndExpand, Children = { startTimeLabel, startTimePicker } }); Label endTimeLabel = new Label { Text = "End Time:", FontSize = 20 }; endTimePicker.Time = new TimeSpan(21, 0, 0); triggerDefinitionLayout.Children.Add(new StackLayout { Orientation = StackOrientation.Horizontal, HorizontalOptions = LayoutOptions.FillAndExpand, Children = { endTimeLabel, endTimePicker } }); #endregion }; probePicker.SelectedIndex = 0; Button okButton = new Button { Text = "OK", FontSize = 20 }; okButton.Clicked += async (o, e) => { try { _scriptRunner.Triggers.Add(new SensusService.Probes.User.Trigger(_selectedProbe, _selectedDatumProperty, _selectedCondition, _conditionValue, changeSwitch.IsToggled, fireRepeatedlySwitch.IsToggled, regexSwitch.IsToggled, ignoreFirstDatumSwitch.IsToggled, startTimePicker.Time, endTimePicker.Time)); await Navigation.PopAsync(); } catch (Exception ex) { string message = "Failed to add trigger: " + ex.Message; UiBoundSensusServiceHelper.Get(true).FlashNotificationAsync(message); UiBoundSensusServiceHelper.Get(true).Logger.Log(message, LoggingLevel.Normal, GetType()); } }; contentLayout.Children.Add(okButton); Content = new ScrollView { Content = contentLayout }; }