2
0
mirror of https://github.com/9ParsonsB/Pulsar.git synced 2025-07-01 16:33:43 -04:00

Export version fixes (#83)

* Add file association for .eop, prompt for install dir

* Handle .eop or .aip file passed as arg.

* VS2022 version bump

* Filter neutron stars and black holes from fast spinning criteria.

* Adjustments for new "high value" check

* Refactor herald cache

* Fix element order and namespaces for voice moods.

* Add explicit .Stop() between audio player calls.

* Use nullsafe member access instead of skipping

* Don't queue up a title that's already queued.

* Improve body ordinal handling for explorer speech titles.

* Escape strings being inserted into xml

* Handle flip-flopping JSON type

* Converter for flip-flopping property type

* Use the converter

* Escape characters *before* we wrap it in xml.

* Give Eahlstan his clear button. :D

* Exclude all stars from fast rotation check.

* Close outstanding popup notifications on exit.

* TO DONE

* [Herald] Suppress duplicate notification titles for spoken notifications

If you have notifications from multiple plugins producing notifications with the same title in quick succession (ie. "Body A 1 e" from both Explorer and BioInsights), the title on successive notifications will not be spoken again to save the breath of our friendly Azure speakers.

* Doc update

* Remove unintended member hiding

* Fix export errors when exporting BioInsights data, cleanup

Discovered a couple issues with exporting BioInsights data resulting from using two different types of objects in the data grid; improved error handling as well.

Also cleaned up some old-style read all code.

* Add read-all on launch setting

* Updated framework xml

* Improve high-value body description text

Co-authored-by: Fred Kuipers <mr.fredk@gmail.com>
This commit is contained in:
Jonathan Miller
2022-05-21 13:00:47 -02:30
committed by GitHub
parent 921f3867fa
commit 8de34a141c
31 changed files with 495 additions and 216 deletions

View File

@ -8,7 +8,6 @@ namespace Observatory.NativeNotification
{
public class NativePopup
{
// TODO: This needs to be cleaned up when the app is closed.
private Dictionary<Guid, NotificationView> notifications;
public NativePopup()
@ -67,5 +66,13 @@ namespace Observatory.NativeNotification
});
}
}
public void CloseAll()
{
foreach (var notification in notifications)
{
notification.Value?.Close();
}
}
}
}

View File

@ -9,6 +9,15 @@ namespace Observatory
[STAThread]
static void Main(string[] args)
{
if (args.Length > 0 && System.IO.File.Exists(args[0]))
{
var fileInfo = new System.IO.FileInfo(args[0]);
if (fileInfo.Extension == ".eop" || fileInfo.Extension == ".zip")
System.IO.File.Copy(
fileInfo.FullName,
$"{AppDomain.CurrentDomain.BaseDirectory}{System.IO.Path.DirectorySeparatorChar}plugins{System.IO.Path.DirectorySeparatorChar}{fileInfo.Name}");
}
string version = System.Reflection.Assembly.GetEntryAssembly().GetName().Version.ToString();
try
{

View File

@ -170,5 +170,10 @@ namespace Observatory.PluginManagement
return folderLocation;
}
}
internal void Shutdown()
{
NativePopup.CloseAll();
}
}
}

View File

@ -34,6 +34,7 @@ namespace Observatory.PluginManagement
public readonly List<DataTable> pluginTables;
public readonly List<(IObservatoryWorker plugin, PluginStatus signed)> workerPlugins;
public readonly List<(IObservatoryNotifier plugin, PluginStatus signed)> notifyPlugins;
private readonly PluginCore core;
private PluginManager()
{
@ -48,7 +49,7 @@ namespace Observatory.PluginManagement
logMonitor.StatusUpdate += pluginHandler.OnStatusUpdate;
logMonitor.LogMonitorStateChanged += pluginHandler.OnLogMonitorStateChanged;
var core = new PluginCore();
core = new PluginCore();
List<IObservatoryPlugin> errorPlugins = new();
@ -346,6 +347,11 @@ namespace Observatory.PluginManagement
return err;
}
internal void Shutdown()
{
core.Shutdown();
}
private static void LoadPlaceholderPlugin(string dllPath, PluginStatus pluginStatus, List<(IObservatoryNotifier plugin, PluginStatus signed)> notifiers)
{
PlaceholderPlugin placeholder = new(new FileInfo(dllPath).Name);

View File

@ -262,5 +262,17 @@ namespace Observatory.Properties {
this["ExportFolder"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool StartReadAll {
get {
return ((bool)(this["StartReadAll"]));
}
set {
this["StartReadAll"] = value;
}
}
}
}

View File

@ -62,5 +62,8 @@
<Setting Name="ExportFolder" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
<Setting Name="StartReadAll" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
</Settings>
</SettingsFile>

View File

@ -21,6 +21,11 @@ namespace Observatory.UI
{
DataContext = new MainWindowViewModel(pluginManager)
};
desktop.MainWindow.Closing += (o, e) =>
{
pluginManager.Shutdown();
};
}
base.OnFrameworkInitializationCompleted();

View File

@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Observatory.UI.Models
namespace Observatory.UI.Models
{
public class NotificationModel
{

View File

@ -58,19 +58,16 @@ namespace Observatory.UI.ViewModels
tabs.Add(new CoreModel() { Name = "Core", UI = new BasicUIViewModel(new ObservableCollection<object>()) { UIType = Framework.PluginUI.UIType.Core } });
if (Properties.Core.Default.StartMonitor)
{
ToggleMonitor();
}
if (Properties.Core.Default.StartReadAll)
ReadAll();
}
public void ReadAll()
{
// TODO(fredjk_gh): remove.
SetWorkerReadAllState(true);
LogMonitor.GetInstance.ReadAllJournals();
// TODO(fredjk_gh): remove.
SetWorkerReadAllState(false);
}
public void ToggleMonitor()
@ -84,12 +81,7 @@ namespace Observatory.UI.ViewModels
}
else
{
// HACK: Find a better way of suppressing notifications when pre-reading.
// TODO(fredjk_gh): remove.
SetWorkerReadAllState(true);
logMonitor.Start();
// TODO(fredjk_gh): remove.
SetWorkerReadAllState(false);
ToggleButtonText = "Stop Monitor";
}
}
@ -117,100 +109,129 @@ namespace Observatory.UI.ViewModels
public async void ExportGrid()
{
var exportFolder = Properties.Core.Default.ExportFolder;
if (string.IsNullOrEmpty(exportFolder))
try
{
exportFolder = System.Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
}
var exportFolder = Properties.Core.Default.ExportFolder;
OpenFolderDialog openFolderDialog = new()
{
Directory = exportFolder
};
var application = (IClassicDesktopStyleApplicationLifetime)Avalonia.Application.Current.ApplicationLifetime;
var selectedFolder = await openFolderDialog.ShowAsync(application.MainWindow);
if (!string.IsNullOrEmpty(selectedFolder))
{
Properties.Core.Default.ExportFolder = selectedFolder;
Properties.Core.Default.Save();
exportFolder = selectedFolder;
foreach (var tab in tabs.Where(t => t.Name != "Core"))
if (string.IsNullOrEmpty(exportFolder))
{
var ui = (BasicUIViewModel)tab.UI;
List<object> selectedData;
bool specificallySelected = ui.SelectedItems?.Count > 1;
exportFolder = System.Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
}
if (specificallySelected)
OpenFolderDialog openFolderDialog = new()
{
Directory = exportFolder
};
var application = (IClassicDesktopStyleApplicationLifetime)Avalonia.Application.Current.ApplicationLifetime;
var selectedFolder = await openFolderDialog.ShowAsync(application.MainWindow);
if (!string.IsNullOrEmpty(selectedFolder))
{
Properties.Core.Default.ExportFolder = selectedFolder;
Properties.Core.Default.Save();
exportFolder = selectedFolder;
foreach (var tab in tabs.Where(t => t.Name != "Core"))
{
selectedData = new();
var ui = (BasicUIViewModel)tab.UI;
List<object> selectedData;
bool specificallySelected = ui.SelectedItems?.Count > 1;
foreach (var item in ui.SelectedItems)
selectedData.Add(item);
}
else
{
selectedData = ui.BasicUIGrid.ToList();
}
var columns = selectedData[0].GetType().GetProperties();
Dictionary<string, int> colSize = new();
Dictionary<string, List<string>> colContent = new();
foreach (var column in columns)
{
colSize.Add(column.Name, 0);
colContent.Add(column.Name, new());
}
var lineType = selectedData[0].GetType();
foreach (var line in selectedData)
{
foreach (var column in colContent)
if (specificallySelected)
{
var cellValue = lineType.GetProperty(column.Key).GetValue(line)?.ToString() ?? string.Empty;
column.Value.Add(cellValue);
if (colSize[column.Key] < cellValue.Length)
colSize[column.Key] = cellValue.Length;
selectedData = new();
foreach (var item in ui.SelectedItems)
selectedData.Add(item);
}
}
System.Text.StringBuilder exportData = new();
foreach (var colTitle in colContent.Keys)
{
if (colSize[colTitle] < colTitle.Length)
colSize[colTitle] = colTitle.Length;
exportData.Append(colTitle.PadRight(colSize[colTitle]) + " ");
}
exportData.AppendLine();
for (int i = 0; i < colContent.First().Value.Count; i++)
{
foreach(var column in colContent)
else
{
if (column.Value[i].Length > 0 && !char.IsNumber(column.Value[i][0]) && column.Value[i].Count(char.IsLetter) / (float)column.Value[i].Length > 0.25)
exportData.Append(column.Value[i].PadRight(colSize[column.Key]) + " ");
else
exportData.Append(column.Value[i].PadLeft(colSize[column.Key]) + " ");
selectedData = ui.BasicUIGrid.ToList();
}
var columns = selectedData[0].GetType().GetProperties();
Dictionary<string, int> colSize = new();
Dictionary<string, List<string>> colContent = new();
foreach (var column in columns)
{
colSize.Add(column.Name, 0);
colContent.Add(column.Name, new());
}
foreach (var line in selectedData)
{
var lineType = line.GetType(); // some plugins have different line types, so don't move this out of loop
foreach (var column in colContent)
{
var cellValue = lineType.GetProperty(column.Key)?.GetValue(line)?.ToString() ?? string.Empty;
column.Value.Add(cellValue);
if (colSize[column.Key] < cellValue.Length)
colSize[column.Key] = cellValue.Length;
}
}
System.Text.StringBuilder exportData = new();
foreach (var colTitle in colContent.Keys)
{
if (colSize[colTitle] < colTitle.Length)
colSize[colTitle] = colTitle.Length;
exportData.Append(colTitle.PadRight(colSize[colTitle]) + " ");
}
exportData.AppendLine();
for (int i = 0; i < colContent.First().Value.Count; i++)
{
foreach (var column in colContent)
{
if (column.Value[i].Length > 0 && !char.IsNumber(column.Value[i][0]) && column.Value[i].Count(char.IsLetter) / (float)column.Value[i].Length > 0.25)
exportData.Append(column.Value[i].PadRight(colSize[column.Key]) + " ");
else
exportData.Append(column.Value[i].PadLeft(colSize[column.Key]) + " ");
}
exportData.AppendLine();
}
string exportPath = $"{exportFolder}{System.IO.Path.DirectorySeparatorChar}Observatory Export - {DateTime.UtcNow:yyyyMMdd-HHmmss} - {tab.Name}.txt";
System.IO.File.WriteAllText(exportPath, exportData.ToString());
}
string exportPath = $"{exportFolder}{System.IO.Path.DirectorySeparatorChar}Observatory Export - {DateTime.UtcNow:yyyyMMdd-HHmmss} - {tab.Name}.txt";
System.IO.File.WriteAllText(exportPath, exportData.ToString());
}
}
catch (Exception e)
{
ObservatoryCore.LogError(e, "while exporting data");
ErrorReporter.ShowErrorPopup("Error encountered!",
"An error occurred while exporting; output may be missing or incomplete." + Environment.NewLine +
"Please check the error log (found in your Documents folder) for more details and visit our discord to report it.");
}
}
public void ClearGrid()
{
foreach (var tab in tabs.Where(t => t.Name != "Core"))
{
var ui = (BasicUIViewModel)tab.UI;
var rowTemplate = ui.BasicUIGrid.First();
foreach (var property in rowTemplate.GetType().GetProperties())
{
property.SetValue(rowTemplate, null);
}
ui.BasicUIGrid.Clear();
ui.BasicUIGrid.Add(rowTemplate);
// For some reason UIType's change event will properly
// redraw the grid, not BasicUIGrid's.
ui.RaisePropertyChanged(nameof(ui.UIType));
}
}
public string ToggleButtonText
@ -241,22 +262,6 @@ namespace Observatory.UI.ViewModels
get { return tabs; }
}
// TODO(fredjk_gh): remove.
private void SetWorkerReadAllState(bool isReadingAll)
{
foreach (var worker in workers)
{
if (isReadingAll)
{
worker.ReadAllStarted();
}
else
{
worker.ReadAllFinished();
}
}
}
private static bool CheckUpdate()
{
try

View File

@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Observatory.Framework;
using Observatory.Framework;
namespace Observatory.UI.ViewModels
{

View File

@ -27,6 +27,11 @@ namespace Observatory.UI.Views
{
InitializeComponent();
nativePopup = new();
this.DetachedFromVisualTree += (o, e) =>
{
nativePopup.CloseAll();
};
}
private void InitializeComponent()
@ -666,7 +671,7 @@ namespace Observatory.UI.Views
#endregion
#region Monitor On Launch
#region Actions On Launch
TextBlock startMonitorLabel = new() { Text = "Start monitor on Observatory launch" };
CheckBox startMonitorCheckbox = new() { IsChecked = Properties.Core.Default.StartMonitor, Content = startMonitorLabel };
@ -683,6 +688,21 @@ namespace Observatory.UI.Views
Properties.Core.Default.Save();
};
TextBlock startReadAllLabel = new() { Text = "Read All on Observatory launch" };
CheckBox startReadAllCheckbox = new() { IsChecked = Properties.Core.Default.StartReadAll, Content = startReadAllLabel };
startReadAllCheckbox.Checked += (object sender, RoutedEventArgs e) =>
{
Properties.Core.Default.StartReadAll = true;
Properties.Core.Default.Save();
};
startReadAllCheckbox.Unchecked += (object sender, RoutedEventArgs e) =>
{
Properties.Core.Default.StartReadAll = false;
Properties.Core.Default.Save();
};
#endregion
#endregion
@ -753,6 +773,7 @@ namespace Observatory.UI.Views
gridManager.AddSetting(primeSystemContexCheckbox);
gridManager.AddSetting(startMonitorCheckbox);
gridManager.AddSetting(startReadAllCheckbox);
gridManager.AddSettingWithLabel(journalPathLabel, journalPath);
gridManager.AddSetting(journalBrowse);

View File

@ -81,6 +81,14 @@
Content="Export">
Export
</Button>
<Button
Name="clear"
Margin="10"
FontSize="15"
Command="{Binding ClearGrid}"
Content="Clear">
Clear
</Button>
<Button
Name="ToggleMonitor"
Margin="10"