diff --git a/.github/main.yml b/.github/main.yml new file mode 100644 index 0000000..a72eb55 --- /dev/null +++ b/.github/main.yml @@ -0,0 +1,36 @@ +name: CI/CD + +on: + push: + branches: + - main + - '*' + +jobs: + build: + runs-on: windows-latest + + steps: + - uses: actions/checkout@v4 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 8.0.x + + - name: Restore dependencies + run: dotnet restore + + - name: Install tools + run: dotnet tool install --global vpk + + - name: Dotnet publish + run: dotnet publish src/Plpext/Plpext.UI/Plpext.UI.csproj -c Release -r win-x64 -o publish + + - name: Vpk pack + run: vpk pack --mainExe=Plpext.exe --packId=Plpext --packVersion=1.0.0 --packDir=publish -o build/win + + - name: Upload artifact + uses: softprops/action-gh-release@v2 + with: + files: build/win/Plpext-win-Setup.exe diff --git a/.gitignore b/.gitignore index 4de168d..ad64cdb 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,5 @@ artifacts/ *.suo *.userprefs *DS_Store -*.sln.ide \ No newline at end of file +*.sln.ide +/build/win diff --git a/src/Plpext.Core.Windows/Plpext.Core.Windows.csproj b/src/Plpext.Core.Windows/Plpext.Core.Windows.csproj index 0af2c11..3fbda68 100644 --- a/src/Plpext.Core.Windows/Plpext.Core.Windows.csproj +++ b/src/Plpext.Core.Windows/Plpext.Core.Windows.csproj @@ -4,14 +4,14 @@ net8.0 enable enable - x86;x64 + x86;x64;AnyCPU - + Always OpenAL32.dll diff --git a/src/Plpext.Core/AudioConverter/MP3AudioConverter.cs b/src/Plpext.Core/AudioConverter/MP3AudioConverter.cs index 7c9dfb5..317b27e 100644 --- a/src/Plpext.Core/AudioConverter/MP3AudioConverter.cs +++ b/src/Plpext.Core/AudioConverter/MP3AudioConverter.cs @@ -61,7 +61,7 @@ namespace Plpext.Core.AudioConverter var audioDuration = (double)(pcmData.Length / 2) / mp3Stream.Frequency; - return new AudioFile() { Name = baseFile.Name, Data = pcmData, Duration = TimeSpan.FromSeconds(audioDuration), Format = AudioFormat.Mono16, Frequency = mp3Stream.Frequency }; + return new AudioFile() { Name = baseFile.Name, MP3Data = file, Data = pcmData, Duration = TimeSpan.FromSeconds(audioDuration), Format = AudioFormat.Mono16, Frequency = mp3Stream.Frequency }; } private static byte[] ResampleToMono(Span data) diff --git a/src/Plpext.Core/AudioPlayer/AudioPlayer.cs b/src/Plpext.Core/AudioPlayer/AudioPlayer.cs index 81d661c..71dfb14 100644 --- a/src/Plpext.Core/AudioPlayer/AudioPlayer.cs +++ b/src/Plpext.Core/AudioPlayer/AudioPlayer.cs @@ -26,23 +26,24 @@ public sealed class AudioPlayer : IAudioPlayer, IDisposable public PlaybackState State { get; private set; } = PlaybackState.Stopped; - public async Task InitAudioPlayerAsync(AudioFile input, CancellationToken cancellationToken) + public async Task InitAudioPlayerAsync(AudioFile input, bool autoStart, CancellationToken cancellationToken) { _audioFile = input; - _playbackCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); try { int bufferId = AL.GenBuffer(); int sourceId = AL.GenSource(); - + _currentBufferId = bufferId; _currentSourceId = sourceId; AL.BufferData(bufferId, ALFormat.Mono16, input.Data.Span, input.Frequency); AL.Source(sourceId, ALSourcei.Buffer, bufferId); - return await Start(); + if(autoStart) + return await Start(); + return true; } catch (Exception ex) { diff --git a/src/Plpext.Core/Interfaces/IAudioPlayer.cs b/src/Plpext.Core/Interfaces/IAudioPlayer.cs index 9504d90..9ae75da 100644 --- a/src/Plpext.Core/Interfaces/IAudioPlayer.cs +++ b/src/Plpext.Core/Interfaces/IAudioPlayer.cs @@ -9,7 +9,7 @@ namespace Plpext.Core.Interfaces; public interface IAudioPlayer { - Task InitAudioPlayerAsync(AudioFile input, CancellationToken cancellationToken); + Task InitAudioPlayerAsync(AudioFile input, bool autoStart, CancellationToken cancellationToken); void Resume(); void Pause(); void Stop(); diff --git a/src/Plpext.Core/Models/AudioFile.cs b/src/Plpext.Core/Models/AudioFile.cs index 6ffcb59..a979428 100644 --- a/src/Plpext.Core/Models/AudioFile.cs +++ b/src/Plpext.Core/Models/AudioFile.cs @@ -9,6 +9,7 @@ namespace Plpext.Core.Models public record AudioFile { public required string Name { get; init; } + public ReadOnlyMemory MP3Data { get; init; } public ReadOnlyMemory Data { get; init; } public TimeSpan Duration { get; init; } public AudioFormat Format { get; init; } diff --git a/src/Plpext/Plpext.UI/App.axaml b/src/Plpext/Plpext.UI/App.axaml new file mode 100644 index 0000000..74f1108 --- /dev/null +++ b/src/Plpext/Plpext.UI/App.axaml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Plpext/Plpext.UI/App.axaml.cs b/src/Plpext/Plpext.UI/App.axaml.cs new file mode 100644 index 0000000..96c8bba --- /dev/null +++ b/src/Plpext/Plpext.UI/App.axaml.cs @@ -0,0 +1,48 @@ +using System; +using System.Linq; +using Avalonia; +using Avalonia.Controls; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Data.Core; +using Avalonia.Data.Core.Plugins; +using Avalonia.Markup.Xaml; +using Microsoft.Extensions.DependencyInjection; +using Plpext.Core.AudioPlayer; +using Plpext.UI.DependencyInjection; +using Plpext.UI.ViewModels; +using Plpext.UI.Views; + +namespace Plpext.UI +{ + public class App : Application + { + public override void Initialize() + { + AvaloniaXamlLoader.Load(this); + } + + public override void OnFrameworkInitializationCompleted() + { + if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + { + DisableAvaloniaDataAnnotationValidation(); + Container.Services.GetRequiredService().Initialize(); + desktop.MainWindow = Container.Services.GetRequiredService(); + desktop.MainWindow.DataContext = Container.Services.GetRequiredService(); + } + + base.OnFrameworkInitializationCompleted(); + } + + private void DisableAvaloniaDataAnnotationValidation() + { + var dataValidationPluginsToRemove = + BindingPlugins.DataValidators.OfType().ToArray(); + + foreach (var plugin in dataValidationPluginsToRemove) + { + BindingPlugins.DataValidators.Remove(plugin); + } + } + } +} \ No newline at end of file diff --git a/docs/plpext.png b/src/Plpext/Plpext.UI/Assets/plpext.png similarity index 100% rename from docs/plpext.png rename to src/Plpext/Plpext.UI/Assets/plpext.png diff --git a/src/Plpext/Plpext.UI/Controls/AudioPlayerControl.axaml b/src/Plpext/Plpext.UI/Controls/AudioPlayerControl.axaml new file mode 100644 index 0000000..d9b76f0 --- /dev/null +++ b/src/Plpext/Plpext.UI/Controls/AudioPlayerControl.axaml @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Plpext/Plpext.UI/Controls/AudioPlayerControl.axaml.cs b/src/Plpext/Plpext.UI/Controls/AudioPlayerControl.axaml.cs new file mode 100644 index 0000000..e03ce1e --- /dev/null +++ b/src/Plpext/Plpext.UI/Controls/AudioPlayerControl.axaml.cs @@ -0,0 +1,107 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Controls.Primitives; +using System.Windows.Input; +using Avalonia.Data; +using Plpext.Core.Models; + +namespace Plpext.UI; + +public class AudioPlayerControl : TemplatedControl +{ + public static readonly StyledProperty PlaybackStateProperty = + AvaloniaProperty.Register(nameof(PlaybackState), defaultValue: PlaybackState.Unknown, inherits: false, defaultBindingMode: BindingMode.OneWay); + + public PlaybackState PlaybackState + { + get {return GetValue(PlaybackStateProperty);} + set {SetValue(PlaybackStateProperty, value);} + } + + public static readonly StyledProperty IsPlayingProperty = + AvaloniaProperty.Register(nameof(IsPlaying), false, false, Avalonia.Data.BindingMode.TwoWay); + + public bool IsPlaying + { + get { return GetValue(IsPlayingProperty); } + set { SetValue(IsPlayingProperty, value); } + } + + public static readonly StyledProperty CurrentDurationProperty = AvaloniaProperty.Register + ( + name: nameof(CurrentDuration), + defaultValue: "0:55", + inherits: false, + defaultBindingMode: Avalonia.Data.BindingMode.TwoWay, + validate: (x) => x != "0" + ); + + public string CurrentDuration + { + get { return GetValue(CurrentDurationProperty); } + set { SetValue(CurrentDurationProperty, value); } + } + + public static readonly StyledProperty TotalDurationProperty = AvaloniaProperty.Register + ( + name: nameof(TotalDuration), + defaultValue: "1:07", + inherits: false, + defaultBindingMode: Avalonia.Data.BindingMode.TwoWay, + validate: (x) => x != "0" + ); + + public string TotalDuration + { + get { return GetValue(TotalDurationProperty); } + set { SetValue(TotalDurationProperty, value); } + } + + public static readonly StyledProperty ProgressProperty = AvaloniaProperty.Register + ( + name: nameof(Progress), + defaultValue: 0, + inherits: false, + defaultBindingMode: Avalonia.Data.BindingMode.TwoWay, + validate: (x) => x >= 0 + ); + + public double Progress + { + get { return GetValue(ProgressProperty); } + set { SetValue(ProgressProperty, value); } + } + + public static readonly StyledProperty PlayCommandProperty = + AvaloniaProperty.Register(nameof(PlayCommand)); + public static readonly StyledProperty PlayCommandParameterProperty = +AvaloniaProperty.Register(nameof(PlayCommandParameter)); + + public ICommand? PlayCommand + { + get => GetValue(PlayCommandProperty); + set => SetValue(PlayCommandProperty, value); + } + public object? PlayCommandParameter + { + get => GetValue(PlayCommandParameterProperty); + set => SetValue(PlayCommandParameterProperty, value); + } + + public static readonly StyledProperty StopCommandProperty = + AvaloniaProperty.Register(nameof(StopCommand)); + public static readonly StyledProperty StopCommandParameterProperty = + AvaloniaProperty.Register(nameof(StopCommandParameter)); + + public ICommand? StopCommand + { + get => GetValue(StopCommandProperty); + set => SetValue(StopCommandProperty, value); + } + public object? StopCommandParameter + { + get => GetValue(StopCommandParameterProperty); + set => SetValue(StopCommandParameterProperty, value); + } + +} \ No newline at end of file diff --git a/src/Plpext/Plpext.UI/Controls/Converters/PlaybackStateToPathConverter.cs b/src/Plpext/Plpext.UI/Controls/Converters/PlaybackStateToPathConverter.cs new file mode 100644 index 0000000..2503dfb --- /dev/null +++ b/src/Plpext/Plpext.UI/Controls/Converters/PlaybackStateToPathConverter.cs @@ -0,0 +1,29 @@ +using System; +using System.Globalization; +using Avalonia.Data.Converters; +using Avalonia.Media; +using Plpext.Core.Models; + +namespace Plpext.UI.Controls.Converters; + +public class PlaybackStateToPathConverter : IValueConverter +{ + public static readonly PlaybackStateToPathConverter Instance = new(); + + public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + { + if (value is PlaybackState state) + { + return state == PlaybackState.Playing + ? Geometry.Parse("M4,2 H7 V14 H4 Z M11,2 H14 V14 H11 Z") + : Geometry.Parse("M5,2 L5,14 L15,8 Z"); + } + + return Geometry.Parse("M4,2 L4,14 L14,8 Z"); + } + + public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/src/Plpext/Plpext.UI/DependencyInjection/Container.cs b/src/Plpext/Plpext.UI/DependencyInjection/Container.cs new file mode 100644 index 0000000..8e54c30 --- /dev/null +++ b/src/Plpext/Plpext.UI/DependencyInjection/Container.cs @@ -0,0 +1,63 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Plpext.Core.FileStorage; +using Plpext.Core.Interfaces; +using Plpext.Core.MP3Parser; +using Plpext.Core.PackExtractor; +using Plpext.UI.ViewModels; +using Serilog; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Plpext.Core.AudioConverter; +using Plpext.Core.AudioPlayer; +using Plpext.UI.Services; +using Plpext.UI.Services.Converter; +using Plpext.UI.Services.FileLoader; +using Plpext.UI.Services.PlatformStorage; +using Plpext.UI.Views; + +namespace Plpext.UI.DependencyInjection +{ + public static class Container + { + private static IServiceProvider? _container; + public static IServiceProvider Services + { + get => _container ?? Register(); + } + + private static IServiceProvider Register() + { + var hostBuilder = Host + .CreateDefaultBuilder() + .UseSerilog((context, loggerConfiguration) => + { + loggerConfiguration.WriteTo.Debug(); + }) + .ConfigureServices((context, services) => + { + services.AddSingleton(); + services.AddSingleton(); + + services.AddTransient(); + + services.AddSingleton(); + services.AddScoped(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + }) + .Build(); + hostBuilder.Start(); + _container = hostBuilder.Services; + return _container; + } + } +} diff --git a/src/Plpext/Plpext.UI/Plpext.UI.csproj b/src/Plpext/Plpext.UI/Plpext.UI.csproj new file mode 100644 index 0000000..a64a8ef --- /dev/null +++ b/src/Plpext/Plpext.UI/Plpext.UI.csproj @@ -0,0 +1,75 @@ + + + WinExe + net8.0 + enable + true + app.manifest + true + x86;x64 + Plpext + true + true + + + + + + + + + + + + + + + + + + + None + All + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Plpext/Plpext.UI/Program.cs b/src/Plpext/Plpext.UI/Program.cs new file mode 100644 index 0000000..215ccb2 --- /dev/null +++ b/src/Plpext/Plpext.UI/Program.cs @@ -0,0 +1,26 @@ +using System; +using Avalonia; +using Velopack; + +namespace Plpext.UI +{ + internal sealed class Program + { + // Initialization code. Don't use any Avalonia, third-party APIs or any + // SynchronizationContext-reliant code before AppMain is called: things aren't initialized + // yet and stuff might break. + [STAThread] + public static void Main(string[] args) + { + VelopackApp.Build().Run(); + BuildAvaloniaApp().StartWithClassicDesktopLifetime(args); + } + + // Avalonia configuration, don't remove; also used by visual designer. + public static AppBuilder BuildAvaloniaApp() + => AppBuilder.Configure() + .UsePlatformDetect() + .WithInterFont() + .LogToTrace(); + } +} diff --git a/src/Plpext/Plpext.UI/Resources/Colors.axaml b/src/Plpext/Plpext.UI/Resources/Colors.axaml new file mode 100644 index 0000000..ca938db --- /dev/null +++ b/src/Plpext/Plpext.UI/Resources/Colors.axaml @@ -0,0 +1,18 @@ + + #020615 + #2D3C81 + #99A6E5 + #1F0400 + #661409 + #BD4131 + #FFAA9F + + + + + + + + + diff --git a/src/Plpext/Plpext.UI/Services/Converter/FileConvertService.cs b/src/Plpext/Plpext.UI/Services/Converter/FileConvertService.cs new file mode 100644 index 0000000..e237aa2 --- /dev/null +++ b/src/Plpext/Plpext.UI/Services/Converter/FileConvertService.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Plpext.Core.Interfaces; +using Plpext.Core.Models; + +namespace Plpext.UI.Services.Converter; + +public class FileConvertService : IConvertService +{ + private readonly IMP3Parser _mp3Parser; + private readonly IFileStorage _fileStorage; + + public FileConvertService(IMP3Parser mp3Parser, IFileStorage fileStorage) + { + _mp3Parser = mp3Parser; + _fileStorage = fileStorage; + } + + public async Task ConvertFilesAsync(IEnumerable files, string outputFolder) + { + var mp3Files = new List(); + foreach (var file in files) + { + mp3Files.Add(await _mp3Parser.ParseIntoMP3(file.MP3Data, default)); + } + await _fileStorage.SaveFilesAsync(mp3Files, outputFolder); + } +} \ No newline at end of file diff --git a/src/Plpext/Plpext.UI/Services/FileLoader/FileLoaderService.cs b/src/Plpext/Plpext.UI/Services/FileLoader/FileLoaderService.cs new file mode 100644 index 0000000..f1321d9 --- /dev/null +++ b/src/Plpext/Plpext.UI/Services/FileLoader/FileLoaderService.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Plpext.Core.AudioPlayer; +using Plpext.Core.Interfaces; +using Plpext.Core.Models; +using Plpext.UI.ViewModels; + +namespace Plpext.UI.Services.FileLoader; + +public class FileLoaderService : IFileLoaderService +{ + private readonly IPackExtractor _packExtractor; + private readonly IAudioConverter _audioConverter; + private IEnumerable> _currentFile = null!; + + public FileLoaderService(IPackExtractor packExtractor, IAudioConverter audioConverter) + { + _packExtractor = packExtractor; + _audioConverter = audioConverter; + } + + public async Task GetFileCountAsync(string filePath) + { + _currentFile = await _packExtractor.GetFileListAsync(filePath, default); + return _currentFile?.Count() ?? 0; + } + + public async IAsyncEnumerable LoadFilesAsync() + { + foreach (var file in _currentFile) + { + var audioFile = await _audioConverter.ConvertAudioAsync(file, default); + yield return new AudioPlayerViewModel(new AudioPlayer(), audioFile); + } + } +} \ No newline at end of file diff --git a/src/Plpext/Plpext.UI/Services/IConvertService.cs b/src/Plpext/Plpext.UI/Services/IConvertService.cs new file mode 100644 index 0000000..933d31f --- /dev/null +++ b/src/Plpext/Plpext.UI/Services/IConvertService.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Plpext.Core.Models; + +namespace Plpext.UI.Services; + +public interface IConvertService +{ + public Task ConvertFilesAsync(IEnumerable files, string outputFolder); +} \ No newline at end of file diff --git a/src/Plpext/Plpext.UI/Services/IFileLoaderService.cs b/src/Plpext/Plpext.UI/Services/IFileLoaderService.cs new file mode 100644 index 0000000..729add5 --- /dev/null +++ b/src/Plpext/Plpext.UI/Services/IFileLoaderService.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Plpext.UI.ViewModels; + +namespace Plpext.UI.Services; + +public interface IFileLoaderService +{ + Task GetFileCountAsync(string filePath); + IAsyncEnumerable LoadFilesAsync(); +} \ No newline at end of file diff --git a/src/Plpext/Plpext.UI/Services/IPlatformStorageService.cs b/src/Plpext/Plpext.UI/Services/IPlatformStorageService.cs new file mode 100644 index 0000000..5b48b35 --- /dev/null +++ b/src/Plpext/Plpext.UI/Services/IPlatformStorageService.cs @@ -0,0 +1,9 @@ +using System.Threading.Tasks; + +namespace Plpext.UI.Services; + +public interface IPlatformStorageService +{ + Task GetOriginFilePath(); + Task GetTargetFolderPath(); +} \ No newline at end of file diff --git a/src/Plpext/Plpext.UI/Services/PlatformStorage/PlatformStorageService.cs b/src/Plpext/Plpext.UI/Services/PlatformStorage/PlatformStorageService.cs new file mode 100644 index 0000000..a980a6d --- /dev/null +++ b/src/Plpext/Plpext.UI/Services/PlatformStorage/PlatformStorageService.cs @@ -0,0 +1,48 @@ +using Avalonia; +using Avalonia.Controls.ApplicationLifetimes; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Avalonia.Platform.Storage; + +namespace Plpext.UI.Services.PlatformStorage +{ + public class PlatformStorageService : IPlatformStorageService + { + public async Task GetOriginFilePath() + { + if (Application.Current?.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop || + desktop.MainWindow?.StorageProvider is not { } provider) + return string.Empty; + + var filePath = await provider.OpenFilePickerAsync(new FilePickerOpenOptions() + { + AllowMultiple = false, + Title = "Select Plus Library Pack", + FileTypeFilter = [new ("Plus Library Pack"){Patterns = ["*.plp"]}], + }); + + return filePath.Any() ? filePath[0].Path.AbsolutePath : string.Empty; + } + + public async Task GetTargetFolderPath() + { + if (Application.Current?.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop || + desktop.MainWindow?.StorageProvider is not { } provider) + return string.Empty; + + var tentativeFolder = await provider.TryGetWellKnownFolderAsync(Avalonia.Platform.Storage.WellKnownFolder.Music); + + var outputPath = await provider.OpenFolderPickerAsync(new Avalonia.Platform.Storage.FolderPickerOpenOptions() + { + AllowMultiple = false, + Title = "Select output folder", + SuggestedStartLocation = tentativeFolder + }); + + return outputPath.Any() ? outputPath[0].Path.AbsolutePath : string.Empty; + } + } +} \ No newline at end of file diff --git a/src/Plpext/Plpext.UI/Styles/AudioPlayerControl.axaml b/src/Plpext/Plpext.UI/Styles/AudioPlayerControl.axaml new file mode 100644 index 0000000..5625227 --- /dev/null +++ b/src/Plpext/Plpext.UI/Styles/AudioPlayerControl.axaml @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Plpext/Plpext.UI/Styles/Border.axaml b/src/Plpext/Plpext.UI/Styles/Border.axaml new file mode 100644 index 0000000..8a8eb0c --- /dev/null +++ b/src/Plpext/Plpext.UI/Styles/Border.axaml @@ -0,0 +1,15 @@ + + + + + + + + + diff --git a/src/Plpext/Plpext.UI/Styles/Button.axaml b/src/Plpext/Plpext.UI/Styles/Button.axaml new file mode 100644 index 0000000..d27bedd --- /dev/null +++ b/src/Plpext/Plpext.UI/Styles/Button.axaml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Plpext/Plpext.UI/Views/MainWindow.axaml.cs b/src/Plpext/Plpext.UI/Views/MainWindow.axaml.cs new file mode 100644 index 0000000..ce4b0af --- /dev/null +++ b/src/Plpext/Plpext.UI/Views/MainWindow.axaml.cs @@ -0,0 +1,12 @@ +using Avalonia.Controls; + +namespace Plpext.UI.Views +{ + public partial class MainWindow : Window + { + public MainWindow() + { + InitializeComponent(); + } + } +} \ No newline at end of file diff --git a/src/Plpext/Plpext.UI/app.manifest b/src/Plpext/Plpext.UI/app.manifest new file mode 100644 index 0000000..0f9de7e --- /dev/null +++ b/src/Plpext/Plpext.UI/app.manifest @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + diff --git a/src/Plpext/Plpext.UI/velopack.json b/src/Plpext/Plpext.UI/velopack.json new file mode 100644 index 0000000..2aff6ab --- /dev/null +++ b/src/Plpext/Plpext.UI/velopack.json @@ -0,0 +1,6 @@ +{ + "version": "1.0.0", + "executable": "Plpext.exe", + "iconFile": "Assets/plpext.png", + "splashImage": "Assets/plpext.png" + } \ No newline at end of file diff --git a/src/Plpext/Plpext.sln b/src/Plpext/Plpext.sln new file mode 100644 index 0000000..bbf7cbf --- /dev/null +++ b/src/Plpext/Plpext.sln @@ -0,0 +1,62 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.12.35521.163 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Plpext.UI", "Plpext.UI\Plpext.UI.csproj", "{CEC79B8A-12B4-4649-B859-08051B00FA96}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Plpext.Core", "..\Plpext.Core\Plpext.Core.csproj", "{2A0B3CBC-C79F-4B19-93AE-BCEEE44BDAD2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Plpext.Core.Windows", "..\Plpext.Core.Windows\Plpext.Core.Windows.csproj", "{CEF95E1F-8E07-4B32-A5D9-EE980AF5FBC4}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {CEC79B8A-12B4-4649-B859-08051B00FA96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CEC79B8A-12B4-4649-B859-08051B00FA96}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CEC79B8A-12B4-4649-B859-08051B00FA96}.Debug|x64.ActiveCfg = Debug|x64 + {CEC79B8A-12B4-4649-B859-08051B00FA96}.Debug|x64.Build.0 = Debug|x64 + {CEC79B8A-12B4-4649-B859-08051B00FA96}.Debug|x86.ActiveCfg = Debug|x86 + {CEC79B8A-12B4-4649-B859-08051B00FA96}.Debug|x86.Build.0 = Debug|x86 + {CEC79B8A-12B4-4649-B859-08051B00FA96}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CEC79B8A-12B4-4649-B859-08051B00FA96}.Release|Any CPU.Build.0 = Release|Any CPU + {CEC79B8A-12B4-4649-B859-08051B00FA96}.Release|x64.ActiveCfg = Release|x64 + {CEC79B8A-12B4-4649-B859-08051B00FA96}.Release|x64.Build.0 = Release|x64 + {CEC79B8A-12B4-4649-B859-08051B00FA96}.Release|x86.ActiveCfg = Release|x86 + {CEC79B8A-12B4-4649-B859-08051B00FA96}.Release|x86.Build.0 = Release|x86 + {2A0B3CBC-C79F-4B19-93AE-BCEEE44BDAD2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2A0B3CBC-C79F-4B19-93AE-BCEEE44BDAD2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2A0B3CBC-C79F-4B19-93AE-BCEEE44BDAD2}.Debug|x64.ActiveCfg = Debug|x64 + {2A0B3CBC-C79F-4B19-93AE-BCEEE44BDAD2}.Debug|x64.Build.0 = Debug|x64 + {2A0B3CBC-C79F-4B19-93AE-BCEEE44BDAD2}.Debug|x86.ActiveCfg = Debug|x86 + {2A0B3CBC-C79F-4B19-93AE-BCEEE44BDAD2}.Debug|x86.Build.0 = Debug|x86 + {2A0B3CBC-C79F-4B19-93AE-BCEEE44BDAD2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2A0B3CBC-C79F-4B19-93AE-BCEEE44BDAD2}.Release|Any CPU.Build.0 = Release|Any CPU + {2A0B3CBC-C79F-4B19-93AE-BCEEE44BDAD2}.Release|x64.ActiveCfg = Release|x64 + {2A0B3CBC-C79F-4B19-93AE-BCEEE44BDAD2}.Release|x64.Build.0 = Release|x64 + {2A0B3CBC-C79F-4B19-93AE-BCEEE44BDAD2}.Release|x86.ActiveCfg = Release|x86 + {2A0B3CBC-C79F-4B19-93AE-BCEEE44BDAD2}.Release|x86.Build.0 = Release|x86 + {CEF95E1F-8E07-4B32-A5D9-EE980AF5FBC4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CEF95E1F-8E07-4B32-A5D9-EE980AF5FBC4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CEF95E1F-8E07-4B32-A5D9-EE980AF5FBC4}.Debug|x64.ActiveCfg = Debug|x64 + {CEF95E1F-8E07-4B32-A5D9-EE980AF5FBC4}.Debug|x64.Build.0 = Debug|x64 + {CEF95E1F-8E07-4B32-A5D9-EE980AF5FBC4}.Debug|x86.ActiveCfg = Debug|x86 + {CEF95E1F-8E07-4B32-A5D9-EE980AF5FBC4}.Debug|x86.Build.0 = Debug|x86 + {CEF95E1F-8E07-4B32-A5D9-EE980AF5FBC4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CEF95E1F-8E07-4B32-A5D9-EE980AF5FBC4}.Release|Any CPU.Build.0 = Release|Any CPU + {CEF95E1F-8E07-4B32-A5D9-EE980AF5FBC4}.Release|x64.ActiveCfg = Release|x64 + {CEF95E1F-8E07-4B32-A5D9-EE980AF5FBC4}.Release|x64.Build.0 = Release|x64 + {CEF95E1F-8E07-4B32-A5D9-EE980AF5FBC4}.Release|x86.ActiveCfg = Release|x86 + {CEF95E1F-8E07-4B32-A5D9-EE980AF5FBC4}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal