From 1b0c1954527c376c2568518c31887de44c058620 Mon Sep 17 00:00:00 2001 From: Michael Gordeev Date: Sat, 9 May 2020 17:11:43 +0300 Subject: [PATCH] Basic visual interactions. Torrent client (non-functional) --- Wintor/WinTorrent.sln | 4 + .../WinTorrent/Dialogs/AddTorrentDialog.xaml | 36 +- .../Dialogs/AddTorrentDialog.xaml.cs | 116 +++++- Wintor/WinTorrent/Models/DataSize.cs | 63 --- .../Models/PointerHoverStateTrigger.cs | 7 +- Wintor/WinTorrent/Models/TorrentItem.cs | 133 ------ .../WinTorrent/Models/TorrentMetadataInfo.cs | 10 + .../Models/TorrentStateDataTrigger.cs | 46 --- .../Models/TorrentStateValuesEntry.cs | 16 + Wintor/WinTorrent/Package.appxmanifest | 6 +- Wintor/WinTorrent/Pages/MainPage.xaml | 221 ++-------- Wintor/WinTorrent/Pages/MainPage.xaml.cs | 41 +- .../Pages/TorrentDetailsPage.xaml.cs | 7 +- Wintor/WinTorrent/Utils/Settings.cs | 2 +- Wintor/WinTorrent/Utils/TorrentClient.cs | 385 +++++++++++++----- .../EstimatesValueConverter.cs | 25 ++ .../TorrentStateValueConverter.cs | 143 +++++++ Wintor/WinTorrent/WinTorrent.csproj | 10 +- 18 files changed, 701 insertions(+), 570 deletions(-) delete mode 100644 Wintor/WinTorrent/Models/DataSize.cs delete mode 100644 Wintor/WinTorrent/Models/TorrentItem.cs create mode 100644 Wintor/WinTorrent/Models/TorrentMetadataInfo.cs delete mode 100644 Wintor/WinTorrent/Models/TorrentStateDataTrigger.cs create mode 100644 Wintor/WinTorrent/Models/TorrentStateValuesEntry.cs create mode 100644 Wintor/WinTorrent/ValueConverters/EstimatesValueConverter.cs create mode 100644 Wintor/WinTorrent/ValueConverters/TorrentStateValueConverter.cs diff --git a/Wintor/WinTorrent.sln b/Wintor/WinTorrent.sln index a8a57f4..7d2bb15 100644 --- a/Wintor/WinTorrent.sln +++ b/Wintor/WinTorrent.sln @@ -7,16 +7,19 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WinTorrent", "WinTorrent\Wi EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU Debug|ARM = Debug|ARM Debug|ARM64 = Debug|ARM64 Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU Release|ARM = Release|ARM Release|ARM64 = Release|ARM64 Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution + {88F8E34F-0129-4856-A1F7-4A89DA892C9B}.Debug|Any CPU.ActiveCfg = Debug|x86 {88F8E34F-0129-4856-A1F7-4A89DA892C9B}.Debug|ARM.ActiveCfg = Debug|ARM {88F8E34F-0129-4856-A1F7-4A89DA892C9B}.Debug|ARM.Build.0 = Debug|ARM {88F8E34F-0129-4856-A1F7-4A89DA892C9B}.Debug|ARM.Deploy.0 = Debug|ARM @@ -29,6 +32,7 @@ Global {88F8E34F-0129-4856-A1F7-4A89DA892C9B}.Debug|x86.ActiveCfg = Debug|x86 {88F8E34F-0129-4856-A1F7-4A89DA892C9B}.Debug|x86.Build.0 = Debug|x86 {88F8E34F-0129-4856-A1F7-4A89DA892C9B}.Debug|x86.Deploy.0 = Debug|x86 + {88F8E34F-0129-4856-A1F7-4A89DA892C9B}.Release|Any CPU.ActiveCfg = Release|x86 {88F8E34F-0129-4856-A1F7-4A89DA892C9B}.Release|ARM.ActiveCfg = Release|ARM {88F8E34F-0129-4856-A1F7-4A89DA892C9B}.Release|ARM.Build.0 = Release|ARM {88F8E34F-0129-4856-A1F7-4A89DA892C9B}.Release|ARM.Deploy.0 = Release|ARM diff --git a/Wintor/WinTorrent/Dialogs/AddTorrentDialog.xaml b/Wintor/WinTorrent/Dialogs/AddTorrentDialog.xaml index 3f824bf..c20492e 100644 --- a/Wintor/WinTorrent/Dialogs/AddTorrentDialog.xaml +++ b/Wintor/WinTorrent/Dialogs/AddTorrentDialog.xaml @@ -2,16 +2,38 @@ x:Class="WinTorrent.Dialogs.AddTorrentDialog" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - xmlns:local="using:WinTorrent.Dialogs" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" - Title="TITLE" - PrimaryButtonText="Button1" - SecondaryButtonText="Button2" + Title="Add new torrent" + PrimaryButtonText="Add" + CloseButtonText="Cancel" + DefaultButton="Primary" + IsPrimaryButtonEnabled="False" PrimaryButtonClick="ContentDialog_PrimaryButtonClick" - SecondaryButtonClick="ContentDialog_SecondaryButtonClick"> + Loaded="ContentDialog_Loaded"> - - + + + + + + + + + - + diff --git a/Wintor/WinTorrent/Pages/MainPage.xaml.cs b/Wintor/WinTorrent/Pages/MainPage.xaml.cs index 49c1221..998d1a7 100644 --- a/Wintor/WinTorrent/Pages/MainPage.xaml.cs +++ b/Wintor/WinTorrent/Pages/MainPage.xaml.cs @@ -1,10 +1,13 @@ -using System; +using MonoTorrent.Client; +using System; +using System.IO; +using Windows.Storage; +using Windows.System; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Media.Animation; using Windows.UI.Xaml.Navigation; using WinTorrent.Dialogs; -using WinTorrent.Models; using WinTorrent.Utils; namespace WinTorrent.Pages @@ -19,7 +22,9 @@ namespace WinTorrent.Pages search.Translation += new System.Numerics.Vector3(0, 0, 10); navigationList.SelectedIndex = 0; - TorrentClient.TorrentItemStateChanged += (s, e) => NavigationViewList_SelectionChanged(this, null); + + //File.Create("E://FUCKYOU.txt"); + //File.WriteAllText("E://FUCKYOU.txt", "FUCK YOU!"); } protected override void OnNavigatedTo(NavigationEventArgs e) @@ -32,17 +37,27 @@ namespace WinTorrent.Pages private void OpenSettings(object sender, Windows.UI.Xaml.Input.TappedRoutedEventArgs e) => Frame.Navigate(typeof(SettingsPage), null, new SlideNavigationTransitionInfo { Effect = SlideNavigationTransitionEffect.FromLeft }); - private async void AddTorrent(object sender, Windows.UI.Xaml.Input.TappedRoutedEventArgs e) => - await new AddTorrentDialog().ShowAsync(); + private async void AddTorrent(object sender, Windows.UI.Xaml.Input.TappedRoutedEventArgs e) + { + AddTorrentDialog addDialog = new AddTorrentDialog(); + await addDialog.ShowAsync(); + + if (addDialog.Torrent == null) + return; + + TorrentClient.AddTorrent(addDialog.Torrent, addDialog.DestinationFolder); + + // TODO: Configure torrent + } private void NavigationViewList_SelectionChanged(object sender, SelectionChangedEventArgs e) { list.ItemsSource = (navigationList.SelectedItem as NavigationViewItem)?.Tag as string switch { - "downloading" => TorrentClient.Torrents.FindAll(i => i.State.BelongsTo(TorrentState.Downloading, TorrentState.Cancelling, TorrentState.Error, TorrentState.Initializing, TorrentState.Pausing)), + "downloading" => TorrentClient.Torrents.FindAll(i => i.State.BelongsTo(TorrentState.Downloading, TorrentState.Hashing, TorrentState.Error, TorrentState.Metadata, TorrentState.Starting, TorrentState.Stopping)), "seeding" => TorrentClient.Torrents.FindAll(i => i.State.BelongsTo(TorrentState.Seeding)), - "completed" => TorrentClient.Torrents.FindAll(i => i.State.BelongsTo(TorrentState.Completed, TorrentState.Seeding)), - "paused" => TorrentClient.Torrents.FindAll(i => i.State.BelongsTo(TorrentState.Paused, TorrentState.Resuming)), + "completed" => TorrentClient.Torrents.FindAll(i => i.State.BelongsTo(TorrentState.Stopped, TorrentState.Seeding)), + "paused" => TorrentClient.Torrents.FindAll(i => i.State.BelongsTo(TorrentState.Paused, TorrentState.HashingPaused)), _ => TorrentClient.Torrents }; search.ItemsSource = null; @@ -56,8 +71,8 @@ namespace WinTorrent.Pages sender.ItemsSource = null; navigationList.SelectedIndex = 0; var result = TorrentClient.Torrents.FindAll(i => - i.Title.ToLowerInvariant().Contains(sender.Text.ToLowerInvariant()) || - (i.Files?.Path.ToLowerInvariant().Contains(sender.Text.ToLowerInvariant()) ?? false) || + i.Torrent.Name.ToLowerInvariant().Contains(sender.Text.ToLowerInvariant()) || + (i?.SavePath.ToLowerInvariant().Contains(sender.Text.ToLowerInvariant()) ?? false) || i.State.ToString().ToLowerInvariant().Contains(sender.Text.ToLowerInvariant())); list.ItemsSource = result; @@ -88,12 +103,12 @@ namespace WinTorrent.Pages } private void list_ItemClick(object sender, ItemClickEventArgs e) => - OpenItem(e.ClickedItem as TorrentItem); + OpenItem(e.ClickedItem as TorrentManager); private void ViewItem(object sender, RoutedEventArgs e) => - OpenItem(list.ItemFromContainer(((sender as FrameworkElement).Parent as FrameworkElement).Parent) as TorrentItem); + OpenItem(list.ItemFromContainer(((sender as FrameworkElement).Parent as FrameworkElement).Parent) as TorrentManager); - private void OpenItem(TorrentItem item) + private void OpenItem(TorrentManager item) { if (list.ContainerFromItem(item) as ListViewItem != null) list.PrepareConnectedAnimation("ca1", item, "caTarget"); diff --git a/Wintor/WinTorrent/Pages/TorrentDetailsPage.xaml.cs b/Wintor/WinTorrent/Pages/TorrentDetailsPage.xaml.cs index 4526af9..1c885ed 100644 --- a/Wintor/WinTorrent/Pages/TorrentDetailsPage.xaml.cs +++ b/Wintor/WinTorrent/Pages/TorrentDetailsPage.xaml.cs @@ -1,4 +1,5 @@ -using Windows.UI.Xaml; +using MonoTorrent.Client; +using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Media.Animation; using Windows.UI.Xaml.Navigation; @@ -8,7 +9,7 @@ namespace WinTorrent.Pages { public sealed partial class TorrentDetailsPage : Page { - public TorrentItem Item { get; private set; } + public TorrentManager Item { get; private set; } public TorrentDetailsPage() { @@ -20,7 +21,7 @@ namespace WinTorrent.Pages { base.OnNavigatedTo(e); - Item = e.Parameter as TorrentItem; + Item = e.Parameter as TorrentManager; if (ConnectedAnimationService.GetForCurrentView().GetAnimation("ca1") is ConnectedAnimation animation) animation.TryStart(caTarget); diff --git a/Wintor/WinTorrent/Utils/Settings.cs b/Wintor/WinTorrent/Utils/Settings.cs index 125c1dc..624713c 100644 --- a/Wintor/WinTorrent/Utils/Settings.cs +++ b/Wintor/WinTorrent/Utils/Settings.cs @@ -62,7 +62,7 @@ namespace WinTorrent.Utils public static async Task GetDefaultFolder() { if (string.IsNullOrWhiteSpace(DefaultFolder)) - return await DownloadsFolder.CreateFolderAsync(Package.Current.DisplayName, CreationCollisionOption.OpenIfExists); + return null; else return await StorageApplicationPermissions.FutureAccessList.GetFolderAsync(DefaultFolder); } diff --git a/Wintor/WinTorrent/Utils/TorrentClient.cs b/Wintor/WinTorrent/Utils/TorrentClient.cs index dc96393..0633731 100644 --- a/Wintor/WinTorrent/Utils/TorrentClient.cs +++ b/Wintor/WinTorrent/Utils/TorrentClient.cs @@ -1,140 +1,317 @@ -using System; +using MonoTorrent; +using MonoTorrent.BEncoding; +using MonoTorrent.Client; +using Newtonsoft.Json; +using System; using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Security.Cryptography; +using System.Threading; +using System.Threading.Tasks; +using Windows.Storage; +using Windows.Storage.AccessCache; +using Windows.UI.Xaml.Controls; using WinTorrent.Models; namespace WinTorrent.Utils { - public delegate void TorrentStateChangedEventHandler(TorrentItem sender, TorrentState previousState); - public static class TorrentClient { - public static event TorrentStateChangedEventHandler TorrentItemStateChanged; + private static ApplicationDataContainer LocalSettings { get; } = ApplicationData.Current.LocalSettings; + private static StorageFolder LocalStorage { get; } = ApplicationData.Current.LocalFolder; - public static List Torrents { get; } + private static ClientEngine Engine { get; set; } + public static EngineSettings Settings => Engine?.Settings; + + public static List Torrents { get; } = new List(); + + private static BEncodedDictionary FastResumeData { get; set; } = new BEncodedDictionary(); + private static List TorrentsMetadata { get; set; } static TorrentClient() { - Torrents = new List + #region TestData + //Torrents = new List + //{ + // new TorrentItem + // { + // Title = "Microsoft Edge", + // TotalSize = new DataSize(3221225472), + // Downloaded = new DataSize(125829120), + // TransmissionSpeed = new DownloadSpeed(33554432), + // RemainingTime = TimeSpan.FromSeconds(36), + // State = Models.TorrentState.Downloading, + // SeedCount = 15 + // }, + // new TorrentItem + // { + // Title = "Microsoft Edge", + // TotalSize = new DataSize(3221225472), + // Downloaded = new DataSize(125829120), + // TransmissionSpeed = new DownloadSpeed(33554432), + // RemainingTime = TimeSpan.FromSeconds(36), + // State = Models.TorrentState.Completed, + // SeedCount = 15 + // }, + // new TorrentItem + // { + // Title = "Microsoft Edge", + // TotalSize = new DataSize(3221225472), + // Downloaded = new DataSize(125829120), + // TransmissionSpeed = new DownloadSpeed(33554432), + // RemainingTime = TimeSpan.FromSeconds(36), + // State = Models.TorrentState.Paused, + // SeedCount = 15 + // }, + // new TorrentItem + // { + // Title = "Microsoft Edge", + // TotalSize = new DataSize(3221225472), + // Downloaded = new DataSize(125829120), + // TransmissionSpeed = new DownloadSpeed(33554432), + // RemainingTime = TimeSpan.FromSeconds(36), + // State = Models.TorrentState.Seeding, + // SeedCount = 15 + // }, + // new TorrentItem + // { + // Title = "Microsoft Edge", + // TotalSize = new DataSize(3221225472), + // Downloaded = new DataSize(125829120), + // TransmissionSpeed = new DownloadSpeed(33554432), + // RemainingTime = TimeSpan.FromSeconds(36), + // State = Models.TorrentState.Cancelling, + // SeedCount = 15 + // }, + // new TorrentItem + // { + // Title = "Microsoft Edge", + // TotalSize = new DataSize(3221225472), + // Downloaded = new DataSize(125829120), + // TransmissionSpeed = new DownloadSpeed(33554432), + // RemainingTime = TimeSpan.FromSeconds(36), + // State = Models.TorrentState.Initializing, + // SeedCount = 15 + // }, + // new TorrentItem + // { + // Title = "Microsoft Edge", + // TotalSize = new DataSize(3221225472), + // Downloaded = new DataSize(125829120), + // TransmissionSpeed = new DownloadSpeed(33554432), + // RemainingTime = TimeSpan.FromSeconds(36), + // State = Models.TorrentState.Pausing, + // SeedCount = 15 + // }, + // new TorrentItem + // { + // Title = "Microsoft Edge", + // TotalSize = new DataSize(3221225472), + // Downloaded = new DataSize(125829120), + // TransmissionSpeed = new DownloadSpeed(33554432), + // RemainingTime = TimeSpan.FromSeconds(36), + // State = Models.TorrentState.Resuming, + // SeedCount = 15 + // }, + // new TorrentItem + // { + // Title = "Microsoft Edge", + // TotalSize = new DataSize(3221225472), + // Downloaded = new DataSize(125829120), + // TransmissionSpeed = new DownloadSpeed(33554432), + // RemainingTime = TimeSpan.FromSeconds(36), + // State = Models.TorrentState.Error, + // SeedCount = 15 + // } + //}; + #endregion + + EngineSettings engineSettings = new EngineSettings { - new TorrentItem - { - Title = "Microsoft Edge", - TotalSize = new DataSize(3221225472), - Downloaded = new DataSize(125829120), - TransmissionSpeed = new DownloadSpeed(33554432), - RemainingTime = TimeSpan.FromSeconds(36), - State = TorrentState.Downloading, - SeedCount = 15 - }, - new TorrentItem - { - Title = "Microsoft Edge", - TotalSize = new DataSize(3221225472), - Downloaded = new DataSize(125829120), - TransmissionSpeed = new DownloadSpeed(33554432), - RemainingTime = TimeSpan.FromSeconds(36), - State = TorrentState.Completed, - SeedCount = 15 - }, - new TorrentItem - { - Title = "Microsoft Edge", - TotalSize = new DataSize(3221225472), - Downloaded = new DataSize(125829120), - TransmissionSpeed = new DownloadSpeed(33554432), - RemainingTime = TimeSpan.FromSeconds(36), - State = TorrentState.Paused, - SeedCount = 15 - }, - new TorrentItem - { - Title = "Microsoft Edge", - TotalSize = new DataSize(3221225472), - Downloaded = new DataSize(125829120), - TransmissionSpeed = new DownloadSpeed(33554432), - RemainingTime = TimeSpan.FromSeconds(36), - State = TorrentState.Seeding, - SeedCount = 15 - }, - new TorrentItem - { - Title = "Microsoft Edge", - TotalSize = new DataSize(3221225472), - Downloaded = new DataSize(125829120), - TransmissionSpeed = new DownloadSpeed(33554432), - RemainingTime = TimeSpan.FromSeconds(36), - State = TorrentState.Cancelling, - SeedCount = 15 - }, - new TorrentItem - { - Title = "Microsoft Edge", - TotalSize = new DataSize(3221225472), - Downloaded = new DataSize(125829120), - TransmissionSpeed = new DownloadSpeed(33554432), - RemainingTime = TimeSpan.FromSeconds(36), - State = TorrentState.Initializing, - SeedCount = 15 - }, - new TorrentItem - { - Title = "Microsoft Edge", - TotalSize = new DataSize(3221225472), - Downloaded = new DataSize(125829120), - TransmissionSpeed = new DownloadSpeed(33554432), - RemainingTime = TimeSpan.FromSeconds(36), - State = TorrentState.Pausing, - SeedCount = 15 - }, - new TorrentItem - { - Title = "Microsoft Edge", - TotalSize = new DataSize(3221225472), - Downloaded = new DataSize(125829120), - TransmissionSpeed = new DownloadSpeed(33554432), - RemainingTime = TimeSpan.FromSeconds(36), - State = TorrentState.Resuming, - SeedCount = 15 - }, - new TorrentItem - { - Title = "Microsoft Edge", - TotalSize = new DataSize(3221225472), - Downloaded = new DataSize(125829120), - TransmissionSpeed = new DownloadSpeed(33554432), - RemainingTime = TimeSpan.FromSeconds(36), - State = TorrentState.Error, - SeedCount = 15 - } + SavePath = ApplicationData.Current.LocalFolder.Path, + MaximumDownloadSpeed = 0, // Set from settings + MaximumUploadSpeed = 0 }; + + Engine = new ClientEngine(engineSettings); + + Restore(); } - public static void AddTorrent() + public static async void AddTorrent(Torrent torrent, StorageFolder destinationFolder) { + TorrentMetadataInfo meta = new TorrentMetadataInfo + { + DestinationFolderFALToken = StorageApplicationPermissions.FutureAccessList.Add(destinationFolder), + TorrentFileName = new FileInfo(torrent.TorrentPath).Name + }; + TorrentManager manager = new TorrentManager(torrent, destinationFolder.Path); + meta.TorrentHash = manager.InfoHash.ToHex(); + + if (TorrentsMetadata.Any(i => i.TorrentHash == meta.TorrentHash)) + { + ContentDialog alert = new ContentDialog + { + Title = "Duplicate torrent", + Content = "You have previously added this torrent to the queue. Do you want to discard it and start a new download?", + PrimaryButtonText = "Yes", + CloseButtonText = "No", + DefaultButton = ContentDialogButton.Close + }; + + if (await alert.ShowAsync() == ContentDialogResult.Primary) + { + FastResumeData.Remove(meta.TorrentHash); + TorrentsMetadata.RemoveAll(i => i.TorrentHash == meta.TorrentHash); + foreach(TorrentManager t in Torrents.FindAll(i => i.InfoHash.ToHex() == meta.TorrentHash)) + { + await t.StopAsync(); + await Engine.Unregister(t); + } + Torrents.RemoveAll(i => i.InfoHash.ToHex() == meta.TorrentHash); + } + else + return; + //return null; + } + + TorrentsMetadata.Add(meta); + SaveData(); + + if (FastResumeData.ContainsKey(meta.TorrentHash)) + manager.LoadFastResume(new FastResume((BEncodedDictionary)FastResumeData[torrent.InfoHash.ToHex()])); + + await Engine.Register(manager); + + Torrents.Add(manager); + + await manager.StartAsync(); + + //return manager; } - public static void PauseTorrent() + public static async void Restore() { + await Engine.EnablePortForwardingAsync(CancellationToken.None); + TorrentsMetadata = JsonConvert.DeserializeObject>(LocalSettings.Values["TorrentsMetadata"] as string ?? "") ?? new List(); + try + { + StorageFile fastResumeFile = await LocalStorage.CreateFileAsync("TorrentFastResume.data", CreationCollisionOption.OpenIfExists); + FastResumeData = BEncodedValue.Decode(await fastResumeFile.OpenStreamForReadAsync()); + } + catch { } + + foreach (TorrentMetadataInfo meta in TorrentsMetadata) + RestoreTorrent(meta); } - public static void CancelTorrent() + private static async void RestoreTorrent(TorrentMetadataInfo meta) { + try + { + StorageFile torrentFile = await LocalStorage.GetFileAsync(meta.TorrentFileName); + Torrent torrent = await Torrent.LoadAsync(await torrentFile.OpenStreamForReadAsync()); + StorageFolder destinationFolder = await StorageApplicationPermissions.FutureAccessList.GetFolderAsync(meta.DestinationFolderFALToken); + TorrentManager manager = new TorrentManager(torrent, destinationFolder.Path); + + if (FastResumeData.ContainsKey(meta.TorrentHash)) + manager.LoadFastResume(new FastResume((BEncodedDictionary)FastResumeData[meta.TorrentHash])); + + await Engine.Register(manager); + + Torrents.Add(manager); + + if (meta.IsActive) + await manager.StartAsync(); + } + catch + { + TorrentsMetadata.Remove(meta); + SaveData(); + } } - public static void ResumeTorrent() + public static async Task Suspend() { + SaveData(); + BEncodedDictionary fastResume = new BEncodedDictionary(); + foreach (TorrentManager item in Torrents) + { + await item.StopAsync(); + if (item.HashChecked) + fastResume.Add(item.InfoHash.ToHex(), item.SaveFastResume().Encode()); + } + + StorageFile fastResumeFile = await LocalStorage.CreateFileAsync("TorrentFastResume.data", CreationCollisionOption.OpenIfExists); + while (true) + try + { + await File.WriteAllBytesAsync(fastResumeFile.Path, fastResume.Encode()); + break; + } + catch { } + + Engine.Dispose(); } - public static void SeedTorrent() + private static void SaveData() { - + foreach (TorrentManager item in Torrents) + TorrentsMetadata.Find(i => i.TorrentHash == item.InfoHash.ToHex()).IsActive = !item.State.BelongsTo(TorrentState.Paused, TorrentState.HashingPaused, TorrentState.Error, TorrentState.Stopped, TorrentState.Stopping); + LocalSettings.Values["TorrentsMetadata"] = JsonConvert.SerializeObject(TorrentsMetadata); } - public static void OnItemStateChanged(TorrentItem item, TorrentState previousState) => - TorrentItemStateChanged?.Invoke(item, previousState); + public static async void PauseTorrent(TorrentManager torrent) + { + await torrent.PauseAsync(); + if (!torrent.HashChecked) + return; + + if (FastResumeData.ContainsKey(torrent.InfoHash.ToHex())) + FastResumeData[torrent.InfoHash.ToHex()] = torrent.SaveFastResume().Encode(); + else + FastResumeData.Add(torrent.InfoHash.ToHex(), torrent.SaveFastResume().Encode()); + + try + { + StorageFile fastResumeFile = await LocalStorage.CreateFileAsync("TorrentFastResume.data", CreationCollisionOption.OpenIfExists); + await File.WriteAllBytesAsync(fastResumeFile.Path, FastResumeData.Encode()); + } + catch { } + } + + public static async void RemoveTorrent(TorrentManager torrent, bool removeFiles = false) + { + await torrent.StopAsync(); + TorrentMetadataInfo meta = TorrentsMetadata.Find(i => i.TorrentHash == torrent.InfoHash.ToHex()); + + if (removeFiles) + { + StorageFolder destinationFolder = await StorageApplicationPermissions.FutureAccessList.GetFolderAsync(meta.DestinationFolderFALToken); + foreach (TorrentFile file in torrent.Torrent.Files) + await (await destinationFolder.GetFileAsync(file.Path)).DeleteAsync(StorageDeleteOption.PermanentDelete); + } + + StorageApplicationPermissions.FutureAccessList.Remove(meta.DestinationFolderFALToken); + await (await LocalStorage.GetFileAsync(meta.TorrentFileName))?.DeleteAsync(StorageDeleteOption.PermanentDelete); + + FastResumeData.Remove(meta.TorrentHash); + + TorrentsMetadata.RemoveAll(i => i.TorrentHash == torrent.InfoHash.ToHex()); + + SaveData(); + + try + { + StorageFile fastResumeFile = await LocalStorage.CreateFileAsync("TorrentFastResume.data", CreationCollisionOption.OpenIfExists); + await File.WriteAllBytesAsync(fastResumeFile.Path, FastResumeData.Encode()); + } + catch { } + } } } \ No newline at end of file diff --git a/Wintor/WinTorrent/ValueConverters/EstimatesValueConverter.cs b/Wintor/WinTorrent/ValueConverters/EstimatesValueConverter.cs new file mode 100644 index 0000000..62aa3b8 --- /dev/null +++ b/Wintor/WinTorrent/ValueConverters/EstimatesValueConverter.cs @@ -0,0 +1,25 @@ +using MonoTorrent.Client; +using System; +using Windows.UI.Xaml.Data; + +namespace WinTorrent.ValueConverters +{ + public class EstimatesValueConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, string language) + { + TorrentManager item = value as TorrentManager; + try + { + return TimeSpan.FromSeconds((item.Torrent.Size - item.Monitor.DataBytesDownloaded) / item.Monitor.DownloadSpeed); + } + catch(DivideByZeroException) + { + return ""; + } + } + + public object ConvertBack(object value, Type targetType, object parameter, string language) => + null; + } +} diff --git a/Wintor/WinTorrent/ValueConverters/TorrentStateValueConverter.cs b/Wintor/WinTorrent/ValueConverters/TorrentStateValueConverter.cs new file mode 100644 index 0000000..a971ec1 --- /dev/null +++ b/Wintor/WinTorrent/ValueConverters/TorrentStateValueConverter.cs @@ -0,0 +1,143 @@ +using MonoTorrent; +using MonoTorrent.Client; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices.ComTypes; +using System.Text; +using System.Threading.Tasks; +using Windows.UI; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Data; +using Windows.UI.Xaml.Media; +using WinTorrent.Models; + +namespace WinTorrent.ValueConverters +{ + public class TorrentStateValueConverter : IValueConverter + { + private static Dictionary StateDictionary { get; } = new Dictionary + { + { + "AccentColor", + new [] + { + new TorrentStateValuesEntry(new SolidColorBrush(Colors.DeepSkyBlue), + TorrentState.Downloading), + new TorrentStateValuesEntry(new SolidColorBrush(Colors.Orange), + TorrentState.Hashing, + TorrentState.Metadata, + TorrentState.Starting, + TorrentState.Stopping), + new TorrentStateValuesEntry(new SolidColorBrush(Colors.Gray), + TorrentState.HashingPaused, + TorrentState.Paused, + TorrentState.Stopped), + new TorrentStateValuesEntry(new SolidColorBrush(Color.FromArgb(255, 85, 187, 85)), + TorrentState.Seeding), + new TorrentStateValuesEntry(new SolidColorBrush(Colors.Red), + TorrentState.Error), + } + }, + { + "ProgressIndeterminate", + new [] { new TorrentStateValuesEntry(true, + TorrentState.Stopping, + TorrentState.Hashing, + TorrentState.Metadata, + TorrentState.Starting) } + }, + { + "StatsVisibility", + new [] { new TorrentStateValuesEntry(Visibility.Visible, TorrentState.Downloading) } + }, + { + "ErrorVisibility", + new [] { new TorrentStateValuesEntry(Visibility.Visible, TorrentState.Error) } + }, + { + "ProgressValue", + new [] { new TorrentStateValuesEntry(1, TorrentState.Error, + TorrentState.Seeding, + TorrentState.Stopped) } + }, + { + "PauseButtonVisibility", + new [] { new TorrentStateValuesEntry(Visibility.Visible, + TorrentState.Downloading, + TorrentState.Error, + TorrentState.Paused, + TorrentState.HashingPaused, + TorrentState.Stopped) } + }, + { + "PauseButtonTooltip", + new [] + { + new TorrentStateValuesEntry("Pause", TorrentState.Downloading), + new TorrentStateValuesEntry("Retry", TorrentState.Error), + new TorrentStateValuesEntry("Resume", TorrentState.Paused, TorrentState.HashingPaused), + new TorrentStateValuesEntry("Start", TorrentState.Stopped) + } + }, + { + "PauseButtonIcon", + new [] + { + new TorrentStateValuesEntry("\xE103", TorrentState.Downloading), + new TorrentStateValuesEntry("\xE149", TorrentState.Error), + new TorrentStateValuesEntry("\xE102", TorrentState.Paused, + TorrentState.HashingPaused, + TorrentState.Stopped) + } + }, + { + "StatusLabel", + new [] + { + new TorrentStateValuesEntry("Downloading", TorrentState.Downloading), + new TorrentStateValuesEntry("Error", TorrentState.Error), + new TorrentStateValuesEntry("Hashing", TorrentState.Hashing), + new TorrentStateValuesEntry("Hashing paused", TorrentState.HashingPaused), + new TorrentStateValuesEntry("Metadata", TorrentState.Metadata), + new TorrentStateValuesEntry("Paused", TorrentState.Paused), + new TorrentStateValuesEntry("Seeding", TorrentState.Seeding), + new TorrentStateValuesEntry("Starting", TorrentState.Starting), + new TorrentStateValuesEntry("Stopped", TorrentState.Stopped), + new TorrentStateValuesEntry("Stopping", TorrentState.Stopping), + } + }, + { + "StatusIcon", + new [] + { + new TorrentStateValuesEntry("\xE121", + TorrentState.Stopping, + TorrentState.Starting, + TorrentState.Metadata, + TorrentState.Hashing), + new TorrentStateValuesEntry("\xE103", + TorrentState.HashingPaused, + TorrentState.Paused), + new TorrentStateValuesEntry("\xE118", + TorrentState.Downloading), + new TorrentStateValuesEntry("\xE11C", + TorrentState.Seeding), + new TorrentStateValuesEntry("\xE7BA", + TorrentState.Error), + new TorrentStateValuesEntry("\xE15B", + TorrentState.Stopped) + } + } + }; + + public object Convert(object value, Type targetType, object parameter, string language) + { + try { return StateDictionary[parameter as string].FirstOrDefault(i => i.AppliedTo.Contains((TorrentState)value))?.Value; } + catch { return value; } + } + + public object ConvertBack(object value, Type targetType, object parameter, string language) => + null; + } +} diff --git a/Wintor/WinTorrent/WinTorrent.csproj b/Wintor/WinTorrent/WinTorrent.csproj index 7c38e01..61d8234 100644 --- a/Wintor/WinTorrent/WinTorrent.csproj +++ b/Wintor/WinTorrent/WinTorrent.csproj @@ -123,9 +123,9 @@ AddTorrentDialog.xaml - - + + TorrentDetailsPage.xaml @@ -141,7 +141,8 @@ - + + @@ -265,6 +266,9 @@ Visual C++ 2015 Runtime for Universal Windows Platform Apps + + + 14.0