refactors and more UI

This commit is contained in:
Alex
2025-08-13 20:13:40 -07:00
parent 32396c3210
commit f61f6a7e28
11 changed files with 268 additions and 43 deletions
+102
View File
@@ -0,0 +1,102 @@
using System;
using System.IO;
using System.Linq;
using System.Text.Json;
namespace MercuryConverter.Data;
public static class Database
{
public static void Setup(string dataDirPath)
{
// Check that path exists
if (!Directory.Exists(dataDirPath))
{
Console.WriteLine($"Folder {dataDirPath} doesn't exist!");
return;
}
// Get metadata.json
var jPath = Path.Combine(dataDirPath, "metadata.json");
string jStr;
JsonElement mdObj;
try
{
jStr = File.ReadAllText(jPath);
}
catch (Exception e)
{
Console.WriteLine($"Couldn't read {jPath}: {e}");
return;
}
try
{
mdObj = JsonDocument.Parse(jStr).RootElement.GetProperty("Exports")[0].GetProperty("Table").GetProperty("Data");
}
catch (Exception e)
{
Console.WriteLine($"Couldn't parse JSON object: {e}");
return;
}
// TODO: Clear existing structures
// Parse metadata.json
foreach (var mdSong in mdObj.EnumerateArray())
{
var id = "";
var title = "";
var rubi = "";
var artist = "";
var genre = -1;
var copyright = "";
var bpm = "";
var version = -1;
var previewTime = -1;
var previewLength = -1;
var jacketPath = "";
var level = new string?[] { null, null, null, null };
var levelBGA = new string?[] { null, null, null, null};
var levelAudio = new string?[] { null, null, null, null };
var levelDesigner = new string?[] { null, null, null, null };
var levelClearRequirements = new string?[] { null, null, null, null };
foreach (var prop in mdSong.GetProperty("Value").EnumerateArray())
{
var value = prop.GetProperty("Value");
// Console.WriteLine($"{prop.GetProperty("Name")}={prop.GetProperty("Value")}");
switch (prop.GetProperty("Name").GetString()!)
{
case "AssetDirectory":
id = value.GetString()!;
break;
case "ScoreGenre":
genre = value.GetInt16();
break;
case "MusicMessage":
title = value.GetString();
break;
case "ArtistMessage":
artist = value.GetString();
break;
case "Rubi":
rubi = value.GetString();
break;
case "Bpm":
bpm = value.GetString();
break;
case "CopyrightMessage":
var c = value.GetString();
if (!new string?[] { "", "-", null }.Contains(c))
{
copyright = c;
}
break;
}
}
Console.WriteLine($"[{id}] {artist} - {title}");
}
}
}
-10
View File
@@ -1,10 +0,0 @@
namespace MercuryConverter;
using System;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
public static class Database
{
public static readonly ObservableCollection<Data.Song> Songs = new();
}
+3 -1
View File
@@ -19,9 +19,11 @@
<IncludeAssets Condition="'$(Configuration)' != 'Debug'">None</IncludeAssets>
<PrivateAssets Condition="'$(Configuration)' != 'Debug'">All</PrivateAssets>
</PackageReference>
<PackageReference Include="Deadpikle.AvaloniaProgressRing" Version="0.10.10" />
<PackageReference Include="DialogHost.Avalonia" Version="0.9.3" />
</ItemGroup>
<ItemGroup>
<AvaloniaResource Include="Assets\**"/>
<AvaloniaResource Include="Assets\**" />
</ItemGroup>
</Project>
+4 -2
View File
@@ -11,8 +11,10 @@ class Program
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
// yet and stuff might break.
[STAThread]
public static void Main(string[] args) => BuildAvaloniaApp()
.StartWithClassicDesktopLifetime(args);
public static void Main(string[] args)
{
BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
}
// Avalonia configuration, don't remove; also used by visual designer.
public static AppBuilder BuildAvaloniaApp()
+5 -1
View File
@@ -1,6 +1,7 @@
<Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="MercuryConverter.UI.App"
xmlns:dialogHostAvalonia="clr-namespace:DialogHostAvalonia;assembly=DialogHost.Avalonia"
RequestedThemeVariant="Default"> <!-- Dark Default Light -->
<Application.Styles>
@@ -15,6 +16,8 @@
</FluentTheme>
<StyleInclude Source="avares://Avalonia.Controls.DataGrid/Themes/Fluent.xaml"/>
<dialogHostAvalonia:DialogHostStyles/>
<StyleInclude Source="avares://AvaloniaProgressRing/Styles/ProgressRing.xaml"/>
</Application.Styles>
<Application.Resources>
@@ -28,7 +31,8 @@
</ResourceDictionary>
<ResourceDictionary x:Key="Dark">
<SolidColorBrush x:Key="ExpanderHeaderBackgroundPointerOver">#20000000</SolidColorBrush>
<SolidColorBrush x:Key="DataGridContentBackground">#20000000</SolidColorBrush>
<SolidColorBrush x:Key="DataGridContentBackground">#ff000000</SolidColorBrush>
<SolidColorBrush x:Key="DialogHostOverlayBackgroundMixinBrush">#222244</SolidColorBrush>
<Bitmap x:Key="BannerBitmap">/Assets/imgs/banner_dark.png</Bitmap>
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
+19
View File
@@ -0,0 +1,19 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:MercuryConverter.UI.Dialogs"
xmlns:progRing="clr-namespace:AvaloniaProgressRing;assembly=AvaloniaProgressRing"
x:Class="MercuryConverter.UI.Dialogs.DataOpen"
>
<StackPanel Margin="12">
<TextBlock Text="Select your data folder..."/>
<progRing:ProgressRing Foreground="{DynamicResource SystemBaseMediumColor}"
Width="36"
Height="36"
IsActive="True"
HorizontalAlignment="Center"
Margin="0,15,0,0"/>
</StackPanel>
</UserControl>
+40
View File
@@ -0,0 +1,40 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Avalonia.Controls;
using Avalonia.Platform.Storage;
using Avalonia.Threading;
namespace MercuryConverter.UI.Dialogs;
public partial class DataOpen : Window
{
public DataOpen()
{
InitializeComponent();
BeginDirSelection();
}
private void BeginDirSelection()
{
Dispatcher.UIThread.Invoke(async () =>
{
await Task.Delay(200);
var dirSelection = await GetTopLevel(this)!.StorageProvider.OpenFolderPickerAsync
(
new FolderPickerOpenOptions
{
Title = "Open Data Folder",
AllowMultiple = false,
}
);
if (dirSelection.Count <= 0)
{
return;
}
var d = dirSelection!.First().TryGetLocalPath()!;
});
}
}
+21
View File
@@ -0,0 +1,21 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:MercuryConverter.UI.Dialogs"
x:Class="MercuryConverter.UI.Dialogs.Welcome"
>
<StackPanel Margin="12">
<TextBlock FontSize="36" HorizontalAlignment="Center">
Welcome to <Bold>MercuryConverter</Bold>!
</TextBlock>
<TextBlock HorizontalAlignment="Center">
<InlineUIContainer BaselineAlignment="Bottom">
<!-- TODO: move HOWTO to this repo -->
<HyperlinkButton Content="Setup your data folder" Padding="0" NavigateUri="https://github.com/muskit/WacK-Repackager/blob/main/HOWTO.md" />
</InlineUIContainer>
before proceeding.
</TextBlock>
<Button Content="Open Data Folder" Click="ClickHandler" HorizontalAlignment="Center" Margin="0 8 0 0" />
</StackPanel>
</UserControl>
+19
View File
@@ -0,0 +1,19 @@
using System;
using Avalonia.Controls;
using Avalonia.Interactivity;
using DialogHostAvalonia;
namespace MercuryConverter.UI.Dialogs;
public partial class Welcome : Window
{
public Welcome()
{
InitializeComponent();
}
private void ClickHandler(object sender, RoutedEventArgs args)
{
MainWindow.Instance!.Dialog.DialogContent = new DataOpen().Content;
}
}
+34 -27
View File
@@ -2,41 +2,48 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:dialogHost="clr-namespace:DialogHostAvalonia;assembly=DialogHost.Avalonia"
xmlns:local="clr-namespace:MercuryConverter.UI"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="MercuryConverter.UI.MainWindow"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
Title="MercuryConverter"
Width="1024" Height="800"
MinWidth="800" MinHeight="600"
ExtendClientAreaToDecorationsHint="True"
>
<!-- Components -->
<Panel>
<!-- Banner -->
<StackPanel>
<UserControl Background="{DynamicResource SystemAltHighColor}" Height="86"/>
</StackPanel>
<StackPanel HorizontalAlignment="Right">
<Image Height="86" Source="{DynamicResource BannerBitmap}"/>
</StackPanel>
<dialogHost:DialogHost CloseOnClickAway="False" Name="Dialog">
<dialogHost:DialogHost.DialogContent>
<Button Content="Test"/>
</dialogHost:DialogHost.DialogContent>
<DockPanel>
<Menu Name="MenuBar" DockPanel.Dock="Top">
<MenuItem Header="File">
<MenuItem Header="Open Data Folder..." />
</MenuItem>
</Menu>
<!-- Components -->
<Panel>
<!-- Banner -->
<StackPanel>
<UserControl Background="{DynamicResource SystemAltHighColor}" Height="86"/>
</StackPanel>
<StackPanel HorizontalAlignment="Right">
<Image Height="86" Source="{DynamicResource BannerBitmap}"/>
</StackPanel>
<TabControl>
<TabItem Header="selection">
<UserControl Name="SelectionControl"/>
</TabItem>
<DockPanel>
<Menu Name="MenuBar" DockPanel.Dock="Top">
<MenuItem Header="File">
<MenuItem Header="Open Data Folder..." />
</MenuItem>
</Menu>
<TabItem Header="export">
</TabItem>
</TabControl>
</DockPanel>
</Panel>
<TabControl>
<TabItem Header="selection">
<UserControl Name="SelectionControl"/>
</TabItem>
<TabItem Header="export">
</TabItem>
</TabControl>
</DockPanel>
</Panel>
</dialogHost:DialogHost>
</Window>
+21 -2
View File
@@ -1,14 +1,21 @@
using System;
using System.Threading.Tasks;
using Avalonia.Controls;
using Avalonia.Styling;
using Avalonia.Threading;
using MercuryConverter.UI.Dialogs;
using MercuryConverter.UI.Views;
namespace MercuryConverter.UI;
using MercuryConverter.UI.Views;
public partial class MainWindow : Window
{
public static MainWindow? Instance { get; private set; }
private bool initialShown = false;
public MainWindow()
{
Instance = this;
InitializeComponent();
// Force dark mode in designer
@@ -19,5 +26,17 @@ public partial class MainWindow : Window
// Setup tab views
SelectionControl.Content = new Selection();
// Show dialog on startup
Activated += OnActivated;
}
private void OnActivated(object? sender, EventArgs e)
{
if (initialShown) return;
initialShown = true;
Dialog.DialogContent = new Welcome().Content;
Dialog.IsOpen = true;
}
}