new_version_init
This commit is contained in:
@@ -0,0 +1,147 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection.Metadata.Ecma335;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using VDownload.GUI.Services.Dialog;
|
||||
using VDownload.GUI.Services.WebView;
|
||||
using VDownload.Sources.Twitch;
|
||||
using VDownload.Sources.Twitch.Authentication;
|
||||
|
||||
namespace VDownload.GUI.ViewModels
|
||||
{
|
||||
public partial class AuthenticationViewModel : ObservableObject
|
||||
{
|
||||
#region ENUMS
|
||||
|
||||
public enum AuthenticationButton
|
||||
{
|
||||
SignIn,
|
||||
SignOut,
|
||||
Loading
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region SERVICES
|
||||
|
||||
private IDialogService _dialogService;
|
||||
private IWebViewService _webViewService;
|
||||
private ITwitchAuthenticationService _twitchAuthenticationService;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region PROPERTIES
|
||||
|
||||
[ObservableProperty]
|
||||
private string _twitchDescription;
|
||||
|
||||
[ObservableProperty]
|
||||
private AuthenticationButton _twitchButtonState;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region CONSTRUCTORS
|
||||
|
||||
public AuthenticationViewModel(IDialogService dialogService, IWebViewService webViewService, ITwitchAuthenticationService twitchAuthenticationService)
|
||||
{
|
||||
_dialogService = dialogService;
|
||||
_webViewService = webViewService;
|
||||
_twitchAuthenticationService = twitchAuthenticationService;
|
||||
|
||||
TwitchButtonState = AuthenticationButton.Loading;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region PUBLIC METHODS
|
||||
|
||||
[RelayCommand]
|
||||
public async Task TwitchAuthentication()
|
||||
{
|
||||
AuthenticationButton state = TwitchButtonState;
|
||||
TwitchButtonState = AuthenticationButton.Loading;
|
||||
|
||||
if (state == AuthenticationButton.SignOut)
|
||||
{
|
||||
await _twitchAuthenticationService.DeleteToken();
|
||||
}
|
||||
else
|
||||
{
|
||||
string url = await _webViewService.Show(new Uri(_twitchAuthenticationService.AuthenticationPageUrl), _twitchAuthenticationService.AuthenticationPageClosePredicate, "Twitch authentication");
|
||||
|
||||
Match match = _twitchAuthenticationService.AuthenticationPageRedirectUrlRegex.Match(url);
|
||||
|
||||
if (match.Success)
|
||||
{
|
||||
string token = match.Groups[1].Value;
|
||||
await _twitchAuthenticationService.SetToken(Encoding.UTF8.GetBytes(token));
|
||||
}
|
||||
else
|
||||
{
|
||||
await _dialogService.ShowOk("Twitch authentication error", "An error occured");
|
||||
}
|
||||
}
|
||||
await TwitchAuthenticationRefresh();
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
public async Task Navigation()
|
||||
{
|
||||
List<Task> refreshTasks = new List<Task>
|
||||
{
|
||||
TwitchAuthenticationRefresh()
|
||||
};
|
||||
await Task.WhenAll(refreshTasks);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region PRIVATE METHODS
|
||||
|
||||
private async Task TwitchAuthenticationRefresh()
|
||||
{
|
||||
TwitchButtonState = AuthenticationButton.Loading;
|
||||
|
||||
byte[]? token = await _twitchAuthenticationService.GetToken();
|
||||
|
||||
if (token is null)
|
||||
{
|
||||
TwitchDescription = "You are not authenticated. Please sign in";
|
||||
TwitchButtonState = AuthenticationButton.SignIn;
|
||||
}
|
||||
else
|
||||
{
|
||||
TwitchValidationResult validationResult = await _twitchAuthenticationService.ValidateToken(token);
|
||||
if (validationResult.Success)
|
||||
{
|
||||
TwitchDescription = $"Signed in as {validationResult.TokenData.Login}. Expiration date: {validationResult.TokenData.ExpirationDate:dd.MM.yyyy HH:mm}";
|
||||
TwitchButtonState = AuthenticationButton.SignOut;
|
||||
}
|
||||
else
|
||||
{
|
||||
await _twitchAuthenticationService.DeleteToken();
|
||||
TwitchDescription = "Token expired or is invalid. Please log in again";
|
||||
TwitchButtonState = AuthenticationButton.SignIn;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
315
VDownload.GUI/VDownload.GUI.ViewModels/HomeViewModel.cs
Normal file
315
VDownload.GUI/VDownload.GUI.ViewModels/HomeViewModel.cs
Normal file
@@ -0,0 +1,315 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using VDownload.Common;
|
||||
using VDownload.Common.Exceptions;
|
||||
using VDownload.Common.Models;
|
||||
using VDownload.GUI.Services.StoragePicker;
|
||||
using VDownload.Services.Search;
|
||||
using VDownload.Tasks;
|
||||
|
||||
namespace VDownload.GUI.ViewModels
|
||||
{
|
||||
public partial class HomeViewModel : ObservableObject
|
||||
{
|
||||
#region ENUMS
|
||||
|
||||
public enum OptionBarContentType
|
||||
{
|
||||
None,
|
||||
VideoSearch,
|
||||
PlaylistSearch
|
||||
}
|
||||
|
||||
public enum MainContentType
|
||||
{
|
||||
Downloads,
|
||||
Video
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region SERVICES
|
||||
|
||||
private IStoragePickerService _storagePickerService;
|
||||
private ISearchService _searchService;
|
||||
private IDownloadTasksManager _tasksService;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region PROPERTIES
|
||||
|
||||
// MAIN
|
||||
|
||||
[ObservableProperty]
|
||||
private MainContentType _mainContent;
|
||||
|
||||
|
||||
// DOWNLOADS
|
||||
public ObservableCollection<DownloadTask> Tasks => _tasksService.Tasks;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _taskListIsEmpty;
|
||||
|
||||
|
||||
// VIDEO
|
||||
|
||||
[ObservableProperty]
|
||||
private DownloadTask _task;
|
||||
|
||||
|
||||
// OPTION BAR
|
||||
|
||||
[ObservableProperty]
|
||||
private OptionBarContentType _optionBarContent;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _optionBarMessage;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _optionBarLoading;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _optionBarVideoSearchButtonChecked;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _optionBarPlaylistSearchButtonChecked;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _optionBarSearchNotPending;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _optionBarVideoSearchTBValue;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _optionBarPlaylistSearchTBValue;
|
||||
|
||||
[ObservableProperty]
|
||||
private int _optionBarPlaylistSearchNBValue;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region CONSTRUCTORS
|
||||
|
||||
public HomeViewModel(IStoragePickerService storagePickerService, ISearchService searchService, IDownloadTasksManager tasksService)
|
||||
{
|
||||
_storagePickerService = storagePickerService;
|
||||
_searchService = searchService;
|
||||
_tasksService = tasksService;
|
||||
_tasksService.Tasks.CollectionChanged += Tasks_CollectionChanged;
|
||||
|
||||
_taskListIsEmpty = _tasksService.Tasks.Count == 0;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region COMMANDS
|
||||
|
||||
[RelayCommand]
|
||||
public void Navigation()
|
||||
{
|
||||
MainContent = MainContentType.Downloads;
|
||||
|
||||
OptionBarContent = OptionBarContentType.None;
|
||||
OptionBarMessage = null;
|
||||
OptionBarVideoSearchButtonChecked = false;
|
||||
OptionBarPlaylistSearchButtonChecked = false;
|
||||
OptionBarSearchNotPending = true;
|
||||
OptionBarVideoSearchTBValue = string.Empty;
|
||||
OptionBarPlaylistSearchNBValue = 1; // TODO: load from settings
|
||||
OptionBarPlaylistSearchTBValue = string.Empty;
|
||||
}
|
||||
|
||||
|
||||
// DOWNLOADS
|
||||
|
||||
[RelayCommand]
|
||||
public void StartCancelTask(DownloadTask task)
|
||||
{
|
||||
DownloadTaskStatus[] idleStatuses =
|
||||
[
|
||||
DownloadTaskStatus.Idle,
|
||||
DownloadTaskStatus.EndedUnsuccessfully,
|
||||
DownloadTaskStatus.EndedSuccessfully,
|
||||
DownloadTaskStatus.EndedCancelled
|
||||
];
|
||||
if (idleStatuses.Contains(task.Status))
|
||||
{
|
||||
task.Enqueue();
|
||||
}
|
||||
else
|
||||
{
|
||||
task.Cancel();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// VIDEO
|
||||
|
||||
[RelayCommand]
|
||||
public async Task Browse()
|
||||
{
|
||||
string? newDirectory = await _storagePickerService.OpenDirectory();
|
||||
if (newDirectory is not null)
|
||||
{
|
||||
Task.DirectoryPath = newDirectory;
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
public async Task CreateTask()
|
||||
{
|
||||
string extension = Task.MediaType switch
|
||||
{
|
||||
MediaType.OnlyAudio => Task.AudioExtension.ToString(),
|
||||
_ => Task.VideoExtension.ToString()
|
||||
};
|
||||
|
||||
Task.Filename = string.Join("_", Task.Filename.Split(Path.GetInvalidFileNameChars()));
|
||||
string file = $"{Task.Filename}.{extension}";
|
||||
string path = Path.Combine(Task.DirectoryPath, file);
|
||||
|
||||
await File.WriteAllBytesAsync(path, [0x00]);
|
||||
File.Delete(path);
|
||||
|
||||
_tasksService.AddTask(Task);
|
||||
|
||||
Navigation();
|
||||
}
|
||||
|
||||
|
||||
// OPTION BAR
|
||||
|
||||
[RelayCommand]
|
||||
public void LoadFromSubscription()
|
||||
{
|
||||
MainContent = MainContentType.Downloads;
|
||||
|
||||
OptionBarContent = OptionBarContentType.None;
|
||||
OptionBarVideoSearchButtonChecked = false;
|
||||
OptionBarPlaylistSearchButtonChecked = false;
|
||||
OptionBarSearchNotPending = false;
|
||||
|
||||
//TODO: Load videos
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
public void VideoSearchShow()
|
||||
{
|
||||
MainContent = MainContentType.Downloads;
|
||||
|
||||
if (OptionBarContent != OptionBarContentType.VideoSearch)
|
||||
{
|
||||
OptionBarContent = OptionBarContentType.VideoSearch;
|
||||
OptionBarPlaylistSearchButtonChecked = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
OptionBarContent = OptionBarContentType.None;
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
public void PlaylistSearchShow()
|
||||
{
|
||||
MainContent = MainContentType.Downloads;
|
||||
|
||||
if (OptionBarContent != OptionBarContentType.PlaylistSearch)
|
||||
{
|
||||
OptionBarContent = OptionBarContentType.PlaylistSearch;
|
||||
OptionBarVideoSearchButtonChecked = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
OptionBarContent = OptionBarContentType.None;
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
public async Task VideoSearchStart()
|
||||
{
|
||||
OptionBarSearchNotPending = false;
|
||||
OptionBarLoading = true;
|
||||
OptionBarMessage = "Loading...";
|
||||
|
||||
Video video;
|
||||
try
|
||||
{
|
||||
video = await _searchService.SearchVideo(OptionBarVideoSearchTBValue);
|
||||
}
|
||||
catch (MediaSearchException ex)
|
||||
{
|
||||
OptionBarLoading = false;
|
||||
OptionBarMessage = ex.Message;
|
||||
OptionBarSearchNotPending = true;
|
||||
return;
|
||||
}
|
||||
|
||||
Task = new DownloadTask(video);
|
||||
|
||||
MainContent = MainContentType.Video;
|
||||
|
||||
OptionBarSearchNotPending = true;
|
||||
OptionBarLoading = false;
|
||||
OptionBarMessage = null;
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
public async Task PlaylistSearchStart()
|
||||
{
|
||||
OptionBarSearchNotPending = false;
|
||||
OptionBarLoading = true;
|
||||
OptionBarMessage = "Loading...";
|
||||
|
||||
Playlist playlist;
|
||||
try
|
||||
{
|
||||
playlist = await _searchService.SearchPlaylist(OptionBarPlaylistSearchTBValue, OptionBarPlaylistSearchNBValue);
|
||||
}
|
||||
catch (MediaSearchException ex)
|
||||
{
|
||||
OptionBarLoading = false;
|
||||
OptionBarMessage = ex.Message;
|
||||
OptionBarSearchNotPending = true;
|
||||
return;
|
||||
}
|
||||
|
||||
OptionBarSearchNotPending = true;
|
||||
OptionBarLoading = false;
|
||||
OptionBarMessage = null;
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
public void Download()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region EVENT HANDLERS
|
||||
|
||||
private void Tasks_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
TaskListIsEmpty = Tasks.Count == 0;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
19
VDownload.GUI/VDownload.GUI.ViewModels/SettingsViewModel.cs
Normal file
19
VDownload.GUI/VDownload.GUI.ViewModels/SettingsViewModel.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace VDownload.GUI.ViewModels
|
||||
{
|
||||
public class SettingsViewModel
|
||||
{
|
||||
#region CONSTRUCTORS
|
||||
|
||||
public SettingsViewModel()
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0-windows10.0.19041.0</TargetFramework>
|
||||
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
|
||||
<RootNamespace>VDownload.GUI.ViewModels</RootNamespace>
|
||||
<RuntimeIdentifiers>win10-x86;win10-x64;win10-arm64</RuntimeIdentifiers>
|
||||
<UseWinUI>true</UseWinUI>
|
||||
<UseRidGraph>true</UseRidGraph>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2" />
|
||||
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.4.231219000" />
|
||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.2428" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\VDownload.Common\VDownload.Common.csproj" />
|
||||
<ProjectReference Include="..\..\VDownload.Services\VDownload.Services.Search\VDownload.Services.Search.csproj" />
|
||||
<ProjectReference Include="..\..\VDownload.Sources\VDownload.Sources.Twitch\VDownload.Sources.Twitch.Authentication\VDownload.Sources.Twitch.Authentication.csproj" />
|
||||
<ProjectReference Include="..\..\VDownload.Sources\VDownload.Sources.Twitch\VDownload.Sources.Twitch\VDownload.Sources.Twitch.csproj" />
|
||||
<ProjectReference Include="..\..\VDownload.Tasks\VDownload.Tasks.csproj" />
|
||||
<ProjectReference Include="..\VDownload.GUI.Services\VDownload.GUI.Services.Dialog\VDownload.GUI.Services.Dialog.csproj" />
|
||||
<ProjectReference Include="..\VDownload.GUI.Services\VDownload.GUI.Services.StoragePicker\VDownload.GUI.Services.StoragePicker.csproj" />
|
||||
<ProjectReference Include="..\VDownload.GUI.Services\VDownload.GUI.Services.WebView\VDownload.GUI.Services.WebView.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Reference in New Issue
Block a user