diff --git a/DICUI.Avalonia/App.axaml b/DICUI.Avalonia/App.axaml
new file mode 100644
index 00000000..c1a2b88f
--- /dev/null
+++ b/DICUI.Avalonia/App.axaml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
diff --git a/DICUI.Avalonia/App.axaml.cs b/DICUI.Avalonia/App.axaml.cs
new file mode 100644
index 00000000..40ee8f77
--- /dev/null
+++ b/DICUI.Avalonia/App.axaml.cs
@@ -0,0 +1,24 @@
+using Avalonia;
+using Avalonia.Controls.ApplicationLifetimes;
+using Avalonia.Markup.Xaml;
+
+namespace DICUI.Avalonia
+{
+ public class App : Application
+ {
+ public override void Initialize()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+
+ public override void OnFrameworkInitializationCompleted()
+ {
+ if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
+ {
+ desktop.MainWindow = new MainWindow();
+ }
+
+ base.OnFrameworkInitializationCompleted();
+ }
+ }
+}
diff --git a/DICUI.Avalonia/ComboBoxItems/CategoryComboBoxItem.cs b/DICUI.Avalonia/ComboBoxItems/CategoryComboBoxItem.cs
new file mode 100644
index 00000000..2eb67000
--- /dev/null
+++ b/DICUI.Avalonia/ComboBoxItems/CategoryComboBoxItem.cs
@@ -0,0 +1,29 @@
+using DICUI.Utilities;
+using DICUI.Web;
+
+namespace DICUI.Avalonia
+{
+ ///
+ /// Represents a single item in the Category combo box
+ ///
+ public class CategoryComboBoxItem
+ {
+ private object data;
+
+ public CategoryComboBoxItem(DiscCategory? category) => data = category;
+
+ public static implicit operator DiscCategory? (CategoryComboBoxItem item) => item.data as DiscCategory?;
+
+ public string Name
+ {
+ get { return (data as DiscCategory?).LongName(); }
+ }
+
+ public bool IsChecked { get; set; }
+
+ public DiscCategory? Value
+ {
+ get { return data as DiscCategory?; }
+ }
+ }
+}
diff --git a/DICUI.Avalonia/ComboBoxItems/KnownSystemComboBoxItem.cs b/DICUI.Avalonia/ComboBoxItems/KnownSystemComboBoxItem.cs
new file mode 100644
index 00000000..0f9160b3
--- /dev/null
+++ b/DICUI.Avalonia/ComboBoxItems/KnownSystemComboBoxItem.cs
@@ -0,0 +1,35 @@
+using Avalonia.Media;
+using DICUI.Data;
+using DICUI.Utilities;
+
+namespace DICUI.Avalonia
+{
+ ///
+ /// Represents a single item in the System combo box
+ ///
+ public class KnownSystemComboBoxItem
+ {
+ private object data;
+
+ public KnownSystemComboBoxItem(KnownSystem? system) => data = system;
+ public KnownSystemComboBoxItem(KnownSystemCategory? category) => data = category;
+
+ public ISolidColorBrush Foreground { get => IsHeader() ? Brushes.Gray : Brushes.Black; }
+
+ public bool IsHeader() => data is KnownSystemCategory?;
+ public bool IsSystem() => data is KnownSystem?;
+
+ public static implicit operator KnownSystem? (KnownSystemComboBoxItem item) => item.data as KnownSystem?;
+
+ public string Name
+ {
+ get
+ {
+ if (IsHeader())
+ return "---------- " + (data as KnownSystemCategory?).LongName() + " ----------";
+ else
+ return (data as KnownSystem?).LongName();
+ }
+ }
+ }
+}
diff --git a/DICUI.Avalonia/ComboBoxItems/LanguageComboBoxItem.cs b/DICUI.Avalonia/ComboBoxItems/LanguageComboBoxItem.cs
new file mode 100644
index 00000000..7216b1fc
--- /dev/null
+++ b/DICUI.Avalonia/ComboBoxItems/LanguageComboBoxItem.cs
@@ -0,0 +1,29 @@
+using DICUI.Utilities;
+using DICUI.Web;
+
+namespace DICUI.Avalonia
+{
+ ///
+ /// Represents a single item in the Language combo box
+ ///
+ public class LanguageComboBoxItem
+ {
+ private object data;
+
+ public LanguageComboBoxItem(Language? region) => data = region;
+
+ public static implicit operator Language? (LanguageComboBoxItem item) => item.data as Language?;
+
+ public string Name
+ {
+ get { return (data as Language?).LongName(); }
+ }
+
+ public bool IsChecked { get; set; }
+
+ public Language? Value
+ {
+ get { return data as Language?; }
+ }
+ }
+}
diff --git a/DICUI.Avalonia/ComboBoxItems/MediaTypeComboBoxItem.cs b/DICUI.Avalonia/ComboBoxItems/MediaTypeComboBoxItem.cs
new file mode 100644
index 00000000..4dbc4abc
--- /dev/null
+++ b/DICUI.Avalonia/ComboBoxItems/MediaTypeComboBoxItem.cs
@@ -0,0 +1,20 @@
+using DICUI.Data;
+using DICUI.Utilities;
+
+namespace DICUI.Avalonia
+{
+ ///
+ /// Represents a single item in the MediaType combo box
+ ///
+ public class MediaTypeComboBoxItem
+ {
+ private MediaType? data;
+
+ public MediaTypeComboBoxItem(MediaType? mediaType) => data = mediaType;
+
+ public static implicit operator MediaType? (MediaTypeComboBoxItem item) => item.data;
+
+ public string Name { get { return data.LongName(); }
+ }
+ }
+}
diff --git a/DICUI.Avalonia/ComboBoxItems/RegionComboBoxItem.cs b/DICUI.Avalonia/ComboBoxItems/RegionComboBoxItem.cs
new file mode 100644
index 00000000..2309b43a
--- /dev/null
+++ b/DICUI.Avalonia/ComboBoxItems/RegionComboBoxItem.cs
@@ -0,0 +1,30 @@
+using DICUI.Utilities;
+using DICUI.Web;
+
+namespace DICUI.Avalonia
+{
+ ///
+ /// Represents a single item in the Region combo box
+ ///
+ public class RegionComboBoxItem
+ {
+ private object data;
+
+ public RegionComboBoxItem(Region? region) => data = region;
+
+ public static implicit operator Region? (RegionComboBoxItem item) => item.data as Region?;
+
+ public string Name
+ {
+ get
+ {
+ return (data as Region?).LongName();
+ }
+ }
+
+ public Region? Value
+ {
+ get { return data as Region?; }
+ }
+ }
+}
diff --git a/DICUI.Avalonia/Constants.cs b/DICUI.Avalonia/Constants.cs
new file mode 100644
index 00000000..600af0c7
--- /dev/null
+++ b/DICUI.Avalonia/Constants.cs
@@ -0,0 +1,55 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using DICUI.Data;
+
+namespace DICUI.Avalonia
+{
+ ///
+ /// Variables for UI elements
+ ///
+ public static class Constants
+ {
+ public const string StartDumping = "Start Dumping";
+ public const string StopDumping = "Stop Dumping";
+
+ public const int LogWindowMarginFromMainWindow = 40;
+
+ // Private lists of known drive speed ranges
+ private static IReadOnlyList cd { get; } = new List { 1, 2, 3, 4, 6, 8, 12, 16, 20, 24, 32, 40, 44, 48, 52, 56, 72 };
+ private static IReadOnlyList dvd { get; } = cd.Where(s => s <= 24).ToList();
+ private static IReadOnlyList bd { get; } = cd.Where(s => s <= 16).ToList();
+ private static IReadOnlyList unknown { get; } = cd; // TODO: All or {1}? Maybe null?
+
+ ///
+ /// Get list of all drive speeds for a given MediaType
+ ///
+ /// MediaType? that represents the current item
+ /// Read-only list of drive speeds
+ public static IReadOnlyList GetSpeedsForMediaType(MediaType? type)
+ {
+ switch (type)
+ {
+ case MediaType.CDROM:
+ case MediaType.GDROM:
+ return cd;
+ case MediaType.DVD:
+ case MediaType.HDDVD:
+ case MediaType.NintendoGameCubeGameDisc:
+ case MediaType.NintendoWiiOpticalDisc:
+ return dvd;
+ case MediaType.BluRay:
+ return bd;
+ default:
+ return unknown;
+ }
+ }
+
+ // Create collections for UI based on known drive speeds
+ public static List SpeedsForCDAsCollection { get; } = GetDoubleCollectionFromIntList(cd);
+ public static List SpeedsForDVDAsCollection { get; } = GetDoubleCollectionFromIntList(dvd);
+ public static List SpeedsForBDAsCollection { get; } = GetDoubleCollectionFromIntList(bd);
+ private static List GetDoubleCollectionFromIntList(IReadOnlyList list)
+ => new List(list.Select(i => Convert.ToDouble(i)).ToList());
+ }
+}
diff --git a/DICUI.Avalonia/DICUI.Avalonia.csproj b/DICUI.Avalonia/DICUI.Avalonia.csproj
new file mode 100644
index 00000000..36a0f517
--- /dev/null
+++ b/DICUI.Avalonia/DICUI.Avalonia.csproj
@@ -0,0 +1,36 @@
+
+
+ WinExe
+ net472;net48;netcoreapp3.1
+ Icon.ico
+ 1.16.1
+ Copyright © 2020
+
+
+
+
+
+
+
+
+
+
+
+
+
+ DiscInformationWindow.axaml
+
+
+ LogWindow.axaml
+
+
+ MainWindow.axaml
+
+
+ OptionsWindow.axaml
+
+
+
+
+
+
diff --git a/DICUI.Avalonia/DiscInformationWindow.axaml b/DICUI.Avalonia/DiscInformationWindow.axaml
new file mode 100644
index 00000000..52e22e14
--- /dev/null
+++ b/DICUI.Avalonia/DiscInformationWindow.axaml
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/DICUI.Avalonia/DiscInformationWindow.axaml.cs b/DICUI.Avalonia/DiscInformationWindow.axaml.cs
new file mode 100644
index 00000000..123b33af
--- /dev/null
+++ b/DICUI.Avalonia/DiscInformationWindow.axaml.cs
@@ -0,0 +1,264 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Interactivity;
+using Avalonia.Markup.Xaml;
+using Avalonia.Media;
+using DICUI.Web;
+
+namespace DICUI.Avalonia
+{
+ public class DiscInformationWindow : Window
+ {
+ #region Fields
+
+ ///
+ /// List of available disc categories
+ ///
+ public List Categories { get; private set; }
+
+ ///
+ /// SubmissionInfo object to fill and save
+ ///
+ public SubmissionInfo SubmissionInfo { get; set; }
+
+ ///
+ /// List of available regions
+ ///
+ public List Regions { get; private set; }
+
+ ///
+ /// List of available languages
+ ///
+ public List Languages { get; private set; }
+
+ #endregion
+
+ public DiscInformationWindow()
+ {
+ this.InitializeComponent();
+#if DEBUG
+ this.AttachDevTools();
+#endif
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+
+ PopulateCategories();
+ PopulateRegions();
+ PopulateLanguages();
+ DisableFieldsIfNeeded();
+ }
+
+ #region Helpers
+
+ ///
+ /// Disable fields that aren't applicable to the current disc
+ ///
+ private void DisableFieldsIfNeeded()
+ {
+ // Only disable for single-layer discs
+ if (SubmissionInfo.SizeAndChecksums?.Layerbreak == default(long))
+ {
+ this.Find("L1MasteringRingTextBox").IsEnabled = false;
+ this.Find("L1MasteringRingTextBox").Background = Brushes.Gray;
+
+ this.Find("L1MasteringSIDTextBox").IsEnabled = false;
+ this.Find("L1MasteringSIDTextBox").Background = Brushes.Gray;
+
+ this.Find("L1ToolstampTextBox").IsEnabled = false;
+ this.Find("L1ToolstampTextBox").Background = Brushes.Gray;
+
+ this.Find("L1MouldSIDTextBox").IsEnabled = false;
+ this.Find("L1MouldSIDTextBox").Background = Brushes.Gray;
+
+ this.Find("L1AdditionalMouldTextBox").IsEnabled = false;
+ this.Find("L1AdditionalMouldTextBox").Background = Brushes.Gray;
+ }
+ }
+
+ ///
+ /// Load the current contents of the base SubmissionInfo to the UI
+ ///
+ public void Load()
+ {
+ // Common Disc Info
+ if (SubmissionInfo.CommonDiscInfo == null)
+ SubmissionInfo.CommonDiscInfo = new CommonDiscInfoSection();
+
+ this.Find("TitleTextBox").Text = SubmissionInfo.CommonDiscInfo.Title ?? "";
+ this.Find("ForeignTitleTextBox").Text = SubmissionInfo.CommonDiscInfo.ForeignTitleNonLatin ?? "";
+ this.Find("DiscNumberLetterTextBox").Text = SubmissionInfo.CommonDiscInfo.DiscNumberLetter ?? "";
+ this.Find("DiscTitleTextBox").Text = SubmissionInfo.CommonDiscInfo.DiscTitle ?? "";
+ this.Find("CategoryComboBox").SelectedIndex = Categories.FindIndex(r => r == SubmissionInfo.CommonDiscInfo.Category);
+ this.Find("RegionComboBox").SelectedIndex = Regions.FindIndex(r => r == SubmissionInfo.CommonDiscInfo.Region);
+ if (SubmissionInfo.CommonDiscInfo.Languages != null)
+ {
+ foreach (var language in SubmissionInfo.CommonDiscInfo.Languages)
+ Languages.Find(l => l == language).IsChecked = true;
+ }
+
+ this.Find("SerialTextBox").Text = SubmissionInfo.CommonDiscInfo.Serial ?? "";
+ this.Find("L0MasteringRingTextBox").Text = SubmissionInfo.CommonDiscInfo.MasteringRingFirstLayerDataSide ?? "";
+ this.Find("L0MasteringSIDTextBox").Text = SubmissionInfo.CommonDiscInfo.MasteringSIDCodeFirstLayerDataSide ?? "";
+ this.Find("L0ToolstampTextBox").Text = SubmissionInfo.CommonDiscInfo.ToolstampMasteringCodeFirstLayerDataSide ?? "";
+ this.Find("L0MouldSIDTextBox").Text = SubmissionInfo.CommonDiscInfo.MouldSIDCodeFirstLayerDataSide ?? "";
+ this.Find("L0AdditionalMouldTextBox").Text = SubmissionInfo.CommonDiscInfo.AdditionalMouldFirstLayerDataSide ?? "";
+ this.Find("L1MasteringRingTextBox").Text = SubmissionInfo.CommonDiscInfo.MasteringRingSecondLayerLabelSide ?? "";
+ this.Find("L1MasteringSIDTextBox").Text = SubmissionInfo.CommonDiscInfo.MasteringSIDCodeSecondLayerLabelSide ?? "";
+ this.Find("L1ToolstampTextBox").Text = SubmissionInfo.CommonDiscInfo.ToolstampMasteringCodeSecondLayerLabelSide ?? "";
+ this.Find("L1MouldSIDTextBox").Text = SubmissionInfo.CommonDiscInfo.MouldSIDCodeSecondLayerLabelSide ?? "";
+ this.Find("L1AdditionalMouldTextBox").Text = SubmissionInfo.CommonDiscInfo.AdditionalMouldSecondLayerLabelSide ?? "";
+ this.Find("BarcodeTextBox").Text = SubmissionInfo.CommonDiscInfo.Barcode ?? "";
+ this.Find("CommentsTextBox").Text = SubmissionInfo.CommonDiscInfo.Comments ?? "";
+ this.Find("ContentsTextBox").Text = SubmissionInfo.CommonDiscInfo.Contents ?? "";
+
+ // Version and Editions
+ if (SubmissionInfo.VersionAndEditions == null)
+ SubmissionInfo.VersionAndEditions = new VersionAndEditionsSection();
+
+ this.Find("VersionTextBox").Text = SubmissionInfo.VersionAndEditions.Version ?? "";
+ this.Find("EditionTextBox").Text = SubmissionInfo.VersionAndEditions.OtherEditions ?? "";
+ }
+
+ ///
+ /// Get a complete list of categories and fill the combo box
+ ///
+ private void PopulateCategories()
+ {
+ var categories = Enum.GetValues(typeof(DiscCategory)).OfType().ToList();
+
+ ViewModels.LoggerViewModel.VerboseLogLn("Populating categories, {0} categories found.", categories.Count);
+
+ Categories = new List();
+ foreach (var category in categories)
+ {
+ Categories.Add(new CategoryComboBoxItem(category));
+ }
+
+ this.Find("CategoryComboBox").Items = Categories;
+ this.Find("CategoryComboBox").SelectedIndex = 0;
+ }
+
+ ///
+ /// Get a complete list of languages and fill the combo box
+ ///
+ private void PopulateLanguages()
+ {
+ var languages = Enum.GetValues(typeof(Language)).OfType().ToList();
+
+ ViewModels.LoggerViewModel.VerboseLogLn("Populating languages, {0} languages found.", languages.Count);
+
+ Languages = new List();
+ foreach (var language in languages)
+ {
+ Languages.Add(new LanguageComboBoxItem(language));
+ }
+
+ this.Find("LanguagesComboBox").Items = Languages;
+ this.Find("LanguagesComboBox").SelectedIndex = 0;
+ }
+
+ ///
+ /// Get a complete list of regions and fill the combo box
+ ///
+ private void PopulateRegions()
+ {
+ var regions = Enum.GetValues(typeof(Region)).OfType().ToList();
+
+ ViewModels.LoggerViewModel.VerboseLogLn("Populating regions, {0} regions found.", regions.Count);
+
+ Regions = new List();
+ foreach (var region in regions)
+ {
+ Regions.Add(new RegionComboBoxItem(region));
+ }
+
+ this.Find("RegionComboBox").Items = Regions;
+ this.Find("RegionComboBox").SelectedIndex = 0;
+ }
+
+ ///
+ /// Save the current contents of the UI to the base SubmissionInfo
+ ///
+ private void Save()
+ {
+ // Common Disc Info
+ if (SubmissionInfo.CommonDiscInfo == null)
+ SubmissionInfo.CommonDiscInfo = new CommonDiscInfoSection();
+
+ SubmissionInfo.CommonDiscInfo.Title = this.Find("TitleTextBox").Text ?? "";
+ SubmissionInfo.CommonDiscInfo.ForeignTitleNonLatin = this.Find("ForeignTitleTextBox").Text ?? "";
+ SubmissionInfo.CommonDiscInfo.DiscNumberLetter = this.Find(" DiscNumberLetterTextBox").Text ?? "";
+ SubmissionInfo.CommonDiscInfo.DiscTitle = this.Find("DiscTitleTextBox").Text ?? "";
+ SubmissionInfo.CommonDiscInfo.Category = (this.Find("CategoryComboBox").SelectedItem as CategoryComboBoxItem)?.Value ?? DiscCategory.Games;
+ SubmissionInfo.CommonDiscInfo.Region = (this.Find("RegionComboBox").SelectedItem as RegionComboBoxItem)?.Value ?? Region.World;
+ var languages = new List();
+ foreach (var language in Languages)
+ {
+ if (language.IsChecked)
+ languages.Add(language.Value);
+ }
+ if (languages.Count == 0)
+ languages.Add(null);
+
+ SubmissionInfo.CommonDiscInfo.Languages = languages.ToArray();
+ SubmissionInfo.CommonDiscInfo.Serial = this.Find("SerialTextBox").Text ?? "";
+ SubmissionInfo.CommonDiscInfo.MasteringRingFirstLayerDataSide = this.Find("L0MasteringRingTextBox").Text ?? "";
+ SubmissionInfo.CommonDiscInfo.MasteringSIDCodeFirstLayerDataSide = this.Find("L0MasteringSIDTextBox").Text ?? "";
+ SubmissionInfo.CommonDiscInfo.ToolstampMasteringCodeFirstLayerDataSide = this.Find("L0ToolstampTextBox").Text ?? "";
+ SubmissionInfo.CommonDiscInfo.MouldSIDCodeFirstLayerDataSide = this.Find("L0MouldSIDTextBox").Text ?? "";
+ SubmissionInfo.CommonDiscInfo.AdditionalMouldFirstLayerDataSide = this.Find("L0AdditionalMouldTextBox").Text ?? "";
+ SubmissionInfo.CommonDiscInfo.MasteringRingSecondLayerLabelSide = this.Find("L1MasteringRingTextBox").Text ?? "";
+ SubmissionInfo.CommonDiscInfo.MasteringSIDCodeSecondLayerLabelSide = this.Find("L1MasteringSIDTextBox").Text ?? "";
+ SubmissionInfo.CommonDiscInfo.ToolstampMasteringCodeSecondLayerLabelSide = this.Find("L1ToolstampTextBox").Text ?? "";
+ SubmissionInfo.CommonDiscInfo.MouldSIDCodeSecondLayerLabelSide = this.Find("L1MouldSIDTextBox").Text ?? "";
+ SubmissionInfo.CommonDiscInfo.AdditionalMouldSecondLayerLabelSide = this.Find("L1AdditionalMouldTextBox").Text ?? "";
+ SubmissionInfo.CommonDiscInfo.Barcode = this.Find("BarcodeTextBox").Text ?? "";
+ SubmissionInfo.CommonDiscInfo.Comments = this.Find("CommentsTextBox").Text ?? "";
+ SubmissionInfo.CommonDiscInfo.Contents = this.Find("ContentsTextBox").Text ?? "";
+
+ // Version and Editions
+ if (SubmissionInfo.VersionAndEditions == null)
+ SubmissionInfo.VersionAndEditions = new VersionAndEditionsSection();
+
+ SubmissionInfo.VersionAndEditions.Version = this.Find("VersionTextBox").Text ?? "";
+ SubmissionInfo.VersionAndEditions.OtherEditions = this.Find("EditionTextBox").Text ?? "";
+ }
+
+ #endregion
+
+ #region Event Handlers
+
+ ///
+ /// Handler for AcceptButton Click event
+ ///
+ private void OnAcceptClick(object sender, RoutedEventArgs e)
+ {
+ Save();
+ Hide();
+ }
+
+ ///
+ /// Handler for CancelButton Click event
+ ///
+ private void OnCancelClick(object sender, RoutedEventArgs e)
+ {
+ Hide();
+ }
+
+ ///
+ /// Handler for DiscInformationWindow Closed event
+ ///
+ private void OnClosed(object sender, EventArgs e)
+ {
+ Hide();
+ }
+
+ #endregion
+ }
+}
diff --git a/DICUI.Avalonia/EnumDescriptionConverter.cs b/DICUI.Avalonia/EnumDescriptionConverter.cs
new file mode 100644
index 00000000..24eb49e1
--- /dev/null
+++ b/DICUI.Avalonia/EnumDescriptionConverter.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Globalization;
+using Avalonia.Data.Converters;
+using DICUI.Data;
+using DICUI.Utilities;
+
+namespace DICUI.Avalonia
+{
+ ///
+ /// Used to provide a converter to XAML files to render comboboxes with enum values
+ ///
+ public class EnumDescriptionConverter : IValueConverter
+ {
+ public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ // Common
+ if (value is MediaType?)
+ return ((MediaType?)value).LongName();
+ else if (value is KnownSystem?)
+ return ((KnownSystem?)value).LongName();
+
+ // Default
+ else
+ return "";
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ return string.Empty;
+ }
+ }
+}
diff --git a/DICUI.Avalonia/Icon.ico b/DICUI.Avalonia/Icon.ico
new file mode 100644
index 00000000..370e6559
Binary files /dev/null and b/DICUI.Avalonia/Icon.ico differ
diff --git a/DICUI.Avalonia/LogWindow.axaml b/DICUI.Avalonia/LogWindow.axaml
new file mode 100644
index 00000000..92e52a96
--- /dev/null
+++ b/DICUI.Avalonia/LogWindow.axaml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/DICUI.Avalonia/LogWindow.axaml.cs b/DICUI.Avalonia/LogWindow.axaml.cs
new file mode 100644
index 00000000..85684c8a
--- /dev/null
+++ b/DICUI.Avalonia/LogWindow.axaml.cs
@@ -0,0 +1,82 @@
+using System.IO;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Interactivity;
+using Avalonia.Markup.Xaml;
+using Avalonia.Media;
+
+namespace DICUI.Avalonia
+{
+ public class LogWindow : Window
+ {
+ public LogWindow()
+ {
+ this.InitializeComponent();
+#if DEBUG
+ this.AttachDevTools();
+#endif
+ }
+
+ ///
+ /// Adjust the position of the log window if the main window is moved
+ ///
+ public void AdjustPositionToMainWindow()
+ {
+ var owner = Owner as Window;
+ Position = new PixelPoint(
+ owner.Position.X,
+ owner.Position.Y + (int)owner.Height + Constants.LogWindowMarginFromMainWindow);
+ }
+
+ ///
+ /// Append rich text to the scrolling element
+ ///
+ /// Text to add, including newlines
+ /// Color to format the text
+ public void AppendToTextBox(string text, ISolidColorBrush color)
+ {
+ // TODO: Use brush color
+ this.Find("Output").Text += $"{text}\n";
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+
+ #region Event Handlers
+
+ ///
+ /// Handler for ClearButton Click event
+ ///
+ private void OnClearButton(object sender, RoutedEventArgs e)
+ {
+ this.Find("Output").Text = string.Empty;
+ }
+
+ ///
+ /// Handler for HideButton Click event
+ ///
+ private void OnHideButton(object sender, RoutedEventArgs e)
+ {
+ ViewModels.LoggerViewModel.WindowVisible = false;
+
+ //TODO: this should be bound directly to WindowVisible property in two way fashion
+ // we need to study how to properly do it in XAML
+ (Owner as MainWindow).Find("ShowLogCheckBox").IsChecked = false;
+ }
+
+ ///
+ /// Handler for SaveButton Click event
+ ///
+ private void OnSaveButton(object sender, RoutedEventArgs e)
+ {
+ using (StreamWriter tw = new StreamWriter(File.OpenWrite("console.log")))
+ {
+ tw.Write(this.Find("Output").Text);
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/DICUI.Avalonia/MainWindow.axaml b/DICUI.Avalonia/MainWindow.axaml
new file mode 100644
index 00000000..a909fedf
--- /dev/null
+++ b/DICUI.Avalonia/MainWindow.axaml
@@ -0,0 +1,109 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/DICUI.Avalonia/MainWindow.axaml.cs b/DICUI.Avalonia/MainWindow.axaml.cs
new file mode 100644
index 00000000..f1769342
--- /dev/null
+++ b/DICUI.Avalonia/MainWindow.axaml.cs
@@ -0,0 +1,843 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Input;
+using Avalonia.Interactivity;
+using Avalonia.Markup.Xaml;
+using BurnOutSharp;
+using DICUI.Data;
+using DICUI.Utilities;
+using DICUI.Web;
+using Newtonsoft.Json.Linq;
+
+namespace DICUI.Avalonia
+{
+ public class MainWindow : Window
+ {
+ #region Fields
+
+ ///
+ /// Currently selected or detected media type
+ ///
+ public MediaType? CurrentMediaType { get; private set; }
+
+ ///
+ /// Current list of drives
+ ///
+ public List Drives { get; private set; }
+
+ ///
+ /// Current dumping environment
+ ///
+ public DumpEnvironment Env { get; private set; }
+
+ ///
+ /// Current list of supported media types
+ ///
+ public List MediaTypes { get; private set; } = new List();
+
+ ///
+ /// Current list of supported system profiles
+ ///
+ public List Systems { get; private set; }
+
+ ///
+ /// Current UI options
+ ///
+ public UIOptions UIOptions { get; private set; } = new UIOptions();
+
+ #endregion
+
+ #region Private Instance Variables
+
+ ///
+ /// Current attached LogWindow
+ ///
+ private LogWindow logWindow;
+
+ #endregion
+
+ public MainWindow()
+ {
+ InitializeComponent();
+#if DEBUG
+ this.AttachDevTools();
+#endif
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+
+ // Load the options
+ ViewModels.OptionsViewModel = new OptionsViewModel(UIOptions);
+
+ // Load the log window
+ logWindow = new LogWindow();
+ logWindow.Owner = this;
+ ViewModels.LoggerViewModel.SetWindow(logWindow);
+
+ // Disable buttons until we load
+ this.Find