Added "Add to" option to video cards context menu
Added "Download" option to video cards context menu Updated changelog Related Work Items: #192
This commit is contained in:
@@ -5,10 +5,14 @@
|
||||
<en-US>### What's new:
|
||||
- Changelog notification now pops up after update at first launch
|
||||
- Added ability to add videos to playlists on video page
|
||||
- Added ability to add videos to playlists through card's context menu
|
||||
- Added ability to download video through card's context menu
|
||||
</en-US>
|
||||
<ru-RU>### Что нового:
|
||||
- Добавлено уведомление со списком изменений при первом запуске после обновления
|
||||
- Добавлена возможность добавлять видео в плейлисты на странице просмотра
|
||||
- Добавлена возможность добавлять видео в плейлисты через контекстное меню карточки
|
||||
- Добавлена возможность скачивать видео через контекстное меню карточки
|
||||
</ru-RU>
|
||||
</content>
|
||||
</item>
|
||||
|
||||
@@ -258,21 +258,29 @@ namespace FoxTube.Controls
|
||||
}
|
||||
|
||||
cts.Cancel();
|
||||
DownloadAgent.Remove(this);
|
||||
status.Text = resources.GetString("/Downloads/cancelling");
|
||||
progressBar.IsIndeterminate = true;
|
||||
}
|
||||
|
||||
void SetMeta()
|
||||
{
|
||||
thumbnail.Source = new BitmapImage(Container.Thumbnail) { DecodePixelHeight = (int)thumbnail.ActualHeight, DecodePixelWidth = (int)thumbnail.ActualWidth };
|
||||
try
|
||||
{
|
||||
thumbnail.Source = new BitmapImage(Container.Thumbnail) { DecodePixelHeight = (int)thumbnail.ActualHeight, DecodePixelWidth = (int)thumbnail.ActualWidth };
|
||||
|
||||
title.Text = Container.Title;
|
||||
path.Text = File.Path;
|
||||
title.Text = Container.Title;
|
||||
path.Text = File.Path;
|
||||
|
||||
meta.Text = $@"{resources.GetString("/Downloads/ext")}: {Container.Extension}
|
||||
meta.Text = $@"{resources.GetString("/Downloads/ext")}: {Container.Extension}
|
||||
{resources.GetString("/Downloads/quality")}: {Container.Quality}
|
||||
{resources.GetString("/Downloads/duration")}: {Container.Duration}
|
||||
{resources.GetString("/Downloads/author")}: {Container.Channel}";
|
||||
}
|
||||
catch
|
||||
{
|
||||
DownloadAgent.Remove(this);
|
||||
}
|
||||
}
|
||||
|
||||
private void Cancel_Click(object sender, RoutedEventArgs e)
|
||||
|
||||
@@ -71,12 +71,17 @@
|
||||
</MenuFlyoutItem.Icon>
|
||||
</MenuFlyoutItem>
|
||||
<MenuFlyoutItem x:Uid="/Cards/channel" Icon="Contact" Text="View channel" Name="viewChannel" Click="ViewChannel_Click"/>
|
||||
<MenuFlyoutSubItem Icon="Add" Text="Add to" Name="addTo">
|
||||
<MenuFlyoutItem Text="New playlist" Name="newPlaylist" Click="NewPlaylist_Click" Icon="Add"/>
|
||||
<ToggleMenuFlyoutItem Text="Watch later" Name="wl" Click="Wl_Click" Icon="Clock"/>
|
||||
<MenuFlyoutSeparator/>
|
||||
</MenuFlyoutSubItem>
|
||||
<MenuFlyoutSeparator/>
|
||||
<MenuFlyoutItem x:Uid="/Cards/getLink" Icon="Link" Text="Copy link" Name="getLink" Click="GetLink_Click"/>
|
||||
<MenuFlyoutItem x:Uid="/Cards/openWeb" Icon="Globe" Text="Open in browser" Name="inBrowser" Click="InBrowser_Click"/>
|
||||
<MenuFlyoutItem x:Uid="/Cards/share" Icon="Share" Text="Share" Name="share" Visibility="Collapsed"/>
|
||||
<MenuFlyoutSeparator Visibility="Collapsed"/>
|
||||
<MenuFlyoutItem Icon="Download" Text="Download" Visibility="Collapsed"/>
|
||||
<MenuFlyoutSeparator Visibility="{x:Bind download.Visibility}"/>
|
||||
<MenuFlyoutSubItem Icon="Download" Text="Download" Visibility="Visible" Name="download"/>
|
||||
</MenuFlyout>
|
||||
</UserControl.ContextFlyout>
|
||||
</UserControl>
|
||||
|
||||
@@ -11,6 +11,7 @@ using Microsoft.AppCenter.Analytics;
|
||||
using System.Collections.Generic;
|
||||
using YoutubeExplode;
|
||||
using Windows.UI.Popups;
|
||||
using YoutubeExplode.Models.MediaStreams;
|
||||
|
||||
namespace FoxTube.Controls
|
||||
{
|
||||
@@ -61,6 +62,7 @@ namespace FoxTube.Controls
|
||||
else
|
||||
info.Text = Methods.GetAgo(item.LiveStreamingDetails.ActualStartTime.Value);
|
||||
liveTag.Visibility = Visibility.Visible;
|
||||
download.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
else if (item.Snippet.LiveBroadcastContent == "upcoming")
|
||||
{
|
||||
@@ -74,12 +76,15 @@ namespace FoxTube.Controls
|
||||
if (item.LiveStreamingDetails.ScheduledStartTime.HasValue)
|
||||
liveContent.Text = resources.GetString("/Cards/goesLive") + (item.LiveStreamingDetails.ScheduledStartTime.Value > DateTime.Now ? " " : " -") + (item.LiveStreamingDetails.ScheduledStartTime.Value - DateTime.Now).ToString(@"hh\:mm\:ss");
|
||||
else liveContent.Text = resources.GetString("/Cards/upcoming");
|
||||
download.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
else
|
||||
{
|
||||
views.Text = $"{item.Statistics.ViewCount:0,0} {resources.GetString("/Cards/views")}";
|
||||
info.Text = $"{item.ContentDetails.Duration.GetDuration()} | {Methods.GetAgo(item.Snippet.PublishedAt.Value)}";
|
||||
LoadDownloads();
|
||||
}
|
||||
LoadAddTo();
|
||||
|
||||
try { thumbnail.Source = new BitmapImage(item.Snippet.Thumbnails.Medium.Url.ToUri()); }
|
||||
catch { }
|
||||
@@ -103,6 +108,42 @@ namespace FoxTube.Controls
|
||||
}
|
||||
}
|
||||
|
||||
async void LoadDownloads()
|
||||
{
|
||||
try
|
||||
{
|
||||
// TODO: Localize context menu
|
||||
MediaStreamInfoSet infoSet = await new YoutubeClient().GetVideoMediaStreamInfosAsync(videoId);
|
||||
foreach (MuxedStreamInfo i in infoSet.Muxed)
|
||||
{
|
||||
MenuFlyoutItem menuItem = new MenuFlyoutItem()
|
||||
{
|
||||
Text = i.VideoQualityLabel,
|
||||
Tag = new object[] { i, i.VideoQualityLabel }
|
||||
};
|
||||
menuItem.Click += downloadItemSelected;
|
||||
download.Items.Add(menuItem);
|
||||
}
|
||||
|
||||
MenuFlyoutItem audioItem = new MenuFlyoutItem()
|
||||
{
|
||||
Text = resources.GetString("/VideoPage/audio"),
|
||||
Tag = new object[] { infoSet.Audio[0], resources.GetString("/Cards/audioOnly") }
|
||||
};
|
||||
audioItem.Click += downloadItemSelected;
|
||||
download.Items.Add(audioItem);
|
||||
}
|
||||
catch
|
||||
{
|
||||
download.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
}
|
||||
|
||||
private void downloadItemSelected(object sender, RoutedEventArgs e)
|
||||
{
|
||||
DownloadAgent.Add(((sender as MenuFlyoutItem).Tag as object[])[0] as MediaStreamInfo, item, ((sender as MenuFlyoutItem).Tag as object[])[1] as string);
|
||||
}
|
||||
|
||||
public async void LoadMeta()
|
||||
{
|
||||
videoId = item.Id;
|
||||
@@ -206,5 +247,179 @@ namespace FoxTube.Controls
|
||||
{
|
||||
thumbnail.Opacity = 1;
|
||||
}
|
||||
|
||||
private async void NewPlaylist_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// TODO: Localize strings
|
||||
StackPanel stack = new StackPanel();
|
||||
stack.Children.Add(new TextBox
|
||||
{
|
||||
PlaceholderText = "Enter playlist name"
|
||||
});
|
||||
|
||||
ComboBox comboBox = new ComboBox
|
||||
{
|
||||
Header = "Availablity",
|
||||
SelectedIndex = 0,
|
||||
HorizontalAlignment = HorizontalAlignment.Stretch
|
||||
};
|
||||
comboBox.Items.Add(new ComboBoxItem { Content = "Public" });
|
||||
comboBox.Items.Add(new ComboBoxItem { Content = "Private" });
|
||||
comboBox.Items.Add(new ComboBoxItem { Content = "Direct link" });
|
||||
|
||||
stack.Children.Add(comboBox);
|
||||
|
||||
ContentDialog playlistDialog = new ContentDialog
|
||||
{
|
||||
PrimaryButtonText = "Create and add",
|
||||
CloseButtonText = "Cancel",
|
||||
DefaultButton = ContentDialogButton.Primary,
|
||||
Title = "New playlist",
|
||||
Content = stack
|
||||
};
|
||||
playlistDialog.PrimaryButtonClick += PlaylistDialog_PrimaryButtonClick;
|
||||
await playlistDialog.ShowAsync();
|
||||
}
|
||||
|
||||
private async void PlaylistDialog_PrimaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args)
|
||||
{
|
||||
string privacy = "private";
|
||||
switch (((sender.Content as StackPanel).Children[1] as ComboBox).SelectedIndex)
|
||||
{
|
||||
case 0:
|
||||
privacy = "public";
|
||||
break;
|
||||
case 1:
|
||||
privacy = "private";
|
||||
break;
|
||||
case 2:
|
||||
privacy = "unlisted";
|
||||
break;
|
||||
}
|
||||
|
||||
Playlist newItem = new Playlist
|
||||
{
|
||||
Snippet = new PlaylistSnippet
|
||||
{
|
||||
Title = ((sender.Content as StackPanel).Children[0] as TextBox).Text
|
||||
},
|
||||
Status = new PlaylistStatus
|
||||
{
|
||||
PrivacyStatus = privacy,
|
||||
}
|
||||
};
|
||||
|
||||
Playlist i;
|
||||
|
||||
try { i = await SecretsVault.Service.Playlists.Insert(newItem, "snippet,status").ExecuteAsync(); }
|
||||
catch
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ToggleMenuFlyoutItem menuItem = new ToggleMenuFlyoutItem
|
||||
{
|
||||
Text = i.Snippet.Title,
|
||||
IsChecked = true,
|
||||
Tag = i,
|
||||
Icon = new FontIcon
|
||||
{
|
||||
Glyph = "\xE728"
|
||||
}
|
||||
};
|
||||
menuItem.Click += Item_Click;
|
||||
addTo.Items.Add(menuItem);
|
||||
|
||||
Item_Click(menuItem, null);
|
||||
}
|
||||
|
||||
private void Wl_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
async void LoadAddTo()
|
||||
{
|
||||
if (SecretsVault.UserChannel == null)
|
||||
{
|
||||
addTo.Visibility = Visibility.Collapsed;
|
||||
return;
|
||||
}
|
||||
|
||||
if (SecretsVault.WatchLater.Contains(item.Id))
|
||||
(addTo.Items[1] as ToggleMenuFlyoutItem).IsChecked = true;
|
||||
|
||||
PlaylistsResource.ListRequest request = SecretsVault.Service.Playlists.List("snippet");
|
||||
request.Mine = true;
|
||||
request.MaxResults = 50;
|
||||
|
||||
PlaylistListResponse response = await request.ExecuteAsync();
|
||||
|
||||
PlaylistItemsResource.ListRequest itemRequest = SecretsVault.Service.PlaylistItems.List("snippet");
|
||||
itemRequest.VideoId = item.Id;
|
||||
|
||||
foreach (Playlist i in response.Items)
|
||||
{
|
||||
itemRequest.PlaylistId = i.Id;
|
||||
ToggleMenuFlyoutItem menuItem = new ToggleMenuFlyoutItem
|
||||
{
|
||||
Text = i.Snippet.Title,
|
||||
IsChecked = (await itemRequest.ExecuteAsync()).Items.Count > 0,
|
||||
Tag = i,
|
||||
Icon = new FontIcon
|
||||
{
|
||||
Glyph = "\xE728"
|
||||
}
|
||||
};
|
||||
menuItem.Click += Item_Click;
|
||||
addTo.Items.Add(menuItem);
|
||||
}
|
||||
}
|
||||
|
||||
private async void Item_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (((ToggleMenuFlyoutItem)sender).IsChecked)
|
||||
{
|
||||
try
|
||||
{
|
||||
PlaylistItem playlist = new PlaylistItem
|
||||
{
|
||||
Snippet = new PlaylistItemSnippet
|
||||
{
|
||||
PlaylistId = (((ToggleMenuFlyoutItem)sender).Tag as Playlist).Id,
|
||||
ResourceId = new ResourceId
|
||||
{
|
||||
VideoId = item.Id,
|
||||
Kind = "youtube#video"
|
||||
}
|
||||
}
|
||||
};
|
||||
PlaylistItemsResource.InsertRequest request = SecretsVault.Service.PlaylistItems.Insert(playlist, "snippet");
|
||||
|
||||
await request.ExecuteAsync();
|
||||
}
|
||||
catch
|
||||
{
|
||||
((ToggleMenuFlyoutItem)sender).IsChecked = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
PlaylistItemsResource.ListRequest itemRequest = SecretsVault.Service.PlaylistItems.List("snippet");
|
||||
itemRequest.VideoId = item.Id;
|
||||
itemRequest.PlaylistId = ((Playlist)((ToggleMenuFlyoutItem)sender).Tag).Id;
|
||||
|
||||
PlaylistItemsResource.DeleteRequest request = SecretsVault.Service.PlaylistItems.Delete((await itemRequest.ExecuteAsync()).Items[0].Id);
|
||||
|
||||
await request.ExecuteAsync();
|
||||
}
|
||||
catch
|
||||
{
|
||||
((ToggleMenuFlyoutItem)sender).IsChecked = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,43 +117,6 @@
|
||||
<ToggleMenuFlyoutItem Text="Watch later" Name="wl" Click="Wl_Click" Icon="Clock"/>
|
||||
<MenuFlyoutSeparator/>
|
||||
</MenuFlyout>
|
||||
<!--<Flyout>
|
||||
<ScrollViewer Margin="-12" MaxHeight="300">
|
||||
<NavigationViewList Width="200" IsMultiSelectCheckBoxEnabled="True" SelectionMode="Multiple">
|
||||
<NavigationViewItem Content="Watch later">
|
||||
<NavigationViewItem.Icon>
|
||||
<FontIcon Glyph=""/>
|
||||
</NavigationViewItem.Icon>
|
||||
</NavigationViewItem>
|
||||
<NavigationViewItem Content="New playlist">
|
||||
<NavigationViewItem.Icon>
|
||||
<FontIcon Glyph=""/>
|
||||
</NavigationViewItem.Icon>
|
||||
</NavigationViewItem>
|
||||
<NavigationViewItemHeader Content="Other playlists"/>
|
||||
<NavigationViewItem Content="My playlist">
|
||||
<NavigationViewItem.Icon>
|
||||
<FontIcon Glyph=""/>
|
||||
</NavigationViewItem.Icon>
|
||||
</NavigationViewItem>
|
||||
<NavigationViewItem Content="Cats">
|
||||
<NavigationViewItem.Icon>
|
||||
<FontIcon Glyph=""/>
|
||||
</NavigationViewItem.Icon>
|
||||
</NavigationViewItem>
|
||||
<NavigationViewItem Content="Dogs">
|
||||
<NavigationViewItem.Icon>
|
||||
<FontIcon Glyph=""/>
|
||||
</NavigationViewItem.Icon>
|
||||
</NavigationViewItem>
|
||||
<NavigationViewItem Content="Another playlist">
|
||||
<NavigationViewItem.Icon>
|
||||
<FontIcon Glyph=""/>
|
||||
</NavigationViewItem.Icon>
|
||||
</NavigationViewItem>
|
||||
</NavigationViewList>
|
||||
</ScrollViewer>
|
||||
</Flyout>-->
|
||||
</AppBarButton.Flyout>
|
||||
</AppBarButton>
|
||||
<AppBarButton x:Uid="/VideoPage/refresh" Name="refresh" Click="refresh_Click" Icon="Refresh" Label="Refresh page"/>
|
||||
@@ -201,7 +164,7 @@
|
||||
</Pivot>
|
||||
</Grid>
|
||||
|
||||
<ContentDialog PrimaryButtonText="Create and add" Title="New playlist" DefaultButton="Primary" PrimaryButtonClick="ContentDialog_PrimaryButtonClick" Name="playlistDialog">
|
||||
<ContentDialog PrimaryButtonText="Create and add" Title="New playlist" CloseButtonText="Cancel" DefaultButton="Primary" PrimaryButtonClick="ContentDialog_PrimaryButtonClick" Name="playlistDialog">
|
||||
<StackPanel>
|
||||
<TextBox PlaceholderText="Enter playlist name" Name="newListName"/>
|
||||
<ComboBox Header="Availablity" SelectedIndex="0" HorizontalAlignment="Stretch" Name="newListDisc">
|
||||
|
||||
Reference in New Issue
Block a user