Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor after Avalonia migration #430

Merged
merged 14 commits into from
Apr 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 18,7 @@ env:

jobs:
format:
runs-on: windows-latest
runs-on: ubuntu-latest
timeout-minutes: 10

permissions:
Expand Down Expand Up @@ -63,6 63,7 @@ jobs:
-p:CSharpier_Bypass=true
--output YoutubeDownloader/bin/publish
--configuration Release
--use-current-runtime

- name: Upload artifacts
uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
Expand Down
8 changes: 4 additions & 4 deletions YoutubeDownloader.Core/Downloading/VideoDownloadOption.cs
Original file line number Diff line number Diff line change
@@ -1,7 1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Lazy;
using YoutubeDownloader.Core.Utils.Extensions;
using YoutubeExplode.Videos.Streams;

Expand All @@ -13,9 12,10 @@ public partial record VideoDownloadOption(
IReadOnlyList<IStreamInfo> StreamInfos
)
{
[Lazy]
public VideoQuality? VideoQuality =>
StreamInfos.OfType<IVideoStreamInfo>().MaxBy(s => s.VideoQuality)?.VideoQuality;
private readonly Lazy<VideoQuality?> _videoQualityLazy =
new(() => StreamInfos.OfType<IVideoStreamInfo>().MaxBy(s => s.VideoQuality)?.VideoQuality);

public VideoQuality? VideoQuality => _videoQualityLazy.Value;
}

public partial record VideoDownloadOption
Expand Down
3 changes: 1 addition & 2 deletions YoutubeDownloader.Core/Downloading/VideoDownloader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 15,7 @@ namespace YoutubeDownloader.Core.Downloading;

public class VideoDownloader(IReadOnlyList<Cookie>? initialCookies = null)
{
private readonly YoutubeClient _youtube =
new(Http.Client, initialCookies ?? Array.Empty<Cookie>());
private readonly YoutubeClient _youtube = new(Http.Client, initialCookies ?? []);

public async Task<IReadOnlyList<VideoDownloadOption>> GetDownloadOptionsAsync(
VideoId videoId,
Expand Down
3 changes: 0 additions & 3 deletions YoutubeDownloader.Core/FodyWeavers.xml

This file was deleted.

3 changes: 1 addition & 2 deletions YoutubeDownloader.Core/Resolving/QueryResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 16,7 @@ namespace YoutubeDownloader.Core.Resolving;

public class QueryResolver(IReadOnlyList<Cookie>? initialCookies = null)
{
private readonly YoutubeClient _youtube =
new(Http.Client, initialCookies ?? Array.Empty<Cookie>());
private readonly YoutubeClient _youtube = new(Http.Client, initialCookies ?? []);

public async Task<QueryResult> ResolveAsync(
string query,
Expand Down
5 changes: 4 additions & 1 deletion YoutubeDownloader.Core/Utils/PathEx.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 6,10 @@ namespace YoutubeDownloader.Core.Utils;

public static class PathEx
{
private static readonly HashSet<char> InvalidFileNameChars = [..Path.GetInvalidFileNameChars()];
private static readonly HashSet<char> InvalidFileNameChars =
[
.. Path.GetInvalidFileNameChars()
];

public static string EscapeFileName(string path)
{
Expand Down
7 changes: 3 additions & 4 deletions YoutubeDownloader.Core/YoutubeDownloader.Core.csproj
Original file line number Diff line number Diff line change
@@ -1,13 1,12 @@
<Project Sdk="Microsoft.NET.Sdk">

<ItemGroup>
<PackageReference Include="CSharpier.MsBuild" Version="0.27.0" PrivateAssets="all" />
<PackageReference Include="CSharpier.MsBuild" Version="0.28.0" PrivateAssets="all" />
<PackageReference Include="Gress" Version="2.1.1" />
<PackageReference Include="JsonExtensions" Version="1.2.0" />
<PackageReference Include="Lazy.Fody" Version="1.11.0" PrivateAssets="all" />
<PackageReference Include="TagLibSharp" Version="2.3.0" />
<PackageReference Include="YoutubeExplode" Version="6.3.12" />
<PackageReference Include="YoutubeExplode.Converter" Version="6.3.12" />
<PackageReference Include="YoutubeExplode" Version="6.3.13" />
<PackageReference Include="YoutubeExplode.Converter" Version="6.3.13" />
</ItemGroup>

</Project>
158 changes: 158 additions & 0 deletions YoutubeDownloader/App.axaml
Original file line number Diff line number Diff line change
@@ -0,0 1,158 @@
<Application
x:Class="YoutubeDownloader.App"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:dialogHostAvalonia="clr-namespace:DialogHostAvalonia;assembly=DialogHost.Avalonia"
xmlns:framework="clr-namespace:YoutubeDownloader.Framework"
xmlns:materialAssists="clr-namespace:Material.Styles.Assists;assembly=Material.Styles"
xmlns:materialControls="clr-namespace:Material.Styles.Controls;assembly=Material.Styles"
xmlns:materialIcons="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
xmlns:materialStyles="clr-namespace:Material.Styles.Themes;assembly=Material.Styles">
<Application.DataTemplates>
<framework:ViewManager />
</Application.DataTemplates>

<Application.Styles>
<materialStyles:MaterialTheme />
<materialIcons:MaterialIconStyles />
<dialogHostAvalonia:DialogHostStyles />

<!-- Combo box -->
<Style Selector="ComboBox">
<Setter Property="FontSize" Value="14" />

<Style Selector="^ /template/ Panel#PART_RootPanel">
<Setter Property="Height" Value="22" />
</Style>
</Style>

<!-- Context menu -->
<Style Selector="ContextMenu">
<Setter Property="BorderBrush" Value="{DynamicResource MaterialDividerBrush}" />
<Setter Property="BorderThickness" Value="1" />
</Style>

<!-- Data grid -->
<Style Selector="DataGrid">
<Setter Property="BorderBrush" Value="{DynamicResource MaterialDividerBrush}" />
<Setter Property="AutoGenerateColumns" Value="False" />
<Setter Property="CanUserReorderColumns" Value="False" />
<Setter Property="CanUserResizeColumns" Value="False" />
<Setter Property="CanUserSortColumns" Value="True" />
<Setter Property="IsReadOnly" Value="True" />
<Setter Property="SelectionMode" Value="Single" />
</Style>

<Style Selector="DataGridColumnHeader">
<Setter Property="AreSeparatorsVisible" Value="False" />
</Style>

<Style Selector="DataGridRow">
<Style Selector="^:selected /template/ Rectangle#BackgroundRectangle">
<Setter Property="IsVisible" Value="False" />
</Style>
<Style Selector="^:pointerover /template/ Rectangle#BackgroundRectangle">
<Setter Property="IsVisible" Value="False" />
</Style>
</Style>

<!-- Dialog host -->
<Style Selector="dialogHostAvalonia|DialogHost">
<Setter Property="DialogMargin" Value="0" />
</Style>

<Style Selector="dialogHostAvalonia|DialogOverlayPopupHost">
<Setter Property="Margin" Value="48" />
</Style>

<!-- Snack bar host -->
<Style Selector="materialControls|SnackbarHost">
<Setter Property="SnackbarHorizontalAlignment" Value="Stretch" />
<Setter Property="VerticalContentAlignment" Value="Center" />

<Style Selector="^ /template/ ItemsControl#PART_SnackbarHostItemsContainer materialControls|Card">
<Setter Property="Background" Value="{DynamicResource MaterialDarkBackgroundBrush}" />
<Setter Property="Foreground" Value="{DynamicResource MaterialDarkForegroundBrush}" />
</Style>

<Style Selector="^ /template/ ItemsControl#PART_SnackbarHostItemsContainer Button">
<Setter Property="Foreground" Value="{DynamicResource SecondaryHueMidBrush}" />
</Style>
</Style>

<!-- Progress bar -->
<Style Selector="ProgressBar">
<Setter Property="Minimum" Value="0" />
<Setter Property="Maximum" Value="1" />
<Setter Property="Foreground" Value="{DynamicResource MaterialSecondaryMidBrush}" />
<Setter Property="materialAssists:TransitionAssist.DisableTransitions" Value="True" />

<Style Selector="^:horizontal">
<Setter Property="MinHeight" Value="0" />
</Style>
</Style>

<!-- Slider -->
<Style Selector="Slider">
<Style Selector="^ /template/ ProgressBar#PART_ProgressLayer">
<Style Selector="^:horizontal">
<Style Selector="^ Panel#PART_InnerPanel">
<Setter Property="Height" Value="2" />

<Style Selector="^ Border#PART_InactiveState">
<Setter Property="Margin" Value="0" />
<Setter Property="Height" Value="2" />
</Style>

<Style Selector="^ Border#PART_Indicator">
<Setter Property="Margin" Value="0" />
</Style>
</Style>
</Style>
</Style>

<Style Selector="^ /template/ Track#PART_Track">
<Style Selector="^:horizontal">
<Setter Property="Margin" Value="4,0" />
</Style>

<Style Selector="^ Border#PART_HoverEffect">
<Setter Property="Width" Value="24" />
<Setter Property="Height" Value="24" />
</Style>

<Style Selector="^ Border#PART_ThumbGrip">
<Setter Property="Width" Value="12" />
<Setter Property="Height" Value="12" />
</Style>
</Style>
</Style>

<!-- Text box -->
<Style Selector="TextBox">
<Setter Property="Height" Value="22" />
<Setter Property="FontSize" Value="14" />

<Style Selector="^ /template/ Panel#PART_TextFieldPanel">
<Setter Property="MinHeight" Value="0" />
</Style>

<Style Selector="^ /template/ Panel#PART_TextContainer">
<Setter Property="Margin" Value="0" />
</Style>
</Style>

<!-- Tooltip -->
<Style Selector="ToolTip">
<Setter Property="TextElement.FontSize" Value="14" />
<Setter Property="TextElement.FontWeight" Value="Normal" />
<Setter Property="TextElement.FontStyle" Value="Normal" />
<Setter Property="TextElement.FontStretch" Value="Normal" />
</Style>

<!-- Toggle switch -->
<Style Selector="ToggleSwitch">
<Setter Property="materialAssists:ToggleSwitchAssist.SwitchThumbOffBackground" Value="{DynamicResource MaterialBackgroundBrush}" />
</Style>
</Application.Styles>
</Application>
131 changes: 131 additions & 0 deletions YoutubeDownloader/App.axaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 1,131 @@
using System;
using System.Net;
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
using Avalonia.Media;
using Avalonia.Platform;
using Avalonia.Styling;
using AvaloniaWebView;
using Material.Styles.Themes;
using Microsoft.Extensions.DependencyInjection;
using YoutubeDownloader.Framework;
using YoutubeDownloader.Services;
using YoutubeDownloader.ViewModels;
using YoutubeDownloader.ViewModels.Components;
using YoutubeDownloader.ViewModels.Dialogs;
using YoutubeDownloader.Views;

namespace YoutubeDownloader;

public partial class App : Application, IDisposable
{
private readonly ServiceProvider _services;
private readonly MainViewModel _mainViewModel;

public App()
{
var services = new ServiceCollection();

// Framework
services.AddSingleton<DialogManager>();
services.AddSingleton<SnackbarManager>();
services.AddSingleton<ViewManager>();
services.AddSingleton<ViewModelManager>();

// Services
services.AddSingleton<SettingsService>();
services.AddSingleton<UpdateService>();

// View models
services.AddTransient<MainViewModel>();
services.AddTransient<DashboardViewModel>();
services.AddTransient<DownloadViewModel>();
services.AddTransient<AuthSetupViewModel>();
services.AddTransient<DownloadMultipleSetupViewModel>();
services.AddTransient<DownloadSingleSetupViewModel>();
services.AddTransient<MessageBoxViewModel>();
services.AddTransient<SettingsViewModel>();

_services = services.BuildServiceProvider(true);
_mainViewModel = _services.GetRequiredService<ViewModelManager>().CreateMainViewModel();
}

public override void Initialize()
{
// Increase maximum concurrent connections
ServicePointManager.DefaultConnectionLimit = 20;

AvaloniaXamlLoader.Load(this);
}

public override void OnFrameworkInitializationCompleted()
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
desktop.MainWindow = new MainView { DataContext = _mainViewModel };

base.OnFrameworkInitializationCompleted();

// Set custom theme colors
SetDefaultTheme();
}

public override void RegisterServices()
{
base.RegisterServices();

AvaloniaWebViewBuilder.Initialize(config => config.IsInPrivateModeEnabled = true);
}

public void Dispose() => _services.Dispose();
}

public partial class App
{
public static void SetLightTheme()
{
if (Current is null)
return;

Current.LocateMaterialTheme<MaterialThemeBase>().CurrentTheme = Theme.Create(
Theme.Light,
Color.Parse("#343838"),
Color.Parse("#F9A825")
);

Current.Resources["SuccessBrush"] = new SolidColorBrush(Colors.DarkGreen);
Current.Resources["CanceledBrush"] = new SolidColorBrush(Colors.DarkOrange);
Current.Resources["FailedBrush"] = new SolidColorBrush(Colors.DarkRed);
}

public static void SetDarkTheme()
{
if (Current is null)
return;

Current.LocateMaterialTheme<MaterialThemeBase>().CurrentTheme = Theme.Create(
Theme.Dark,
Color.Parse("#E8E8E8"),
Color.Parse("#F9A825")
);

Current.Resources["SuccessBrush"] = new SolidColorBrush(Colors.LightGreen);
Current.Resources["CanceledBrush"] = new SolidColorBrush(Colors.Orange);
Current.Resources["FailedBrush"] = new SolidColorBrush(Colors.OrangeRed);
}

public static void SetDefaultTheme()
{
if (Current is null)
return;

var isDark = Current.RequestedThemeVariant is not null
? Current.RequestedThemeVariant == ThemeVariant.Dark
: Current.PlatformSettings?.GetColorValues().ThemeVariant == PlatformThemeVariant.Dark;

if (isDark)
SetDarkTheme();
else
SetLightTheme();
}
}
Loading