diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 645ff78..8889b5a 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -11,12 +11,12 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v1 with: - dotnet-version: 6.0.x + dotnet-version: 7.0.x - uses: actions/checkout@v2 - name: Publish win-x64 run: | dotnet publish -c Release -r win-x64 Outseek.AvaloniaClient -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true --no-self-contained - Move-Item -Path Outseek.AvaloniaClient/bin/Release/net6.0/win-x64/publish/Outseek.AvaloniaClient.exe -Destination Outseek.exe + Move-Item -Path Outseek.AvaloniaClient/bin/Release/net7.0/win-x64/publish/Outseek.AvaloniaClient.exe -Destination Outseek.exe - name: Upload win-x64 uses: actions/upload-artifact@v2 with: @@ -31,12 +31,12 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v1 with: - dotnet-version: 6.0.x + dotnet-version: 7.0.x - uses: actions/checkout@v2 - name: Publish linux-x64 run: | dotnet publish -c Release -r linux-x64 Outseek.AvaloniaClient -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true --no-self-contained - mv Outseek.AvaloniaClient/bin/Release/net6.0/linux-x64/publish/Outseek.AvaloniaClient Outseek + mv Outseek.AvaloniaClient/bin/Release/net7.0/linux-x64/publish/Outseek.AvaloniaClient Outseek - name: Upload linux-x64 uses: actions/upload-artifact@v2 with: diff --git a/Directory.Build.props b/Directory.Build.props index 7c299ae..8bce0d8 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,6 +1,6 @@ - net6.0 + net7.0 enable true true diff --git a/Outseek.AvaloniaClient/App.axaml b/Outseek.AvaloniaClient/App.axaml index 0c16d01..20edfb4 100644 --- a/Outseek.AvaloniaClient/App.axaml +++ b/Outseek.AvaloniaClient/App.axaml @@ -7,7 +7,7 @@ - + diff --git a/Outseek.AvaloniaClient/Controls/PropertyGrid/PropertyGrid.axaml.cs b/Outseek.AvaloniaClient/Controls/PropertyGrid/PropertyGrid.axaml.cs index a581f18..dbf0d7b 100644 --- a/Outseek.AvaloniaClient/Controls/PropertyGrid/PropertyGrid.axaml.cs +++ b/Outseek.AvaloniaClient/Controls/PropertyGrid/PropertyGrid.axaml.cs @@ -5,15 +5,14 @@ using Avalonia; using Avalonia.Controls; using Avalonia.Data; -using Avalonia.Markup.Xaml; namespace Outseek.AvaloniaClient.Controls.PropertyGrid; -public class PropertyGrid : UserControl +public partial class PropertyGrid : UserControl { public static readonly StyledProperty PropertyObjectProperty = AvaloniaProperty.Register( - nameof(PropertyObject), typeof(object), notifying: OnSelectedObjectChanged); + nameof(PropertyObject), typeof(object)); public object? PropertyObject { @@ -29,18 +28,14 @@ public PropertyGrid() { InitializeComponent(); - _gridMain = this.FindControl("GridMain"); - } + PropertyObjectProperty.Changed.Subscribe(OnSelectedObjectChanged); - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); + _gridMain = this.FindControl("GridMain")!; } - private static void OnSelectedObjectChanged(IAvaloniaObject sender, bool beforeChanging) + private void OnSelectedObjectChanged(AvaloniaPropertyChangedEventArgs propertyObjectChanged) { - if (beforeChanging) return; - if (sender is not PropertyGrid propGrid) return; + if (propertyObjectChanged.Sender is not PropertyGrid propGrid) return; propGrid.UpdatePropertyControls(); } diff --git a/Outseek.AvaloniaClient/Outseek.AvaloniaClient.csproj b/Outseek.AvaloniaClient/Outseek.AvaloniaClient.csproj index b44011a..d1cdf2b 100644 --- a/Outseek.AvaloniaClient/Outseek.AvaloniaClient.csproj +++ b/Outseek.AvaloniaClient/Outseek.AvaloniaClient.csproj @@ -1,28 +1,30 @@  WinExe + app.manifest - - - - - - - - + + + + + + + + + - + - - + + diff --git a/Outseek.AvaloniaClient/SharedViewModels/TimelineState.cs b/Outseek.AvaloniaClient/SharedViewModels/TimelineState.cs index e1345c4..8d9a797 100644 --- a/Outseek.AvaloniaClient/SharedViewModels/TimelineState.cs +++ b/Outseek.AvaloniaClient/SharedViewModels/TimelineState.cs @@ -39,7 +39,6 @@ public class TimelineState : ViewModelBase public double PlaybackPositionScaled => PlaybackPosition * DevicePixelsPerSecond - ScrollOffset * ScrollableWidth; public double EndScaled => End * DevicePixelsPerSecond; public Vector ScrollPositionScaled => new(ScrollOffset * ScrollableWidth, 0); - public Size ViewportWidthScaledAsSize => new(ViewportWidthScaled, 0); // // commands @@ -63,8 +62,6 @@ public TimelineState() .Subscribe(_ => this.RaisePropertyChanged(nameof(EndScaled))); this.WhenAnyValue(t => t.ScrollOffset, t => t.ScrollableWidth) .Subscribe(_ => this.RaisePropertyChanged(nameof(ScrollPositionScaled))); - this.WhenAnyValue(t => t.ViewportWidthScaled) - .Subscribe(_ => this.RaisePropertyChanged(nameof(ViewportWidthScaledAsSize))); Scroll = ReactiveCommand.Create((Vector delta) => { diff --git a/Outseek.AvaloniaClient/Utils/ChatDownloader.cs b/Outseek.AvaloniaClient/Utils/ChatDownloader.cs index 5b0d5c8..8632edf 100644 --- a/Outseek.AvaloniaClient/Utils/ChatDownloader.cs +++ b/Outseek.AvaloniaClient/Utils/ChatDownloader.cs @@ -53,13 +53,12 @@ public IAsyncEnumerable GetChat(string url, string cacheStorageDir) List messages = new(); - IntPtr state = PythonEngine.AcquireLock(); + Py.GILState gil = Py.GIL(); try { dynamic chat = _chatDownloaderModule.ChatDownloader().get_chat(url); dynamic builtins = Py.Import("builtins"); - PyObject keyError = builtins.KeyError; // this loop is not async, so it needs to be offloaded onto a thread to not block the caller. foreach (var message in chat) @@ -71,7 +70,7 @@ public IAsyncEnumerable GetChat(string url, string cacheStorageDir) foreach (var badge in author["badges"]) badges.Add(badge["title"].As()); } - catch (PythonException ex) when (ex.Type.Handle == keyError.Handle) + catch (PythonException ex) when (ex.Type == builtins.KeyError) { } @@ -98,20 +97,20 @@ public IAsyncEnumerable GetChat(string url, string cacheStorageDir) messages.Add(msg); // awaiting yields to god knows whose code, so release the GIL for its duration - PythonEngine.ReleaseLock(state); + gil.Dispose(); try { await channel.Writer.WriteAsync(msg); } finally { - state = PythonEngine.AcquireLock(); + gil = Py.GIL(); } } } finally { - PythonEngine.ReleaseLock(state); + gil.Dispose(); } // Successfully downloaded the entire chat. Cache it on disk so we don't have to do that again. diff --git a/Outseek.AvaloniaClient/ViewLocator.cs b/Outseek.AvaloniaClient/ViewLocator.cs index cf42816..39b2dd0 100644 --- a/Outseek.AvaloniaClient/ViewLocator.cs +++ b/Outseek.AvaloniaClient/ViewLocator.cs @@ -9,9 +9,9 @@ public class ViewLocator : IDataTemplate { public bool SupportsRecycling => false; - public IControl Build(object data) + public Control Build(object? data) { - var name = data.GetType().FullName!.Replace("ViewModel", "View"); + var name = data!.GetType().FullName!.Replace("ViewModel", "View"); var type = Type.GetType(name); if (type != null) @@ -24,7 +24,7 @@ public IControl Build(object data) } } - public bool Match(object data) + public bool Match(object? data) { return data is ViewModelBase; } diff --git a/Outseek.AvaloniaClient/ViewModels/VideoplayerViewModel.cs b/Outseek.AvaloniaClient/ViewModels/VideoplayerViewModel.cs index 570b482..60b1edd 100644 --- a/Outseek.AvaloniaClient/ViewModels/VideoplayerViewModel.cs +++ b/Outseek.AvaloniaClient/ViewModels/VideoplayerViewModel.cs @@ -1,13 +1,16 @@ using System; +using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reactive; using System.Reactive.Linq; using System.Runtime.InteropServices; using System.Threading; +using System.Threading.Tasks; using Avalonia; using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Platform.Storage; using LibVLCSharp.Avalonia; using LibVLCSharp.Shared; using MessageBox.Avalonia; @@ -83,13 +86,12 @@ public VideoplayerViewModel(TimelineState timelineState, MediaState mediaState) { Debug.Assert(Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime); Window mainWindow = ((IClassicDesktopStyleApplicationLifetime) Application.Current.ApplicationLifetime) - .MainWindow; - var fileDialog = new OpenFileDialog + .MainWindow!; + mainWindow.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions { AllowMultiple = false, Title = "Choose video file", - }; - fileDialog.ShowAsync(mainWindow).ContinueWith(async task => + }).ContinueWith(async task => { if (task.Exception != null) { @@ -99,9 +101,9 @@ public VideoplayerViewModel(TimelineState timelineState, MediaState mediaState) } else { - string[]? selectedFiles = task.Result; - if (selectedFiles?.Length > 0) - MediaState.Filename = selectedFiles[0]; + IReadOnlyList selectedFiles = task.Result; + if (selectedFiles.Count > 0) + MediaState.Filename = selectedFiles.First().Path.AbsolutePath; } }); }); diff --git a/Outseek.AvaloniaClient/ViewModels/WorkingAreaToolsViewModel.cs b/Outseek.AvaloniaClient/ViewModels/WorkingAreaToolsViewModel.cs index b5e2453..7d6dd76 100644 --- a/Outseek.AvaloniaClient/ViewModels/WorkingAreaToolsViewModel.cs +++ b/Outseek.AvaloniaClient/ViewModels/WorkingAreaToolsViewModel.cs @@ -5,6 +5,7 @@ using Avalonia; using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Platform.Storage; using MessageBox.Avalonia; using MessageBox.Avalonia.Enums; using Outseek.AvaloniaClient.SharedViewModels; @@ -30,14 +31,13 @@ public WorkingAreaToolsViewModel(WorkingAreaViewModel workingAreaViewModel, Medi IObservable otioAvailable = this.WhenAnyValue(vm => vm.Otio).Select(otio => otio != null); Export = ReactiveCommand.Create(() => { - Window mainWindow = ((IClassicDesktopStyleApplicationLifetime)Application.Current!.ApplicationLifetime!).MainWindow; - var fileDialog = new SaveFileDialog + Window mainWindow = ((IClassicDesktopStyleApplicationLifetime)Application.Current!.ApplicationLifetime!).MainWindow!; + mainWindow.StorageProvider.SaveFilePickerAsync(new FilePickerSaveOptions() { DefaultExtension = ".otio", - InitialFileName = "my_highlights.otio", + SuggestedFileName = "my_highlights.otio", Title = "Choose file to save to", - }; - fileDialog.ShowAsync(mainWindow).ContinueWith(async task => + }).ContinueWith(async task => { if (task.Exception != null) { @@ -47,11 +47,11 @@ public WorkingAreaToolsViewModel(WorkingAreaViewModel workingAreaViewModel, Medi } else { - string? selectedFile = task.Result; + IStorageFile? selectedFile = task.Result; if (selectedFile != null && mediaState.Filename != null) Otio?.SaveSegments( mediaState.Filename, - selectedFile, + selectedFile.Path.AbsolutePath, workingAreaViewModel.WorkingAreaState.Segments.Select(r => r.Range)); } }); diff --git a/Outseek.AvaloniaClient/Views/MainWindow.axaml.cs b/Outseek.AvaloniaClient/Views/MainWindow.axaml.cs index e199a2e..bc9442f 100644 --- a/Outseek.AvaloniaClient/Views/MainWindow.axaml.cs +++ b/Outseek.AvaloniaClient/Views/MainWindow.axaml.cs @@ -5,19 +5,11 @@ namespace Outseek.AvaloniaClient.Views; -public class MainWindow : Window +public partial class MainWindow : Window { public MainWindow() { DataContext = new MainWindowViewModel(); InitializeComponent(); -#if DEBUG - this.AttachDevTools(); -#endif - } - - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); } } diff --git a/Outseek.AvaloniaClient/Views/TimelineObjectView.axaml.cs b/Outseek.AvaloniaClient/Views/TimelineObjectView.axaml.cs index 396b93d..56f00bc 100644 --- a/Outseek.AvaloniaClient/Views/TimelineObjectView.axaml.cs +++ b/Outseek.AvaloniaClient/Views/TimelineObjectView.axaml.cs @@ -3,15 +3,10 @@ namespace Outseek.AvaloniaClient.Views; -public class TimelineObjectView : UserControl +public partial class TimelineObjectView : UserControl { public TimelineObjectView() { InitializeComponent(); } - - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); - } } diff --git a/Outseek.AvaloniaClient/Views/TimelineObjects/ErrorView.axaml.cs b/Outseek.AvaloniaClient/Views/TimelineObjects/ErrorView.axaml.cs index 47f2d65..888fbd6 100644 --- a/Outseek.AvaloniaClient/Views/TimelineObjects/ErrorView.axaml.cs +++ b/Outseek.AvaloniaClient/Views/TimelineObjects/ErrorView.axaml.cs @@ -3,15 +3,10 @@ namespace Outseek.AvaloniaClient.Views.TimelineObjects; -public class ErrorView : UserControl +public partial class ErrorView : UserControl { public ErrorView() { InitializeComponent(); } - - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); - } } diff --git a/Outseek.AvaloniaClient/Views/TimelineObjects/NothingView.axaml.cs b/Outseek.AvaloniaClient/Views/TimelineObjects/NothingView.axaml.cs index aee3e5f..0b1ff71 100644 --- a/Outseek.AvaloniaClient/Views/TimelineObjects/NothingView.axaml.cs +++ b/Outseek.AvaloniaClient/Views/TimelineObjects/NothingView.axaml.cs @@ -3,15 +3,10 @@ namespace Outseek.AvaloniaClient.Views.TimelineObjects; -public class NothingView : UserControl +public partial class NothingView : UserControl { public NothingView() { InitializeComponent(); } - - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); - } } diff --git a/Outseek.AvaloniaClient/Views/TimelineObjects/SegmentsView.axaml b/Outseek.AvaloniaClient/Views/TimelineObjects/SegmentsView.axaml index 66b1975..561922e 100644 --- a/Outseek.AvaloniaClient/Views/TimelineObjects/SegmentsView.axaml +++ b/Outseek.AvaloniaClient/Views/TimelineObjects/SegmentsView.axaml @@ -11,7 +11,7 @@ - + diff --git a/Outseek.AvaloniaClient/Views/TimelineProcessorExplorerView.axaml.cs b/Outseek.AvaloniaClient/Views/TimelineProcessorExplorerView.axaml.cs index 8bb2b29..907f425 100644 --- a/Outseek.AvaloniaClient/Views/TimelineProcessorExplorerView.axaml.cs +++ b/Outseek.AvaloniaClient/Views/TimelineProcessorExplorerView.axaml.cs @@ -2,23 +2,17 @@ using Avalonia; using Avalonia.Controls; using Avalonia.Input; -using Avalonia.Markup.Xaml; using Outseek.API; namespace Outseek.AvaloniaClient.Views; -public class TimelineProcessorExplorerView : UserControl +public partial class TimelineProcessorExplorerView : UserControl { public TimelineProcessorExplorerView() { InitializeComponent(); } - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); - } - private void OnTimelineProcessorItemPointerPressed(object? sender, PointerPressedEventArgs e) { var draggedElement = sender as StyledElement; diff --git a/Outseek.AvaloniaClient/Views/TimelineProcessorInfoView.axaml.cs b/Outseek.AvaloniaClient/Views/TimelineProcessorInfoView.axaml.cs index 78e6fa7..73c4cc4 100644 --- a/Outseek.AvaloniaClient/Views/TimelineProcessorInfoView.axaml.cs +++ b/Outseek.AvaloniaClient/Views/TimelineProcessorInfoView.axaml.cs @@ -3,15 +3,10 @@ namespace Outseek.AvaloniaClient.Views; -public class TimelineProcessorInfoView : UserControl +public partial class TimelineProcessorInfoView : UserControl { public TimelineProcessorInfoView() { InitializeComponent(); } - - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); - } } diff --git a/Outseek.AvaloniaClient/Views/TimelineProcessorObjectView.axaml b/Outseek.AvaloniaClient/Views/TimelineProcessorObjectView.axaml index 6aff925..1acaf94 100644 --- a/Outseek.AvaloniaClient/Views/TimelineProcessorObjectView.axaml +++ b/Outseek.AvaloniaClient/Views/TimelineProcessorObjectView.axaml @@ -12,7 +12,6 @@ diff --git a/Outseek.AvaloniaClient/Views/TimelineProcessorObjectView.axaml.cs b/Outseek.AvaloniaClient/Views/TimelineProcessorObjectView.axaml.cs index d851ab1..f67426b 100644 --- a/Outseek.AvaloniaClient/Views/TimelineProcessorObjectView.axaml.cs +++ b/Outseek.AvaloniaClient/Views/TimelineProcessorObjectView.axaml.cs @@ -3,15 +3,10 @@ namespace Outseek.AvaloniaClient.Views; -public class TimelineProcessorObjectView : UserControl +public partial class TimelineProcessorObjectView : UserControl { public TimelineProcessorObjectView() { InitializeComponent(); } - - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); - } } diff --git a/Outseek.AvaloniaClient/Views/TimelineProcessorParamsView.axaml.cs b/Outseek.AvaloniaClient/Views/TimelineProcessorParamsView.axaml.cs index 3a801e0..a042157 100644 --- a/Outseek.AvaloniaClient/Views/TimelineProcessorParamsView.axaml.cs +++ b/Outseek.AvaloniaClient/Views/TimelineProcessorParamsView.axaml.cs @@ -5,18 +5,13 @@ namespace Outseek.AvaloniaClient.Views; -public class TimelineProcessorParamsView : UserControl +public partial class TimelineProcessorParamsView : UserControl { public TimelineProcessorParamsView() { InitializeComponent(); } - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); - } - private void PropertyGrid_OnPropertyObjectChanged(object? sender, EventArgs e) { // TODO avoid wiring this up in code behind diff --git a/Outseek.AvaloniaClient/Views/TimelineView.axaml b/Outseek.AvaloniaClient/Views/TimelineView.axaml index c824151..dcb2ae1 100644 --- a/Outseek.AvaloniaClient/Views/TimelineView.axaml +++ b/Outseek.AvaloniaClient/Views/TimelineView.axaml @@ -55,7 +55,7 @@ DragDropEffect="Copy" DropAllowed="{Binding CheckDropAllowed}" /> - @@ -82,20 +82,9 @@ - - - - - - - - - - - -