Archived
1
0

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:
Michael Gordeev
2019-04-06 18:31:11 +03:00
parent 022ad84790
commit 9bca44c5f4
5 changed files with 239 additions and 44 deletions
+4
View File
@@ -5,10 +5,14 @@
<en-US>### What's new: <en-US>### What's new:
- Changelog notification now pops up after update at first launch - 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 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> </en-US>
<ru-RU>### Что нового: <ru-RU>### Что нового:
- Добавлено уведомление со списком изменений при первом запуске после обновления - Добавлено уведомление со списком изменений при первом запуске после обновления
- Добавлена возможность добавлять видео в плейлисты на странице просмотра - Добавлена возможность добавлять видео в плейлисты на странице просмотра
- Добавлена возможность добавлять видео в плейлисты через контекстное меню карточки
- Добавлена возможность скачивать видео через контекстное меню карточки
</ru-RU> </ru-RU>
</content> </content>
</item> </item>
+8
View File
@@ -258,11 +258,14 @@ namespace FoxTube.Controls
} }
cts.Cancel(); cts.Cancel();
DownloadAgent.Remove(this);
status.Text = resources.GetString("/Downloads/cancelling"); status.Text = resources.GetString("/Downloads/cancelling");
progressBar.IsIndeterminate = true; progressBar.IsIndeterminate = true;
} }
void SetMeta() void SetMeta()
{
try
{ {
thumbnail.Source = new BitmapImage(Container.Thumbnail) { DecodePixelHeight = (int)thumbnail.ActualHeight, DecodePixelWidth = (int)thumbnail.ActualWidth }; thumbnail.Source = new BitmapImage(Container.Thumbnail) { DecodePixelHeight = (int)thumbnail.ActualHeight, DecodePixelWidth = (int)thumbnail.ActualWidth };
@@ -274,6 +277,11 @@ namespace FoxTube.Controls
{resources.GetString("/Downloads/duration")}: {Container.Duration} {resources.GetString("/Downloads/duration")}: {Container.Duration}
{resources.GetString("/Downloads/author")}: {Container.Channel}"; {resources.GetString("/Downloads/author")}: {Container.Channel}";
} }
catch
{
DownloadAgent.Remove(this);
}
}
private void Cancel_Click(object sender, RoutedEventArgs e) private void Cancel_Click(object sender, RoutedEventArgs e)
{ {
+7 -2
View File
@@ -71,12 +71,17 @@
</MenuFlyoutItem.Icon> </MenuFlyoutItem.Icon>
</MenuFlyoutItem> </MenuFlyoutItem>
<MenuFlyoutItem x:Uid="/Cards/channel" Icon="Contact" Text="View channel" Name="viewChannel" Click="ViewChannel_Click"/> <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/> <MenuFlyoutSeparator/>
<MenuFlyoutItem x:Uid="/Cards/getLink" Icon="Link" Text="Copy link" Name="getLink" Click="GetLink_Click"/> <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/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"/> <MenuFlyoutItem x:Uid="/Cards/share" Icon="Share" Text="Share" Name="share" Visibility="Collapsed"/>
<MenuFlyoutSeparator Visibility="Collapsed"/> <MenuFlyoutSeparator Visibility="{x:Bind download.Visibility}"/>
<MenuFlyoutItem Icon="Download" Text="Download" Visibility="Collapsed"/> <MenuFlyoutSubItem Icon="Download" Text="Download" Visibility="Visible" Name="download"/>
</MenuFlyout> </MenuFlyout>
</UserControl.ContextFlyout> </UserControl.ContextFlyout>
</UserControl> </UserControl>
+215
View File
@@ -11,6 +11,7 @@ using Microsoft.AppCenter.Analytics;
using System.Collections.Generic; using System.Collections.Generic;
using YoutubeExplode; using YoutubeExplode;
using Windows.UI.Popups; using Windows.UI.Popups;
using YoutubeExplode.Models.MediaStreams;
namespace FoxTube.Controls namespace FoxTube.Controls
{ {
@@ -61,6 +62,7 @@ namespace FoxTube.Controls
else else
info.Text = Methods.GetAgo(item.LiveStreamingDetails.ActualStartTime.Value); info.Text = Methods.GetAgo(item.LiveStreamingDetails.ActualStartTime.Value);
liveTag.Visibility = Visibility.Visible; liveTag.Visibility = Visibility.Visible;
download.Visibility = Visibility.Collapsed;
} }
else if (item.Snippet.LiveBroadcastContent == "upcoming") else if (item.Snippet.LiveBroadcastContent == "upcoming")
{ {
@@ -74,12 +76,15 @@ namespace FoxTube.Controls
if (item.LiveStreamingDetails.ScheduledStartTime.HasValue) 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"); 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"); else liveContent.Text = resources.GetString("/Cards/upcoming");
download.Visibility = Visibility.Collapsed;
} }
else else
{ {
views.Text = $"{item.Statistics.ViewCount:0,0} {resources.GetString("/Cards/views")}"; views.Text = $"{item.Statistics.ViewCount:0,0} {resources.GetString("/Cards/views")}";
info.Text = $"{item.ContentDetails.Duration.GetDuration()} | {Methods.GetAgo(item.Snippet.PublishedAt.Value)}"; 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()); } try { thumbnail.Source = new BitmapImage(item.Snippet.Thumbnails.Medium.Url.ToUri()); }
catch { } 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() public async void LoadMeta()
{ {
videoId = item.Id; videoId = item.Id;
@@ -206,5 +247,179 @@ namespace FoxTube.Controls
{ {
thumbnail.Opacity = 1; 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;
}
}
}
} }
} }
+1 -38
View File
@@ -117,43 +117,6 @@
<ToggleMenuFlyoutItem Text="Watch later" Name="wl" Click="Wl_Click" Icon="Clock"/> <ToggleMenuFlyoutItem Text="Watch later" Name="wl" Click="Wl_Click" Icon="Clock"/>
<MenuFlyoutSeparator/> <MenuFlyoutSeparator/>
</MenuFlyout> </MenuFlyout>
<!--<Flyout>
<ScrollViewer Margin="-12" MaxHeight="300">
<NavigationViewList Width="200" IsMultiSelectCheckBoxEnabled="True" SelectionMode="Multiple">
<NavigationViewItem Content="Watch later">
<NavigationViewItem.Icon>
<FontIcon Glyph="&#xE728;"/>
</NavigationViewItem.Icon>
</NavigationViewItem>
<NavigationViewItem Content="New playlist">
<NavigationViewItem.Icon>
<FontIcon Glyph="&#xE109;"/>
</NavigationViewItem.Icon>
</NavigationViewItem>
<NavigationViewItemHeader Content="Other playlists"/>
<NavigationViewItem Content="My playlist">
<NavigationViewItem.Icon>
<FontIcon Glyph="&#xE292;"/>
</NavigationViewItem.Icon>
</NavigationViewItem>
<NavigationViewItem Content="Cats">
<NavigationViewItem.Icon>
<FontIcon Glyph="&#xE292;"/>
</NavigationViewItem.Icon>
</NavigationViewItem>
<NavigationViewItem Content="Dogs">
<NavigationViewItem.Icon>
<FontIcon Glyph="&#xE292;"/>
</NavigationViewItem.Icon>
</NavigationViewItem>
<NavigationViewItem Content="Another playlist">
<NavigationViewItem.Icon>
<FontIcon Glyph="&#xE292;"/>
</NavigationViewItem.Icon>
</NavigationViewItem>
</NavigationViewList>
</ScrollViewer>
</Flyout>-->
</AppBarButton.Flyout> </AppBarButton.Flyout>
</AppBarButton> </AppBarButton>
<AppBarButton x:Uid="/VideoPage/refresh" Name="refresh" Click="refresh_Click" Icon="Refresh" Label="Refresh page"/> <AppBarButton x:Uid="/VideoPage/refresh" Name="refresh" Click="refresh_Click" Icon="Refresh" Label="Refresh page"/>
@@ -201,7 +164,7 @@
</Pivot> </Pivot>
</Grid> </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> <StackPanel>
<TextBox PlaceholderText="Enter playlist name" Name="newListName"/> <TextBox PlaceholderText="Enter playlist name" Name="newListName"/>
<ComboBox Header="Availablity" SelectedIndex="0" HorizontalAlignment="Stretch" Name="newListDisc"> <ComboBox Header="Availablity" SelectedIndex="0" HorizontalAlignment="Stretch" Name="newListDisc">