New arch (not working)
This commit is contained in:
+23
-232
@@ -1,30 +1,16 @@
|
|||||||
using Google.Apis.YouTube.v3.Data;
|
using FoxTube.Classes;
|
||||||
using Microsoft.AppCenter;
|
|
||||||
using Microsoft.AppCenter.Analytics;
|
using Microsoft.AppCenter.Analytics;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Xml;
|
|
||||||
using Windows.ApplicationModel;
|
|
||||||
using Windows.ApplicationModel.Activation;
|
using Windows.ApplicationModel.Activation;
|
||||||
using Windows.ApplicationModel.Background;
|
|
||||||
using Windows.Globalization;
|
using Windows.Globalization;
|
||||||
using Windows.Storage;
|
|
||||||
using Windows.System.Power;
|
|
||||||
using Windows.UI.Notifications;
|
using Windows.UI.Notifications;
|
||||||
using Windows.UI.Xaml;
|
using Windows.UI.Xaml;
|
||||||
using Windows.UI.Xaml.Controls;
|
using Windows.UI.Xaml.Controls;
|
||||||
using Windows.UI.Xaml.Navigation;
|
|
||||||
|
|
||||||
namespace FoxTube
|
namespace FoxTube
|
||||||
{
|
{
|
||||||
sealed partial class App : Application
|
sealed partial class App : Application
|
||||||
{
|
{
|
||||||
public static string[] AvailableLanguages => new[] { "en-US", "ru-RU" };
|
|
||||||
|
|
||||||
Stopwatch sw = new Stopwatch();
|
|
||||||
public App()
|
public App()
|
||||||
{
|
{
|
||||||
SettingsStorage.LoadData();
|
SettingsStorage.LoadData();
|
||||||
@@ -40,113 +26,30 @@ namespace FoxTube
|
|||||||
}
|
}
|
||||||
ApplicationLanguages.PrimaryLanguageOverride = SettingsStorage.Language;
|
ApplicationLanguages.PrimaryLanguageOverride = SettingsStorage.Language;
|
||||||
|
|
||||||
CheckVersion();
|
|
||||||
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
Suspending += OnSuspending;
|
Suspending += (s, e) => Processes.SuspendApp();
|
||||||
UnhandledException += UnhandledError;
|
UnhandledException += (s, e) => Analytics.TrackEvent("The app crashed", new Dictionary<string, string>()
|
||||||
|
|
||||||
AppCenter.Start("45774462-9ea7-438a-96fc-03982666f39e", typeof(Analytics));
|
|
||||||
AppCenter.SetCountryCode(SettingsStorage.Region);
|
|
||||||
|
|
||||||
sw.Start();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Comparing current version with last recorded version. If doesn't match, poping up changelog notification
|
|
||||||
/// </summary>
|
|
||||||
public async void CheckVersion()
|
|
||||||
{
|
{
|
||||||
PackageVersion ver = Package.Current.Id.Version;
|
{ "Exception", e.Exception.GetType().ToString() },
|
||||||
if (SettingsStorage.Version != $"{ver.Major}.{ver.Minor}.{ver.Build}")
|
{ "Details", e.Message },
|
||||||
{
|
{ "StackTrace", e.Exception.StackTrace }
|
||||||
try
|
|
||||||
{
|
|
||||||
XmlDocument changelog = new XmlDocument();
|
|
||||||
StorageFile file = await (await Package.Current.InstalledLocation.GetFolderAsync(@"Assets\Data")).GetFileAsync("Patchnotes.xml");
|
|
||||||
changelog.Load(await file.OpenStreamForReadAsync());
|
|
||||||
XmlElement e = changelog["items"].ChildNodes[0] as XmlElement;
|
|
||||||
|
|
||||||
ToastNotificationManager.CreateToastNotifier().Show(Background.Notification.GetChangelogToast(e.GetAttribute("version")));
|
|
||||||
|
|
||||||
SettingsStorage.Version = $"{ver.Major}.{ver.Minor}.{ver.Build}";
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Analytics.TrackEvent("Unable to retrieve changelog", new Dictionary<string, string>
|
|
||||||
{
|
|
||||||
{ "Exception", e.GetType().ToString() },
|
|
||||||
{ "Message", e.Message },
|
|
||||||
{ "App version", $"{ver.Major}.{ver.Minor}.{ver.Revision}.{ver.Build}" },
|
|
||||||
{ "StackTrace", e.StackTrace }
|
|
||||||
});
|
});
|
||||||
}
|
|
||||||
}
|
Processes.InitializeApp();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnLaunched(LaunchActivatedEventArgs e)
|
protected override void OnLaunched(LaunchActivatedEventArgs e)
|
||||||
{
|
{
|
||||||
if (!(Window.Current.Content is Frame rootFrame))
|
if (!(Window.Current.Content is Frame))
|
||||||
{
|
Window.Current.Content = new Frame();
|
||||||
rootFrame = new Frame();
|
|
||||||
rootFrame.NavigationFailed += OnNavigationFailed;
|
|
||||||
Window.Current.Content = rootFrame;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e.PrelaunchActivated == false)
|
if (e.PrelaunchActivated == false)
|
||||||
{
|
{
|
||||||
if (rootFrame.Content == null)
|
if ((Window.Current.Content as Frame).Content == null)
|
||||||
rootFrame.Navigate(typeof(MainPage), e.Arguments);
|
(Window.Current.Content as Frame).Navigate(typeof(MainPage), e.Arguments);
|
||||||
|
|
||||||
Window.Current.Activate();
|
Window.Current.Activate();
|
||||||
}
|
}
|
||||||
|
|
||||||
ActivateToastBackgoundTask();
|
|
||||||
ActivateBackgoundTask();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes background task for processing toast notifications' clicks
|
|
||||||
/// </summary>
|
|
||||||
public async void ActivateToastBackgoundTask()
|
|
||||||
{
|
|
||||||
const string taskName = "FoxtubeToastBackground";
|
|
||||||
if (BackgroundTaskRegistration.AllTasks.Any(i => i.Value.Name.Equals(taskName)))
|
|
||||||
return;
|
|
||||||
|
|
||||||
var backgroundRequest = await BackgroundExecutionManager.RequestAccessAsync();
|
|
||||||
if (backgroundRequest == BackgroundAccessStatus.DeniedBySystemPolicy || backgroundRequest == BackgroundAccessStatus.DeniedByUser)
|
|
||||||
return;
|
|
||||||
|
|
||||||
BackgroundTaskBuilder builder = new BackgroundTaskBuilder() { Name = taskName };
|
|
||||||
builder.SetTrigger(new ToastNotificationActionTrigger());
|
|
||||||
|
|
||||||
BackgroundTaskRegistration registration = builder.Register();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes background task for checking user's subscriptions and poping toast notifications when new video is uploaded
|
|
||||||
/// </summary>
|
|
||||||
public async void ActivateBackgoundTask()
|
|
||||||
{
|
|
||||||
const string taskName = "FoxtubeBackgound";
|
|
||||||
if (BackgroundTaskRegistration.AllTasks.Any(i => i.Value.Name.Equals(taskName)))
|
|
||||||
return;
|
|
||||||
|
|
||||||
var backgroundRequest = await BackgroundExecutionManager.RequestAccessAsync();
|
|
||||||
var saverRequest = PowerManager.EnergySaverStatus;
|
|
||||||
if (backgroundRequest == BackgroundAccessStatus.DeniedBySystemPolicy || backgroundRequest == BackgroundAccessStatus.DeniedByUser || saverRequest == EnergySaverStatus.On)
|
|
||||||
return;
|
|
||||||
|
|
||||||
BackgroundTaskBuilder builder = new BackgroundTaskBuilder()
|
|
||||||
{
|
|
||||||
Name = taskName,
|
|
||||||
IsNetworkRequested = true,
|
|
||||||
TaskEntryPoint = "FoxTube.Background.BackgroundProcessor"
|
|
||||||
};
|
|
||||||
builder.SetTrigger(new TimeTrigger(15, false));
|
|
||||||
|
|
||||||
BackgroundTaskRegistration registration = builder.Register();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnBackgroundActivated(BackgroundActivatedEventArgs args)
|
protected override void OnBackgroundActivated(BackgroundActivatedEventArgs args)
|
||||||
@@ -154,50 +57,10 @@ namespace FoxTube
|
|||||||
var deferral = args.TaskInstance.GetDeferral();
|
var deferral = args.TaskInstance.GetDeferral();
|
||||||
base.OnBackgroundActivated(args);
|
base.OnBackgroundActivated(args);
|
||||||
|
|
||||||
if (args.TaskInstance.Task.Name == "FoxtubeToastBackground" && args.TaskInstance.TriggerDetails is ToastNotificationActionTriggerDetail details)
|
if (args.TaskInstance.Task.Name == "FoxtubeToastBackground" || !(args.TaskInstance.TriggerDetails is ToastNotificationActionTriggerDetail details))
|
||||||
{
|
return;
|
||||||
string[] arguments = details.Argument.Split('|');
|
|
||||||
|
|
||||||
switch (arguments[0])
|
Processes.ProcessToast(details.Argument);
|
||||||
{
|
|
||||||
case "later":
|
|
||||||
try
|
|
||||||
{
|
|
||||||
SecretsVault.AuthorizationStateChanged += async (s, e) =>
|
|
||||||
{
|
|
||||||
if ((bool)e[0])
|
|
||||||
{
|
|
||||||
PlaylistItem item = new PlaylistItem()
|
|
||||||
{
|
|
||||||
Snippet = new PlaylistItemSnippet()
|
|
||||||
{
|
|
||||||
ResourceId = new ResourceId()
|
|
||||||
{
|
|
||||||
Kind = "youtube#video",
|
|
||||||
VideoId = arguments[1]
|
|
||||||
},
|
|
||||||
PlaylistId = "WL"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
await SecretsVault.Service.PlaylistItems.Insert(item, "snippet").ExecuteAsync();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
SecretsVault.CheckAuthorization(false);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Analytics.TrackEvent("Failed to add video to WL from toast", new Dictionary<string, string>
|
|
||||||
{
|
|
||||||
{ "Exception", e.GetType().ToString() },
|
|
||||||
{ "Message", e.Message },
|
|
||||||
{ "Video ID", arguments[1] },
|
|
||||||
{ "StackTrace", e.StackTrace }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deferral.Complete();
|
deferral.Complete();
|
||||||
}
|
}
|
||||||
@@ -206,7 +69,8 @@ namespace FoxTube
|
|||||||
{
|
{
|
||||||
base.OnActivated(e);
|
base.OnActivated(e);
|
||||||
|
|
||||||
if (!(Window.Current.Content is Frame rootFrame))
|
//TODO: Check this shit
|
||||||
|
/*if (!(Window.Current.Content is Frame rootFrame))
|
||||||
{
|
{
|
||||||
rootFrame = new Frame();
|
rootFrame = new Frame();
|
||||||
rootFrame.NavigationFailed += OnNavigationFailed;
|
rootFrame.NavigationFailed += OnNavigationFailed;
|
||||||
@@ -217,88 +81,15 @@ namespace FoxTube
|
|||||||
if (rootFrame.Content == null)
|
if (rootFrame.Content == null)
|
||||||
rootFrame.Navigate(typeof(MainPage));
|
rootFrame.Navigate(typeof(MainPage));
|
||||||
|
|
||||||
Window.Current.Activate();
|
Window.Current.Activate();*/
|
||||||
|
|
||||||
|
if (e.Kind != ActivationKind.ToastNotification)
|
||||||
|
return;
|
||||||
|
|
||||||
switch (e.Kind)
|
|
||||||
{
|
|
||||||
case ActivationKind.ToastNotification:
|
|
||||||
if (SecretsVault.IsAuthorized)
|
if (SecretsVault.IsAuthorized)
|
||||||
ProcessToast((e as ToastNotificationActivatedEventArgs).Argument);
|
Processes.ProcessToast((e as ToastNotificationActivatedEventArgs).Argument);
|
||||||
else
|
else
|
||||||
SecretsVault.AuthorizationStateChanged += (s, arg) => ProcessToast((e as ToastNotificationActivatedEventArgs).Argument);
|
SecretsVault.AuthorizationStateChanged += (arg) => Processes.ProcessToast((e as ToastNotificationActivatedEventArgs).Argument);
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ProcessToast(string arg)
|
|
||||||
{
|
|
||||||
string[] args = arg.Split('|');
|
|
||||||
switch (args[0])
|
|
||||||
{
|
|
||||||
case "changelog":
|
|
||||||
case "inbox":
|
|
||||||
Methods.MainPage.GoToDeveloper(args[1]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "video":
|
|
||||||
Methods.MainPage.GoToVideo(args[1]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "channel":
|
|
||||||
Methods.MainPage.GoToChannel(args[1]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "download":
|
|
||||||
Methods.MainPage.GoToDownloads();
|
|
||||||
break;
|
|
||||||
case "dcancel":
|
|
||||||
DownloadAgent.Cancel(args[1]);
|
|
||||||
break;
|
|
||||||
case "clipboard":
|
|
||||||
switch (args[1])
|
|
||||||
{
|
|
||||||
case "video":
|
|
||||||
Methods.MainPage.GoToVideo(args[2]);
|
|
||||||
break;
|
|
||||||
case "channel":
|
|
||||||
Methods.MainPage.GoToChannel(args[2]);
|
|
||||||
break;
|
|
||||||
case "playlist":
|
|
||||||
Methods.MainPage.GoToPlaylist(args[2]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
|
|
||||||
{
|
|
||||||
throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnSuspending(object sender, SuspendingEventArgs e)
|
|
||||||
{
|
|
||||||
var deferral = e.SuspendingOperation.GetDeferral();
|
|
||||||
|
|
||||||
sw.Stop();
|
|
||||||
SettingsStorage.Uptime += sw.Elapsed;
|
|
||||||
|
|
||||||
HistorySet.Save();
|
|
||||||
SettingsStorage.SaveData();
|
|
||||||
DownloadAgent.QuitPrompt();
|
|
||||||
Controls.Player.ManifestGenerator.ClearRoaming();
|
|
||||||
deferral.Complete();
|
|
||||||
Analytics.TrackEvent("Session terminated");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UnhandledError(object sender, Windows.UI.Xaml.UnhandledExceptionEventArgs e)
|
|
||||||
{
|
|
||||||
Analytics.TrackEvent("The app crashed", new Dictionary<string, string>()
|
|
||||||
{
|
|
||||||
{ "Exception", e.Exception.GetType().ToString() },
|
|
||||||
{ "Details", e.Message },
|
|
||||||
{ "StackTrace", e.Exception.StackTrace }
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,7 @@ namespace FoxTube.Classes
|
|||||||
{
|
{
|
||||||
class AdaptiveCommandBar : CommandBar
|
class AdaptiveCommandBar : CommandBar
|
||||||
{
|
{
|
||||||
public AdaptiveCommandBar()
|
public AdaptiveCommandBar() =>
|
||||||
{
|
|
||||||
ClosedDisplayMode = SettingsStorage.AppBarClosedMode;
|
ClosedDisplayMode = SettingsStorage.AppBarClosedMode;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,26 +3,26 @@ using System.Collections.Generic;
|
|||||||
using Windows.Storage;
|
using Windows.Storage;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using YoutubeExplode.Models.MediaStreams;
|
using YoutubeExplode.Models.MediaStreams;
|
||||||
using Google.Apis.YouTube.v3.Data;
|
|
||||||
using FoxTube.Controls;
|
using FoxTube.Controls;
|
||||||
using FoxTube.Pages;
|
using FoxTube.Pages;
|
||||||
using Microsoft.AppCenter.Analytics;
|
using Microsoft.AppCenter.Analytics;
|
||||||
|
using YoutubeExplode.Models;
|
||||||
|
|
||||||
namespace FoxTube
|
namespace FoxTube
|
||||||
{
|
{
|
||||||
public static class DownloadAgent
|
public static class DownloadAgent
|
||||||
{
|
{
|
||||||
public static List<DownloadItem> Items { get; set; } = new List<DownloadItem>();
|
public static List<DownloadItem> Items { get; set; } = new List<DownloadItem>();
|
||||||
private static readonly ApplicationDataContainer settings = ApplicationData.Current.LocalSettings;
|
static readonly ApplicationDataContainer settings = ApplicationData.Current.LocalSettings;
|
||||||
public static Downloads Page { get; set; }
|
public static Downloads Page { get; set; }
|
||||||
public static StorageFolder Downloads { get; set; }
|
public static StorageFolder Downloads { get; set; }
|
||||||
|
|
||||||
public static async void Initialize()
|
public static async void Initialize()
|
||||||
{
|
{
|
||||||
Downloads = await KnownFolders.VideosLibrary.CreateFolderAsync("FoxTube", CreationCollisionOption.OpenIfExists);
|
|
||||||
Items.Clear();
|
Items.Clear();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
Downloads = await KnownFolders.VideosLibrary.CreateFolderAsync("FoxTube", CreationCollisionOption.OpenIfExists);
|
||||||
List<DownloadItemContainer> containers = JsonConvert.DeserializeObject<List<DownloadItemContainer>>((string)settings.Values[$"downloads"]);
|
List<DownloadItemContainer> containers = JsonConvert.DeserializeObject<List<DownloadItemContainer>>((string)settings.Values[$"downloads"]);
|
||||||
containers.ForEach(i => Items.Add(new DownloadItem(i)));
|
containers.ForEach(i => Items.Add(new DownloadItem(i)));
|
||||||
}
|
}
|
||||||
@@ -38,10 +38,8 @@ namespace FoxTube
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Add(MediaStreamInfo info, Video meta, string qualty)
|
public static void Add((MediaStreamInfo info, Video meta, string qualty) e) =>
|
||||||
{
|
Items.Insert(0, new DownloadItem(e.info, e.meta, e.qualty));
|
||||||
Items.Insert(0, new DownloadItem(info, meta, qualty));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Remove(DownloadItem item)
|
public static void Remove(DownloadItem item)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
using Google.Apis.YouTube.v3.Data;
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace FoxTube.Classes
|
||||||
|
{
|
||||||
|
public delegate void SubscriptionsChangedEventHandler(string action, Subscription subscription);
|
||||||
|
public delegate void AuthorizationChangedEventHandler(bool? isAuthorized);
|
||||||
|
public delegate void MinimodeChangedEventHandler(bool isOn);
|
||||||
|
public delegate void SimpleEventHandler();
|
||||||
|
public delegate void PlaylistItemChangedEventHandler(string id);
|
||||||
|
public delegate void NavigationEventHanlder(Type sourcePageType, object parameter);
|
||||||
|
|
||||||
|
public static class Extensions
|
||||||
|
{
|
||||||
|
public static bool Belongs(this double num, double x1, double x2)
|
||||||
|
{
|
||||||
|
return num > x1 && num < x2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface INavigationPage
|
||||||
|
{
|
||||||
|
object Parameter { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ICard
|
||||||
|
{
|
||||||
|
Task Initialize();
|
||||||
|
void ItemClicked();
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum PlayerDisplayState { Normal, Minimized, Compact }
|
||||||
|
}
|
||||||
@@ -9,16 +9,7 @@ namespace FoxTube.Classes
|
|||||||
{
|
{
|
||||||
public InboxItemType Type { get; set; } = InboxItemType.Default;
|
public InboxItemType Type { get; set; } = InboxItemType.Default;
|
||||||
public DateTime TimeStamp { get; set; }
|
public DateTime TimeStamp { get; set; }
|
||||||
public string TimeStampString
|
public string TimeStampString => Type == InboxItemType.PatchNote ? TimeStamp.ToShortDateString() : TimeStamp.ToString();
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (Type == InboxItemType.PatchNote)
|
|
||||||
return TimeStamp.ToShortDateString();
|
|
||||||
else
|
|
||||||
return TimeStamp.ToString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Subject { get; set; }
|
public string Subject { get; set; }
|
||||||
public string Content { get; set; }
|
public string Content { get; set; }
|
||||||
@@ -26,38 +17,10 @@ namespace FoxTube.Classes
|
|||||||
|
|
||||||
private ResourceLoader resources = ResourceLoader.GetForCurrentView("Inbox");
|
private ResourceLoader resources = ResourceLoader.GetForCurrentView("Inbox");
|
||||||
|
|
||||||
public string Icon
|
public string Icon => Type == InboxItemType.PatchNote ? "\xE728" : "\xE119";
|
||||||
{
|
public string Subtitle => Type == InboxItemType.PatchNote ? resources.GetString("changelog") : resources.GetString("dev");
|
||||||
get
|
|
||||||
{
|
|
||||||
if (Type == InboxItemType.PatchNote)
|
|
||||||
return "\xE728";
|
|
||||||
else
|
|
||||||
return "\xE119";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public string Subtitle
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (Type == InboxItemType.PatchNote)
|
|
||||||
return resources.GetString("changelog");
|
|
||||||
else
|
|
||||||
return resources.GetString("dev");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Title
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (Type == InboxItemType.PatchNote)
|
|
||||||
return $"{resources.GetString("whatsnew")}{Id}";
|
|
||||||
else
|
|
||||||
return Subject;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
public string Title => Type == InboxItemType.PatchNote ? $"{resources.GetString("whatsnew")}{Id}" : Subject;
|
||||||
|
|
||||||
public InboxItem(string version, string content, DateTime timeStamp)
|
public InboxItem(string version, string content, DateTime timeStamp)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ using Windows.ApplicationModel.Resources;
|
|||||||
using Windows.Storage;
|
using Windows.Storage;
|
||||||
using YoutubeExplode.Models.MediaStreams;
|
using YoutubeExplode.Models.MediaStreams;
|
||||||
|
|
||||||
namespace FoxTube.Controls.Player
|
namespace FoxTube.Classes
|
||||||
{
|
{
|
||||||
public static class ManifestGenerator
|
public static class ManifestGenerator
|
||||||
{
|
{
|
||||||
@@ -82,7 +82,7 @@ namespace FoxTube.Controls.Player
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static XmlElement GetVideoPresentation(XmlDocument doc, StreamInfo.VideoInfo info)
|
static XmlElement GetVideoPresentation(XmlDocument doc, StreamInfo.VideoInfo info)
|
||||||
{
|
{
|
||||||
XmlElement representation = doc.CreateElement("Representation");
|
XmlElement representation = doc.CreateElement("Representation");
|
||||||
representation.SetAttribute("bandwidth", GetBandwidth(info.Label));
|
representation.SetAttribute("bandwidth", GetBandwidth(info.Label));
|
||||||
@@ -108,7 +108,7 @@ namespace FoxTube.Controls.Player
|
|||||||
return representation;
|
return representation;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static XmlElement GetAudioPresentation(XmlDocument doc, StreamInfo.AudioInfo info)
|
static XmlElement GetAudioPresentation(XmlDocument doc, StreamInfo.AudioInfo info)
|
||||||
{
|
{
|
||||||
XmlElement audio = doc.CreateElement("Representation");
|
XmlElement audio = doc.CreateElement("Representation");
|
||||||
audio.SetAttribute("bandwidth", "200000");
|
audio.SetAttribute("bandwidth", "200000");
|
||||||
@@ -133,7 +133,7 @@ namespace FoxTube.Controls.Player
|
|||||||
return audio;
|
return audio;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<StreamInfo> GetInfoAsync(Video info, VideoStreamInfo requestedQuality)
|
static async Task<StreamInfo> GetInfoAsync(Video info, VideoStreamInfo requestedQuality)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -195,7 +195,7 @@ namespace FoxTube.Controls.Player
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Dictionary<string, string> SplitQuery(string query)
|
static Dictionary<string, string> SplitQuery(string query)
|
||||||
{
|
{
|
||||||
Dictionary<string, string> dic = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
Dictionary<string, string> dic = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||||
string[] paramsEncoded = query.TrimStart('?').Split("&");
|
string[] paramsEncoded = query.TrimStart('?').Split("&");
|
||||||
@@ -221,7 +221,7 @@ namespace FoxTube.Controls.Player
|
|||||||
return dic;
|
return dic;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetBandwidth(string quality)
|
static string GetBandwidth(string quality)
|
||||||
{
|
{
|
||||||
string parsed = quality.Split('p')[0];
|
string parsed = quality.Split('p')[0];
|
||||||
switch (quality)
|
switch (quality)
|
||||||
@@ -301,41 +301,4 @@ namespace FoxTube.Controls.Player
|
|||||||
await f.DeleteAsync(StorageDeleteOption.PermanentDelete);
|
await f.DeleteAsync(StorageDeleteOption.PermanentDelete);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class StreamInfo
|
|
||||||
{
|
|
||||||
public class VideoInfo
|
|
||||||
{
|
|
||||||
public string IndexRange { get; set; }
|
|
||||||
public string InitRange => $"0-{int.Parse(IndexRange.Split('-')[0]) - 1}";
|
|
||||||
public string Itag { get; set; }
|
|
||||||
public string Fps { get; set; }
|
|
||||||
public string Url { get; set; }
|
|
||||||
public string Codecs { get; set; }
|
|
||||||
public string MimeType { get; set; }
|
|
||||||
public string Height { get; set; }
|
|
||||||
public string Width { get; set; }
|
|
||||||
public string Label { get; set; }
|
|
||||||
}
|
|
||||||
public class AudioInfo
|
|
||||||
{
|
|
||||||
public string IndexRange { get; set; }
|
|
||||||
public string InitRange => $"0-{int.Parse(IndexRange.Split('-')[0]) - 1}";
|
|
||||||
public string SampleRate { get; set; }
|
|
||||||
public string ChannelsCount { get; set; }
|
|
||||||
public string Codecs { get; set; }
|
|
||||||
public string MimeType { get; set; }
|
|
||||||
public string Url { get; set; }
|
|
||||||
public string Itag { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<VideoInfo> Video { get; } = new List<VideoInfo>();
|
|
||||||
public List<AudioInfo> Audio { get; } = new List<AudioInfo>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public class StreamQuality
|
|
||||||
{
|
|
||||||
public Uri Url { get; set; }
|
|
||||||
public string Resolution { get; set; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+57
-71
@@ -1,6 +1,7 @@
|
|||||||
using FoxTube.Pages;
|
using FoxTube.Classes;
|
||||||
|
using FoxTube.Controls.VideoPage;
|
||||||
|
using Google.Apis.YouTube.v3.Data;
|
||||||
using Microsoft.AppCenter.Analytics;
|
using Microsoft.AppCenter.Analytics;
|
||||||
using Newtonsoft.Json;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
@@ -9,7 +10,6 @@ using System.Net.Mail;
|
|||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using Windows.ApplicationModel.Core;
|
|
||||||
using Windows.ApplicationModel.DataTransfer;
|
using Windows.ApplicationModel.DataTransfer;
|
||||||
using Windows.ApplicationModel.Resources;
|
using Windows.ApplicationModel.Resources;
|
||||||
using Windows.Storage.Streams;
|
using Windows.Storage.Streams;
|
||||||
@@ -26,21 +26,47 @@ namespace FoxTube
|
|||||||
|
|
||||||
public delegate void ObjectEventHandler(object sender = null, params object[] args);
|
public delegate void ObjectEventHandler(object sender = null, params object[] args);
|
||||||
|
|
||||||
public interface INavigationPage
|
|
||||||
{
|
|
||||||
object Parameter { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Methods
|
public static class Methods
|
||||||
{
|
{
|
||||||
private static readonly ResourceLoader resources = ResourceLoader.GetForCurrentView("Methods");
|
private static readonly ResourceLoader resources = ResourceLoader.GetForCurrentView("Methods");
|
||||||
|
|
||||||
public static CommentsPage CommentsPage { get; set; }
|
public static Comments CommentsPage { get; set; }
|
||||||
public static MainPage MainPage => (Window.Current.Content as Frame).Content as MainPage;
|
public static MainPage MainPage => (Window.Current.Content as Frame).Content as MainPage;
|
||||||
|
|
||||||
public static void CloseApp()
|
public static async Task<bool> AddItemToWL(string id)
|
||||||
{
|
{
|
||||||
CoreApplication.Exit();
|
try
|
||||||
|
{
|
||||||
|
SecretsVault.RefreshToken();
|
||||||
|
|
||||||
|
PlaylistItem item = new PlaylistItem
|
||||||
|
{
|
||||||
|
Snippet = new PlaylistItemSnippet
|
||||||
|
{
|
||||||
|
ResourceId = new ResourceId
|
||||||
|
{
|
||||||
|
Kind = "youtube#video",
|
||||||
|
VideoId = id
|
||||||
|
},
|
||||||
|
PlaylistId = "WL"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
await SecretsVault.Service.PlaylistItems.Insert(item, "snippet").ExecuteAsync();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Analytics.TrackEvent("Failed to add video to WL", new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
{ "Exception", e.GetType().ToString() },
|
||||||
|
{ "Message", e.Message },
|
||||||
|
{ "Video ID", id },
|
||||||
|
{ "StackTrace", e.StackTrace }
|
||||||
|
});
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Uri ToUri(this string url)
|
public static Uri ToUri(this string url)
|
||||||
@@ -49,10 +75,8 @@ namespace FoxTube
|
|||||||
catch { return null; }
|
catch { return null; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GuardFromNull(string str)
|
public static string GuardFromNull(string str) =>
|
||||||
{
|
str ?? string.Empty;
|
||||||
return str ?? string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SendMail(string content)
|
public static void SendMail(string content)
|
||||||
{
|
{
|
||||||
@@ -68,22 +92,6 @@ namespace FoxTube
|
|||||||
client.Send(msg);
|
client.Send(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Obsolete]
|
|
||||||
public static string GetChars(this string str, int count)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
string s = "";
|
|
||||||
for (int i = 0; i < count; i++)
|
|
||||||
s += str[i];
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<object> ToReversedList(this Array array)
|
public static List<object> ToReversedList(this Array array)
|
||||||
{
|
{
|
||||||
List<object> list = new List<object>();
|
List<object> list = new List<object>();
|
||||||
@@ -93,22 +101,15 @@ namespace FoxTube
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ForEach<T>(this IEnumerable<T> array, Action<T> action)
|
public static void ForEach<T>(this IEnumerable<T> array, Action<T> action) =>
|
||||||
{
|
|
||||||
array.ToList().ForEach(action);
|
array.ToList().ForEach(action);
|
||||||
}
|
|
||||||
|
|
||||||
public static T Find<T>(this IEnumerable<T> array, Predicate<T> match)
|
public static T Find<T>(this IEnumerable<T> array, Predicate<T> match) =>
|
||||||
{
|
array.ToList().Find(match);
|
||||||
return array.ToList().Find(match);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<T> FindAll<T>(this IEnumerable<T> array, Predicate<T> match)
|
public static List<T> FindAll<T>(this IEnumerable<T> array, Predicate<T> match) =>
|
||||||
{
|
array.ToList().FindAll(match);
|
||||||
return array.ToList().FindAll(match);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Obsolete]
|
|
||||||
public static string ReplaceInvalidChars(this string str, char newValue)
|
public static string ReplaceInvalidChars(this string str, char newValue)
|
||||||
{
|
{
|
||||||
foreach (char i in Path.GetInvalidFileNameChars())
|
foreach (char i in Path.GetInvalidFileNameChars())
|
||||||
@@ -116,12 +117,7 @@ namespace FoxTube
|
|||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Obsolete]
|
[Obsolete("Use *YoutubeExplode.Models.Video instead*")]
|
||||||
public static string Last(this string[] arr)
|
|
||||||
{
|
|
||||||
return arr[arr.Length - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static TimeSpan GetDuration(this string str)
|
public static TimeSpan GetDuration(this string str)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -243,6 +239,8 @@ namespace FoxTube
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async static void ProcessLink(string url)
|
public async static void ProcessLink(string url)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
string type;
|
string type;
|
||||||
|
|
||||||
@@ -274,19 +272,21 @@ namespace FoxTube
|
|||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case "channel":
|
case "channel":
|
||||||
MainPage.GoToChannel(output);
|
Navigation.GoToChannel(output);
|
||||||
break;
|
break;
|
||||||
case "video":
|
case "video":
|
||||||
MainPage.GoToVideo(output);
|
Navigation.GoToVideo(output);
|
||||||
break;
|
break;
|
||||||
case "playlist":
|
case "playlist":
|
||||||
MainPage.GoToPlaylist(output);
|
Navigation.GoToPlaylist(output);
|
||||||
break;
|
break;
|
||||||
case "user":
|
case "user":
|
||||||
MainPage.GoToChannel(await new YoutubeClient().GetChannelIdAsync(output));
|
Navigation.GoToChannel(await new YoutubeClient().GetChannelIdAsync(output));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
|
||||||
public static void Share(DataRequestedEventArgs args, string thumbnail, string title, string url, string type)
|
public static void Share(DataRequestedEventArgs args, string thumbnail, string title, string url, string type)
|
||||||
{
|
{
|
||||||
@@ -302,32 +302,18 @@ namespace FoxTube
|
|||||||
request.Data.SetBitmap(RandomAccessStreamReference.CreateFromUri(thumbnail.ToUri()));
|
request.Data.SetBitmap(RandomAccessStreamReference.CreateFromUri(thumbnail.ToUri()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<List<string>> GetHistory()
|
public static async Task<YoutubeExplode.Models.Playlist> GetHistory()
|
||||||
{
|
{
|
||||||
SecretsVault.RefreshToken();
|
SecretsVault.RefreshToken();
|
||||||
List<string> list = new List<string>();
|
|
||||||
|
|
||||||
string output = await SecretsVault.HttpClient.GetStringAsync($"https://www.youtube.com/list_ajax?style=json&action_get_list=1&list=HL&hl={SettingsStorage.RelevanceLanguage}");
|
return await new YoutubeClient(SecretsVault.HttpClient).GetPlaylistAsync("HL");
|
||||||
|
|
||||||
dynamic raw = JsonConvert.DeserializeObject(output);
|
|
||||||
foreach (dynamic i in raw.video)
|
|
||||||
list.Add(i.encrypted_id.ToString());
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<List<string>> GetLater()
|
public static async Task<YoutubeExplode.Models.Playlist> GetLater()
|
||||||
{
|
{
|
||||||
SecretsVault.RefreshToken();
|
SecretsVault.RefreshToken();
|
||||||
List<string> list = new List<string>();
|
|
||||||
|
|
||||||
string output = await SecretsVault.HttpClient.GetStringAsync($"https://www.youtube.com/list_ajax?style=json&action_get_list=1&list=WL&hl={SettingsStorage.RelevanceLanguage}");
|
return await new YoutubeClient(SecretsVault.HttpClient).GetPlaylistAsync("WL");
|
||||||
|
|
||||||
dynamic raw = JsonConvert.DeserializeObject(output);
|
|
||||||
foreach (dynamic i in raw.video)
|
|
||||||
list.Add(i.encrypted_id.ToString());
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
using FoxTube.Pages;
|
||||||
|
using Google.Apis.YouTube.v3.Data;
|
||||||
|
using Windows.UI.Xaml;
|
||||||
|
using Windows.UI.Xaml.Controls;
|
||||||
|
|
||||||
|
namespace FoxTube.Classes
|
||||||
|
{
|
||||||
|
public static class Navigation
|
||||||
|
{
|
||||||
|
public static MainFrame Frame => ((Window.Current.Content as Frame).Content as MainPage).Content;
|
||||||
|
|
||||||
|
public static void GoToSearch(SearchParameters args) =>
|
||||||
|
Frame.NavigateTo(typeof(Search), new object[] { args, Frame.Frame });
|
||||||
|
|
||||||
|
public static void GoToChannel(string id) =>
|
||||||
|
Frame.NavigateTo(typeof(ChannelPage), id);
|
||||||
|
|
||||||
|
public static void GoToHome() =>
|
||||||
|
Frame.NavigateTo(typeof(Home));
|
||||||
|
|
||||||
|
public static void GoToVideo(string id, string playlistId = null, bool incognito = false) =>
|
||||||
|
Frame.OpenVideo(id, playlistId, incognito);
|
||||||
|
|
||||||
|
public static void GoToDeveloper(string id) =>
|
||||||
|
Frame.NavigateTo(typeof(Settings), id);
|
||||||
|
|
||||||
|
public static void GoToPlaylist(string id) =>
|
||||||
|
Frame.NavigateTo(typeof(PlaylistPage), id);
|
||||||
|
|
||||||
|
public static void GoToHistory() =>
|
||||||
|
Frame.NavigateTo(typeof(History));
|
||||||
|
|
||||||
|
public static void GoToDownloads() =>
|
||||||
|
Frame.NavigateTo(typeof(Downloads));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,299 @@
|
|||||||
|
using Microsoft.AppCenter;
|
||||||
|
using Microsoft.AppCenter.Analytics;
|
||||||
|
using Microsoft.Services.Store.Engagement;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Xml;
|
||||||
|
using Windows.ApplicationModel;
|
||||||
|
using Windows.ApplicationModel.Background;
|
||||||
|
using Windows.ApplicationModel.DataTransfer;
|
||||||
|
using Windows.ApplicationModel.Resources;
|
||||||
|
using Windows.Storage;
|
||||||
|
using Windows.System;
|
||||||
|
using Windows.System.Power;
|
||||||
|
using Windows.UI.Notifications;
|
||||||
|
using Windows.UI.Popups;
|
||||||
|
using Windows.UI.Xaml;
|
||||||
|
using Windows.UI.Core;
|
||||||
|
|
||||||
|
namespace FoxTube.Classes
|
||||||
|
{
|
||||||
|
public static class Processes
|
||||||
|
{
|
||||||
|
static Stopwatch sw = new Stopwatch();
|
||||||
|
public static async void InitializeApp() => await CoreWindow.GetForCurrentThread().Dispatcher.RunAsync(CoreDispatcherPriority.High, () =>
|
||||||
|
{
|
||||||
|
CheckVersion();
|
||||||
|
|
||||||
|
RegisterToastTask();
|
||||||
|
ActivateBackgoundTask();
|
||||||
|
|
||||||
|
AppCenter.Start("45774462-9ea7-438a-96fc-03982666f39e", typeof(Analytics));
|
||||||
|
AppCenter.SetCountryCode(SettingsStorage.Region);
|
||||||
|
|
||||||
|
sw.Start();
|
||||||
|
|
||||||
|
SecretsVault.Initialize();
|
||||||
|
DownloadAgent.Initialize();
|
||||||
|
|
||||||
|
if (SettingsStorage.ProcessClipboard)
|
||||||
|
{
|
||||||
|
Clipboard.ContentChanged += ParseClipboard;
|
||||||
|
ParseClipboard();
|
||||||
|
}
|
||||||
|
|
||||||
|
PromptFeedback();
|
||||||
|
});
|
||||||
|
|
||||||
|
public static void SuspendApp()
|
||||||
|
{
|
||||||
|
sw.Stop();
|
||||||
|
SettingsStorage.Uptime += sw.Elapsed;
|
||||||
|
|
||||||
|
HistorySet.Save();
|
||||||
|
SettingsStorage.SaveData();
|
||||||
|
DownloadAgent.QuitPrompt();
|
||||||
|
ManifestGenerator.ClearRoaming();
|
||||||
|
Analytics.TrackEvent("Session terminated", new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
{ "Uptime", sw.Elapsed.ToString() },
|
||||||
|
{ "Total time", SettingsStorage.Uptime.ToString() }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async void ProcessToast(string arg)
|
||||||
|
{
|
||||||
|
string[] args = arg.Split('|');
|
||||||
|
switch (args[0])
|
||||||
|
{
|
||||||
|
case "changelog":
|
||||||
|
case "inbox":
|
||||||
|
Navigation.GoToDeveloper(args[1]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "video":
|
||||||
|
Navigation.GoToVideo(args[1]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "channel":
|
||||||
|
Navigation.GoToChannel(args[1]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "download":
|
||||||
|
Navigation.GoToDownloads();
|
||||||
|
break;
|
||||||
|
case "dcancel":
|
||||||
|
DownloadAgent.Cancel(args[1]);
|
||||||
|
break;
|
||||||
|
case "clipboard":
|
||||||
|
switch (args[1])
|
||||||
|
{
|
||||||
|
case "video":
|
||||||
|
Navigation.GoToVideo(args[2]);
|
||||||
|
break;
|
||||||
|
case "channel":
|
||||||
|
Navigation.GoToChannel(args[2]);
|
||||||
|
break;
|
||||||
|
case "playlist":
|
||||||
|
Navigation.GoToPlaylist(args[2]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "later":
|
||||||
|
if (SecretsVault.IsAuthorized)
|
||||||
|
await Methods.AddItemToWL(args[1]);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SecretsVault.AuthorizationStateChanged += async (e) =>
|
||||||
|
{
|
||||||
|
if (e.Value)
|
||||||
|
await Methods.AddItemToWL(args[1]);
|
||||||
|
};
|
||||||
|
SecretsVault.CheckAuthorization(false);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static async void PromptFeedback()
|
||||||
|
{
|
||||||
|
ResourceLoader resources = ResourceLoader.GetForCurrentView("Main");
|
||||||
|
|
||||||
|
if (SettingsStorage.Uptime.TotalHours >= 12 && SettingsStorage.PromptFeedback)
|
||||||
|
{
|
||||||
|
MessageDialog dialog = new MessageDialog(resources.GetString("/Main/feedbackMessage"));
|
||||||
|
dialog.Commands.Add(new UICommand(resources.GetString("/Main/dontAsk"), (command) => SettingsStorage.PromptFeedback = false));
|
||||||
|
dialog.Commands.Add(new UICommand(resources.GetString("/Main/promptLater")));
|
||||||
|
dialog.Commands.Add(new UICommand(resources.GetString("/Main/sure"), async (command) =>
|
||||||
|
{
|
||||||
|
SettingsStorage.PromptFeedback = false;
|
||||||
|
if (StoreServicesFeedbackLauncher.IsSupported())
|
||||||
|
await StoreServicesFeedbackLauncher.GetDefault().LaunchAsync();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MessageDialog message = new MessageDialog(resources.GetString("/Main/feedbackFail"));
|
||||||
|
message.Commands.Add(new UICommand(resources.GetString("/Main/sendEmail"), async (c) => await Launcher.LaunchUriAsync("mailto:michael.xfox@outlook.com".ToUri())));
|
||||||
|
message.Commands.Add(new UICommand(resources.GetString("/Main/goBack")));
|
||||||
|
message.CancelCommandIndex = 1;
|
||||||
|
message.DefaultCommandIndex = 0;
|
||||||
|
await message.ShowAsync();
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
dialog.DefaultCommandIndex = 2;
|
||||||
|
dialog.CancelCommandIndex = 1;
|
||||||
|
await dialog.ShowAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SettingsStorage.Uptime.TotalHours >= 24 && SettingsStorage.PromptReview)
|
||||||
|
{
|
||||||
|
MessageDialog dialog = new MessageDialog(resources.GetString("/Main/rate"));
|
||||||
|
dialog.Commands.Add(new UICommand(resources.GetString("/Main/dontAsk"), (command) => SettingsStorage.PromptReview = false));
|
||||||
|
dialog.Commands.Add(new UICommand(resources.GetString("/Main/promptLater")));
|
||||||
|
dialog.Commands.Add(new UICommand(resources.GetString("/Main/sure"), async (command) =>
|
||||||
|
{
|
||||||
|
SettingsStorage.PromptReview = false;
|
||||||
|
await Launcher.LaunchUriAsync("ms-windows-store://review/?ProductId=9NCQQXJTDLFH".ToUri());
|
||||||
|
}));
|
||||||
|
dialog.DefaultCommandIndex = 2;
|
||||||
|
dialog.CancelCommandIndex = 1;
|
||||||
|
await dialog.ShowAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async void ParseClipboard(object sender = null, object e = null)
|
||||||
|
{
|
||||||
|
ResourceLoader resources = ResourceLoader.GetForCurrentView("Main");
|
||||||
|
|
||||||
|
if (Window.Current.CoreWindow.ActivationMode != Windows.UI.Core.CoreWindowActivationMode.ActivatedInForeground || !SettingsStorage.ProcessClipboard)
|
||||||
|
return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string link = await Clipboard.GetContent().GetTextAsync();
|
||||||
|
|
||||||
|
if (!link.Contains("youtube") && !link.Contains("youtu.be"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
string id;
|
||||||
|
string type = string.Empty;
|
||||||
|
string name = string.Empty;
|
||||||
|
|
||||||
|
if (YoutubeExplode.YoutubeClient.TryParseChannelId(link, out id))
|
||||||
|
{
|
||||||
|
type = "channel";
|
||||||
|
name = (await new YoutubeExplode.YoutubeClient().GetChannelAsync(id)).Title;
|
||||||
|
}
|
||||||
|
else if (YoutubeExplode.YoutubeClient.TryParsePlaylistId(link, out id))
|
||||||
|
{
|
||||||
|
type = "playlist";
|
||||||
|
name = (await new YoutubeExplode.YoutubeClient().GetPlaylistAsync(id)).Title;
|
||||||
|
}
|
||||||
|
else if (YoutubeExplode.YoutubeClient.TryParseUsername(link, out id))
|
||||||
|
{
|
||||||
|
id = await new YoutubeExplode.YoutubeClient().GetChannelIdAsync(id);
|
||||||
|
type = "channel";
|
||||||
|
name = (await new YoutubeExplode.YoutubeClient().GetChannelAsync(id)).Title;
|
||||||
|
}
|
||||||
|
else if (YoutubeExplode.YoutubeClient.TryParseVideoId(link, out id))
|
||||||
|
{
|
||||||
|
type = "video";
|
||||||
|
name = (await new YoutubeExplode.YoutubeClient().GetVideoAsync(id)).Title;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(string.IsNullOrWhiteSpace(id))
|
||||||
|
return;
|
||||||
|
|
||||||
|
Windows.Data.Xml.Dom.XmlDocument toastXml = new Windows.Data.Xml.Dom.XmlDocument();
|
||||||
|
toastXml.LoadXml($@"<toast launch='clipboard|{type}|{id}'>
|
||||||
|
<visual>
|
||||||
|
<binding template='ToastGeneric'>
|
||||||
|
<text>{resources.GetString("/Main/clipboardHead")}</text>
|
||||||
|
<text>{name}</text>
|
||||||
|
<text>{resources.GetString($"/Main/{type}")}</text>
|
||||||
|
</binding>
|
||||||
|
</visual>
|
||||||
|
<actions>
|
||||||
|
<action content='{resources.GetString("/Main/clipboardOpen")}' arguments='clipboard|{type}|{id}'/>
|
||||||
|
</actions>
|
||||||
|
</toast>");
|
||||||
|
ToastNotificationManager.CreateToastNotifier().Show(new ToastNotification(toastXml));
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Comparing current version with last recorded version. If doesn't match, poping up changelog notification
|
||||||
|
/// </summary>
|
||||||
|
static async void CheckVersion()
|
||||||
|
{
|
||||||
|
PackageVersion ver = Package.Current.Id.Version;
|
||||||
|
if (SettingsStorage.Version != $"{ver.Major}.{ver.Minor}.{ver.Build}")
|
||||||
|
try
|
||||||
|
{
|
||||||
|
XmlDocument changelog = new XmlDocument();
|
||||||
|
StorageFile file = await (await Package.Current.InstalledLocation.GetFolderAsync(@"Assets\Data")).GetFileAsync("Patchnotes.xml");
|
||||||
|
changelog.Load(await file.OpenStreamForReadAsync());
|
||||||
|
|
||||||
|
ToastNotificationManager.CreateToastNotifier().Show(Background.Notification.GetChangelogToast(changelog["items"].FirstChild.Attributes["version"].Value));
|
||||||
|
|
||||||
|
SettingsStorage.Version = $"{ver.Major}.{ver.Minor}.{ver.Build}";
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Analytics.TrackEvent("Unable to retrieve changelog", new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
{ "Exception", e.GetType().ToString() },
|
||||||
|
{ "Message", e.Message },
|
||||||
|
{ "App version", $"{ver.Major}.{ver.Minor}.{ver.Revision}.{ver.Build}" },
|
||||||
|
{ "StackTrace", e.StackTrace }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes background task for processing toast notifications' clicks
|
||||||
|
/// </summary>
|
||||||
|
static async void RegisterToastTask()
|
||||||
|
{
|
||||||
|
const string taskName = "FoxtubeToastBackground";
|
||||||
|
if (BackgroundTaskRegistration.AllTasks.Any(i => i.Value.Name.Equals(taskName)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var backgroundRequest = await BackgroundExecutionManager.RequestAccessAsync();
|
||||||
|
if (backgroundRequest == BackgroundAccessStatus.DeniedBySystemPolicy || backgroundRequest == BackgroundAccessStatus.DeniedByUser)
|
||||||
|
return;
|
||||||
|
|
||||||
|
BackgroundTaskBuilder builder = new BackgroundTaskBuilder() { Name = taskName };
|
||||||
|
builder.SetTrigger(new ToastNotificationActionTrigger());
|
||||||
|
|
||||||
|
BackgroundTaskRegistration registration = builder.Register();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes background task for checking user's subscriptions and poping toast notifications when new video is uploaded
|
||||||
|
/// </summary>
|
||||||
|
static async void ActivateBackgoundTask()
|
||||||
|
{
|
||||||
|
const string taskName = "FoxtubeBackgound";
|
||||||
|
if (BackgroundTaskRegistration.AllTasks.Any(i => i.Value.Name.Equals(taskName)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var backgroundRequest = await BackgroundExecutionManager.RequestAccessAsync();
|
||||||
|
var saverRequest = PowerManager.EnergySaverStatus;
|
||||||
|
if (backgroundRequest == BackgroundAccessStatus.DeniedBySystemPolicy || backgroundRequest == BackgroundAccessStatus.DeniedByUser || saverRequest == EnergySaverStatus.On)
|
||||||
|
return;
|
||||||
|
|
||||||
|
BackgroundTaskBuilder builder = new BackgroundTaskBuilder()
|
||||||
|
{
|
||||||
|
Name = taskName,
|
||||||
|
IsNetworkRequested = true,
|
||||||
|
TaskEntryPoint = "FoxTube.Background.BackgroundProcessor"
|
||||||
|
};
|
||||||
|
builder.SetTrigger(new TimeTrigger(15, false));
|
||||||
|
|
||||||
|
BackgroundTaskRegistration registration = builder.Register();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace FoxTube.Classes
|
||||||
|
{
|
||||||
|
public class QualityComparer : IComparer<string>
|
||||||
|
{
|
||||||
|
public int Compare(string x, string y)
|
||||||
|
{
|
||||||
|
string[] xArr = x.Split('p');
|
||||||
|
string[] yArr = y.Split('p');
|
||||||
|
|
||||||
|
int qualityA = int.Parse(xArr[0]);
|
||||||
|
int qualityB = int.Parse(yArr[0]);
|
||||||
|
int framerateA = 30;
|
||||||
|
int framerateB = 30;
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(xArr[1]))
|
||||||
|
framerateA = int.Parse(xArr[1]);
|
||||||
|
if (!string.IsNullOrWhiteSpace(yArr[1]))
|
||||||
|
framerateB = int.Parse(yArr[1]);
|
||||||
|
|
||||||
|
if (qualityA > qualityB)
|
||||||
|
return 1;
|
||||||
|
else if (qualityA < qualityB)
|
||||||
|
return -1;
|
||||||
|
else
|
||||||
|
return framerateA - framerateB > 0 ? 1 : -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,8 +6,6 @@ using Google.Apis.Auth.OAuth2;
|
|||||||
using Google.Apis.Services;
|
using Google.Apis.Services;
|
||||||
using Google.Apis.YouTube.v3;
|
using Google.Apis.YouTube.v3;
|
||||||
using Google.Apis.YouTube.v3.Data;
|
using Google.Apis.YouTube.v3.Data;
|
||||||
using Newtonsoft.Json;
|
|
||||||
using Windows.Storage;
|
|
||||||
using Windows.Services.Store;
|
using Windows.Services.Store;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using Google.Apis.Oauth2.v2.Data;
|
using Google.Apis.Oauth2.v2.Data;
|
||||||
@@ -15,6 +13,8 @@ using Google.Apis.Oauth2.v2;
|
|||||||
using static Google.Apis.Auth.OAuth2.UwpCodeReceiver;
|
using static Google.Apis.Auth.OAuth2.UwpCodeReceiver;
|
||||||
using Microsoft.AppCenter.Analytics;
|
using Microsoft.AppCenter.Analytics;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using FoxTube.Classes;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace FoxTube
|
namespace FoxTube
|
||||||
{
|
{
|
||||||
@@ -22,12 +22,12 @@ namespace FoxTube
|
|||||||
{
|
{
|
||||||
#region Properties
|
#region Properties
|
||||||
//Events
|
//Events
|
||||||
public static event ObjectEventHandler AuthorizationStateChanged;
|
public static event AuthorizationChangedEventHandler AuthorizationStateChanged;
|
||||||
public static event ObjectEventHandler SubscriptionsChanged;
|
public static event SubscriptionsChangedEventHandler SubscriptionsChanged;
|
||||||
public static event ObjectEventHandler Purchased; //Rising when app finds out that it's not a PRO version
|
public static event ObjectEventHandler Purchased; //Rising when app finds out that it's not a PRO version or after purchase
|
||||||
|
|
||||||
//Properties
|
//Properties
|
||||||
public static NetworkCredential EmailCredential => new NetworkCredential("mikhailagord@gmail.com", "JkY39w$.7?bT57O,8k3a");
|
public static NetworkCredential EmailCredential => new NetworkCredential("foxtube.bot@xfox111.net", "JkY39w$.7?bT57O,8k3a");
|
||||||
private static ClientSecrets Secrets => new ClientSecrets
|
private static ClientSecrets Secrets => new ClientSecrets
|
||||||
{
|
{
|
||||||
ClientId = "349735264870-2ekqlm0a4mkg3mmrfcv90s3qp3o15dq0.apps.googleusercontent.com",
|
ClientId = "349735264870-2ekqlm0a4mkg3mmrfcv90s3qp3o15dq0.apps.googleusercontent.com",
|
||||||
@@ -38,7 +38,7 @@ namespace FoxTube
|
|||||||
ApiKey = "AIzaSyBgHrCnrlzlVmk0cJKL8RqP9Y8x6XSuk_0",
|
ApiKey = "AIzaSyBgHrCnrlzlVmk0cJKL8RqP9Y8x6XSuk_0",
|
||||||
ApplicationName = "FoxTube"
|
ApplicationName = "FoxTube"
|
||||||
});
|
});
|
||||||
public static BaseClientService.Initializer Initializer => new BaseClientService.Initializer
|
private static BaseClientService.Initializer Initializer => new BaseClientService.Initializer
|
||||||
{
|
{
|
||||||
HttpClientInitializer = Credential,
|
HttpClientInitializer = Credential,
|
||||||
ApplicationName = "FoxTube"
|
ApplicationName = "FoxTube"
|
||||||
@@ -46,7 +46,7 @@ namespace FoxTube
|
|||||||
public static YouTubeService Service => IsAuthorized ? new YouTubeService(Initializer) : NoAuthService;
|
public static YouTubeService Service => IsAuthorized ? new YouTubeService(Initializer) : NoAuthService;
|
||||||
|
|
||||||
public static HttpClient HttpClient { get; } = new HttpClient();
|
public static HttpClient HttpClient { get; } = new HttpClient();
|
||||||
private static bool TestAds => false; //TODO: Change this bool
|
private static bool TestAds => true; //TODO: Change this bool
|
||||||
public static string AppId => TestAds ? "d25517cb-12d4-4699-8bdc-52040c712cab" : "9ncqqxjtdlfh";
|
public static string AppId => TestAds ? "d25517cb-12d4-4699-8bdc-52040c712cab" : "9ncqqxjtdlfh";
|
||||||
public static string AdUnitId => TestAds ? "test" : "1100037769";
|
public static string AdUnitId => TestAds ? "test" : "1100037769";
|
||||||
public static bool AdsDisabled { get; private set; } = true;
|
public static bool AdsDisabled { get; private set; } = true;
|
||||||
@@ -60,15 +60,13 @@ namespace FoxTube
|
|||||||
public static Userinfoplus UserInfo { get; private set; }
|
public static Userinfoplus UserInfo { get; private set; }
|
||||||
|
|
||||||
public static List<Subscription> Subscriptions { get; } = new List<Subscription>();
|
public static List<Subscription> Subscriptions { get; } = new List<Subscription>();
|
||||||
public static List<string> History { get; set; } = new List<string>();
|
public static YoutubeExplode.Models.Playlist History { get; set; }
|
||||||
public static List<string> WatchLater { get; set; } = new List<string>();
|
public static YoutubeExplode.Models.Playlist WatchLater { get; set; }
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Methods
|
#region Methods
|
||||||
public static void RefreshToken()
|
public static void RefreshToken() =>
|
||||||
{
|
|
||||||
Credential?.RefreshTokenAsync(CancellationToken.None);
|
Credential?.RefreshTokenAsync(CancellationToken.None);
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Subscribes or unsibscribes authorized user from the channel
|
/// Subscribes or unsibscribes authorized user from the channel
|
||||||
@@ -77,26 +75,23 @@ namespace FoxTube
|
|||||||
/// <returns>Returns 'true' if channel is in subscriptions now; 'false' if it's not</returns>
|
/// <returns>Returns 'true' if channel is in subscriptions now; 'false' if it's not</returns>
|
||||||
public static async Task<bool> ChangeSubscriptionState(string id)
|
public static async Task<bool> ChangeSubscriptionState(string id)
|
||||||
{
|
{
|
||||||
if(Subscriptions.Exists(x => x.Snippet.ResourceId.ChannelId == id))
|
if(Subscriptions.Find(i => i.Snippet.ResourceId.ChannelId == id) is Subscription subscription)
|
||||||
{
|
{
|
||||||
Subscription s = Subscriptions.Find(x => x.Snippet.ResourceId.ChannelId == id);
|
try { await Service.Subscriptions.Delete(subscription.Id).ExecuteAsync(); }
|
||||||
|
|
||||||
try { await Service.Subscriptions.Delete(s.Id).ExecuteAsync(); }
|
|
||||||
catch { return true; }
|
catch { return true; }
|
||||||
|
|
||||||
SubscriptionsChanged?.Invoke(null, "remove", s);
|
SubscriptionsChanged?.Invoke("remove", subscription);
|
||||||
Subscriptions.Remove(s);
|
Subscriptions.Remove(subscription);
|
||||||
|
|
||||||
SaveSubscriptions();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var request = Service.Subscriptions.Insert(new Subscription()
|
var request = Service.Subscriptions.Insert(new Subscription
|
||||||
{
|
{
|
||||||
Snippet = new SubscriptionSnippet()
|
Snippet = new SubscriptionSnippet
|
||||||
{
|
{
|
||||||
ResourceId = new ResourceId()
|
ResourceId = new ResourceId
|
||||||
{
|
{
|
||||||
ChannelId = id,
|
ChannelId = id,
|
||||||
Kind = "youtube#channel"
|
Kind = "youtube#channel"
|
||||||
@@ -104,13 +99,12 @@ namespace FoxTube
|
|||||||
}
|
}
|
||||||
}, "snippet");
|
}, "snippet");
|
||||||
|
|
||||||
Subscription s = await request.ExecuteAsync();
|
if (!(await request.ExecuteAsync() is Subscription sub))
|
||||||
if (s == null)
|
|
||||||
return false;
|
return false;
|
||||||
Subscriptions.Add(s);
|
|
||||||
SubscriptionsChanged?.Invoke(null, "add", s);
|
|
||||||
|
|
||||||
SaveSubscriptions();
|
Subscriptions.Add(sub);
|
||||||
|
SubscriptionsChanged?.Invoke("add", sub);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -140,23 +134,17 @@ namespace FoxTube
|
|||||||
Oauth2Service.Scope.UserinfoProfile,
|
Oauth2Service.Scope.UserinfoProfile,
|
||||||
Oauth2Service.Scope.UserinfoEmail,
|
Oauth2Service.Scope.UserinfoEmail,
|
||||||
YouTubeService.Scope.YoutubeForceSsl,
|
YouTubeService.Scope.YoutubeForceSsl,
|
||||||
YouTubeService.Scope.Youtube,
|
YouTubeService.Scope.YoutubeUpload
|
||||||
YouTubeService.Scope.YoutubeUpload,
|
|
||||||
YouTubeService.Scope.YoutubeReadonly,
|
|
||||||
YouTubeService.Scope.Youtubepartner
|
|
||||||
},
|
},
|
||||||
"user",
|
"user",
|
||||||
CancellationToken.None);
|
CancellationToken.None);
|
||||||
|
|
||||||
await Credential.RefreshTokenAsync(CancellationToken.None);
|
await Credential.RefreshTokenAsync(CancellationToken.None);
|
||||||
}
|
}
|
||||||
catch (AuthenticateException e)
|
catch (AuthenticateException e) when (e.Message.Contains("UserCancel")) { }
|
||||||
|
catch(Exception e)
|
||||||
{
|
{
|
||||||
if (e.Message.Contains("UserCancel"))
|
AuthorizationStateChanged?.Invoke(null);
|
||||||
return;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AuthorizationStateChanged?.Invoke(args: new bool?[] { null });
|
|
||||||
Analytics.TrackEvent("Failed to authorize", new Dictionary<string, string>
|
Analytics.TrackEvent("Failed to authorize", new Dictionary<string, string>
|
||||||
{
|
{
|
||||||
{ "Exception", e.GetType().ToString() },
|
{ "Exception", e.GetType().ToString() },
|
||||||
@@ -164,7 +152,6 @@ namespace FoxTube
|
|||||||
{ "StackTrace", e.StackTrace }
|
{ "StackTrace", e.StackTrace }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (Credential == null || !retrieveSubs)
|
if (Credential == null || !retrieveSubs)
|
||||||
return;
|
return;
|
||||||
@@ -188,7 +175,6 @@ namespace FoxTube
|
|||||||
subRequest.Order = SubscriptionsResource.ListRequest.OrderEnum.Relevance;
|
subRequest.Order = SubscriptionsResource.ListRequest.OrderEnum.Relevance;
|
||||||
SubscriptionListResponse subResponse;
|
SubscriptionListResponse subResponse;
|
||||||
string nextToken = null;
|
string nextToken = null;
|
||||||
Subscriptions.Clear();
|
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
@@ -200,22 +186,17 @@ namespace FoxTube
|
|||||||
|
|
||||||
} while (!string.IsNullOrWhiteSpace(nextToken));
|
} while (!string.IsNullOrWhiteSpace(nextToken));
|
||||||
|
|
||||||
var request = Service.Channels.List("snippet,contentDetails");
|
ChannelsResource.ListRequest request = Service.Channels.List("snippet,contentDetails");
|
||||||
request.Mine = true;
|
request.Mine = true;
|
||||||
UserChannel = (await request.ExecuteAsync()).Items[0];
|
UserChannel = (await request.ExecuteAsync()).Items.FirstOrDefault();
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
//Saving user's subscriptions for background task
|
AuthorizationStateChanged?.Invoke(true);
|
||||||
SaveSubscriptions();
|
|
||||||
|
|
||||||
AuthorizationStateChanged?.Invoke(args: true);
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
AuthorizationStateChanged?.Invoke(args: new bool?[] { null });
|
AuthorizationStateChanged?.Invoke(null);
|
||||||
Methods.SendMail($@"Exception: {e.GetType()}
|
Methods.SendMail(e.ToString());
|
||||||
Message: {e.Message}
|
|
||||||
Stack trace: {e.StackTrace}");
|
|
||||||
Analytics.TrackEvent("Failed to retrieve user's info", new Dictionary<string, string>
|
Analytics.TrackEvent("Failed to retrieve user's info", new Dictionary<string, string>
|
||||||
{
|
{
|
||||||
{ "Exception", e.GetType().ToString() },
|
{ "Exception", e.GetType().ToString() },
|
||||||
@@ -225,43 +206,6 @@ Stack trace: {e.StackTrace}");
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Saves user's subscriptions keypairs (channel ID: avatar URL) into "background.json" file for concurrent background processing
|
|
||||||
/// </summary>
|
|
||||||
public static void SaveSubscriptions()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Dictionary<string, string> subs = new Dictionary<string, string>();
|
|
||||||
foreach (Subscription i in Subscriptions)
|
|
||||||
try
|
|
||||||
{
|
|
||||||
subs.Add(i.Snippet.ResourceId.ChannelId, i.Snippet.Thumbnails.Default__.Url);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Analytics.TrackEvent("Failed to save user's subscription", new Dictionary<string, string>
|
|
||||||
{
|
|
||||||
{ "Exception", e.GetType().ToString() },
|
|
||||||
{ "Message", e.Message },
|
|
||||||
{ "Channel ID", i.Snippet.ResourceId.ChannelId },
|
|
||||||
{ "StackTrace", e.StackTrace }
|
|
||||||
});
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
ApplicationData.Current.RoamingSettings.Values["subscriptions"] = JsonConvert.SerializeObject(subs);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Analytics.TrackEvent("Failed to write user's subscriptions", new Dictionary<string, string>
|
|
||||||
{
|
|
||||||
{ "Exception", e.GetType().ToString() },
|
|
||||||
{ "Message", e.Message },
|
|
||||||
{ "StackTrace", e.StackTrace }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Deauthenticates current user
|
/// Deauthenticates current user
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -273,12 +217,13 @@ Stack trace: {e.StackTrace}");
|
|||||||
Credential = null;
|
Credential = null;
|
||||||
UserChannel = null;
|
UserChannel = null;
|
||||||
UserInfo = null;
|
UserInfo = null;
|
||||||
History.Clear();
|
History = null;
|
||||||
WatchLater.Clear();
|
WatchLater = null;
|
||||||
Subscriptions.Clear();
|
Subscriptions.Clear();
|
||||||
ApplicationData.Current.RoamingSettings.Values["subscriptions"] = "";
|
|
||||||
|
|
||||||
AuthorizationStateChanged?.Invoke(args: false);
|
HttpClient.DefaultRequestHeaders.Authorization = null;
|
||||||
|
|
||||||
|
AuthorizationStateChanged?.Invoke(false);
|
||||||
SettingsStorage.HasAccount = false;
|
SettingsStorage.HasAccount = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -291,10 +236,7 @@ Stack trace: {e.StackTrace}");
|
|||||||
if (SettingsStorage.HasAccount)
|
if (SettingsStorage.HasAccount)
|
||||||
Authorize(retrieveSubs);
|
Authorize(retrieveSubs);
|
||||||
else
|
else
|
||||||
{
|
AuthorizationStateChanged.Invoke(false);
|
||||||
AuthorizationStateChanged.Invoke(args: false);
|
|
||||||
ApplicationData.Current.RoamingSettings.Values["subscriptions"] = "";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ namespace FoxTube
|
|||||||
|
|
||||||
private static string GetLanguage()
|
private static string GetLanguage()
|
||||||
{
|
{
|
||||||
if (App.AvailableLanguages.Contains(CultureInfo.InstalledUICulture.Name))
|
if (new string[] { "ru-RU", "en-US" }.Contains(CultureInfo.InstalledUICulture.Name))
|
||||||
return CultureInfo.InstalledUICulture.Name;
|
return CultureInfo.InstalledUICulture.Name;
|
||||||
else if ((new[] { "ua", "ru", "by", "kz", "kg", "md", "lv", "ee" }).Contains(CultureInfo.InstalledUICulture.TwoLetterISOLanguageName))
|
else if ((new[] { "ua", "ru", "by", "kz", "kg", "md", "lv", "ee" }).Contains(CultureInfo.InstalledUICulture.TwoLetterISOLanguageName))
|
||||||
return "ru-RU";
|
return "ru-RU";
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace FoxTube.Classes
|
||||||
|
{
|
||||||
|
public class StreamInfo
|
||||||
|
{
|
||||||
|
public class VideoInfo
|
||||||
|
{
|
||||||
|
public string IndexRange { get; set; }
|
||||||
|
public string InitRange => $"0-{int.Parse(IndexRange.Split('-')[0]) - 1}";
|
||||||
|
public string Itag { get; set; }
|
||||||
|
public string Fps { get; set; }
|
||||||
|
public string Url { get; set; }
|
||||||
|
public string Codecs { get; set; }
|
||||||
|
public string MimeType { get; set; }
|
||||||
|
public string Height { get; set; }
|
||||||
|
public string Width { get; set; }
|
||||||
|
public string Label { get; set; }
|
||||||
|
}
|
||||||
|
public class AudioInfo
|
||||||
|
{
|
||||||
|
public string IndexRange { get; set; }
|
||||||
|
public string InitRange => $"0-{int.Parse(IndexRange.Split('-')[0]) - 1}";
|
||||||
|
public string SampleRate { get; set; }
|
||||||
|
public string ChannelsCount { get; set; }
|
||||||
|
public string Codecs { get; set; }
|
||||||
|
public string MimeType { get; set; }
|
||||||
|
public string Url { get; set; }
|
||||||
|
public string Itag { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<VideoInfo> Video { get; } = new List<VideoInfo>();
|
||||||
|
public List<AudioInfo> Audio { get; } = new List<AudioInfo>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class StreamQuality
|
||||||
|
{
|
||||||
|
public Uri Url { get; set; }
|
||||||
|
public string Resolution { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,10 +6,9 @@
|
|||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
VerticalAlignment="Top"
|
VerticalAlignment="Stretch"
|
||||||
d:DesignHeight="290"
|
d:DesignHeight="290"
|
||||||
d:DesignWidth="384"
|
d:DesignWidth="384"
|
||||||
Visibility="Collapsed"
|
|
||||||
Opacity="0"
|
Opacity="0"
|
||||||
Name="card">
|
Name="card">
|
||||||
|
|
||||||
@@ -17,19 +16,9 @@
|
|||||||
<Storyboard x:Name="show">
|
<Storyboard x:Name="show">
|
||||||
<DoubleAnimation Storyboard.TargetName="card" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="{StaticResource CardOpacityDuration}"/>
|
<DoubleAnimation Storyboard.TargetName="card" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="{StaticResource CardOpacityDuration}"/>
|
||||||
</Storyboard>
|
</Storyboard>
|
||||||
<Storyboard x:Name="hide">
|
|
||||||
<DoubleAnimation Storyboard.TargetName="card" Storyboard.TargetProperty="Opacity" From="1" To="0" Duration="{StaticResource CardOpacityDuration}"/>
|
|
||||||
</Storyboard>
|
|
||||||
<Storyboard x:Name="showThumb">
|
|
||||||
<DoubleAnimation Storyboard.TargetName="image" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="{StaticResource CardOpacityDuration}"/>
|
|
||||||
</Storyboard>
|
|
||||||
<Storyboard x:Name="hideThumb">
|
|
||||||
<DoubleAnimation Storyboard.TargetName="image" Storyboard.TargetProperty="Opacity" From="1" To="0" Duration="{StaticResource CardOpacityDuration}"/>
|
|
||||||
</Storyboard>
|
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
|
|
||||||
<Button Padding="0" Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}">
|
<Grid Name="grid" Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}">
|
||||||
<Grid Name="grid">
|
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition/>
|
<RowDefinition/>
|
||||||
<RowDefinition Height="20"/>
|
<RowDefinition Height="20"/>
|
||||||
@@ -61,5 +50,4 @@
|
|||||||
|
|
||||||
<TextBlock Grid.Row="2" Name="title" Text="[Title]" TextWrapping="WrapWholeWords" Margin="5" MaxLines="2" TextTrimming="CharacterEllipsis"/>
|
<TextBlock Grid.Row="2" Name="title" Text="[Title]" TextWrapping="WrapWholeWords" Margin="5" MaxLines="2" TextTrimming="CharacterEllipsis"/>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Button>
|
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ namespace FoxTube.Controls.Adverts
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed partial class CardAdvert : UserControl
|
public sealed partial class CardAdvert : UserControl
|
||||||
{
|
{
|
||||||
NativeAdsManagerV2 manager = new NativeAdsManagerV2(SecretsVault.AppId, SecretsVault.AdUnitId);
|
readonly NativeAdsManagerV2 manager = new NativeAdsManagerV2(SecretsVault.AppId, SecretsVault.AdUnitId);
|
||||||
public NativeAdV2 advert;
|
NativeAdV2 advert;
|
||||||
public CardAdvert()
|
public CardAdvert()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
@@ -22,22 +22,21 @@ namespace FoxTube.Controls.Adverts
|
|||||||
manager.RequestAd();
|
manager.RequestAd();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ErrorOccurred(object sender, NativeAdErrorEventArgs e)
|
void ErrorOccurred(object sender, NativeAdErrorEventArgs e)
|
||||||
{
|
{
|
||||||
(Parent as AdaptiveGridView)?.Items.Remove(this);
|
(Parent as AdaptiveGridView)?.Items.Remove(this);
|
||||||
System.Diagnostics.Debug.WriteLine("Error has occured while loading ad");
|
System.Diagnostics.Debug.WriteLine("Error has occured while loading ad");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AdReady(object sender, NativeAdReadyEventArgs e)
|
void AdReady(object sender, NativeAdReadyEventArgs e)
|
||||||
{
|
{
|
||||||
advert = e.NativeAd;
|
advert = e.NativeAd;
|
||||||
Initialize();
|
Initialize();
|
||||||
e.NativeAd.RegisterAdContainer(grid);
|
e.NativeAd.RegisterAdContainer(grid);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Initialize()
|
void Initialize()
|
||||||
{
|
{
|
||||||
Visibility = Visibility.Visible;
|
|
||||||
title.Text = advert.Title;
|
title.Text = advert.Title;
|
||||||
image.Source = new BitmapImage(advert.MainImages.First().Url.ToUri());
|
image.Source = new BitmapImage(advert.MainImages.First().Url.ToUri());
|
||||||
|
|
||||||
@@ -57,13 +56,9 @@ namespace FoxTube.Controls.Adverts
|
|||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(advert.Rating))
|
if (!string.IsNullOrWhiteSpace(advert.Rating))
|
||||||
desc.Text += " " + advert.Rating;
|
desc.Text += " " + advert.Rating;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Image_ImageOpened(object sender, RoutedEventArgs e) =>
|
||||||
show.Begin();
|
show.Begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Image_ImageOpened(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
showThumb.Begin();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
<ListViewItem
|
||||||
|
x:Class="FoxTube.Controls.Adverts.ChatAdvert"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
|
||||||
|
<Grid x:Name="grid">
|
||||||
|
<Border BorderBrush="Red" BorderThickness="2" CornerRadius="5" HorizontalAlignment="Stretch" Margin="0,27,0,2">
|
||||||
|
<Border.Background>
|
||||||
|
<SolidColorBrush Color="Red" Opacity=".2"/>
|
||||||
|
</Border.Background>
|
||||||
|
|
||||||
|
<Grid Margin="0,5,5,5">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="auto"/>
|
||||||
|
<ColumnDefinition Width="auto"/>
|
||||||
|
<ColumnDefinition/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<StackPanel Orientation="Horizontal" VerticalAlignment="Top" Margin="5,0">
|
||||||
|
<PersonPicture Height="20" Name="icon"/>
|
||||||
|
<FontIcon Glyph="" Margin="2,0">
|
||||||
|
<ToolTipService.ToolTip>
|
||||||
|
<TextBlock x:Uid="/Chat/sponsor"/>
|
||||||
|
</ToolTipService.ToolTip>
|
||||||
|
</FontIcon>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<StackPanel Orientation="Horizontal" VerticalAlignment="Top" Margin="0,0,2,0" Grid.Column="1">
|
||||||
|
<HyperlinkButton Margin="0,-6,0,0" FontWeight="Bold">
|
||||||
|
<TextBlock TextTrimming="CharacterEllipsis" MaxWidth="150" Name="name"/>
|
||||||
|
</HyperlinkButton>
|
||||||
|
<TextBlock Text=":"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<StackPanel Padding="2,0,0,0" Grid.Column="2" VerticalAlignment="Top">
|
||||||
|
<TextBlock TextWrapping="WrapWholeWords" FontWeight="Bold" Name="title"/>
|
||||||
|
<TextBlock TextWrapping="WrapWholeWords" Name="description"/>
|
||||||
|
<Button x:Name="ctaBtn">
|
||||||
|
<TextBlock TextWrapping="WrapWholeWords" Name="cta"/>
|
||||||
|
</Button>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
</Grid>
|
||||||
|
</ListViewItem>
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
using Microsoft.Advertising.WinRT.UI;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices.WindowsRuntime;
|
||||||
|
using Windows.Foundation;
|
||||||
|
using Windows.Foundation.Collections;
|
||||||
|
using Windows.UI.Xaml;
|
||||||
|
using Windows.UI.Xaml.Controls;
|
||||||
|
using Windows.UI.Xaml.Controls.Primitives;
|
||||||
|
using Windows.UI.Xaml.Data;
|
||||||
|
using Windows.UI.Xaml.Input;
|
||||||
|
using Windows.UI.Xaml.Media;
|
||||||
|
using Windows.UI.Xaml.Navigation;
|
||||||
|
|
||||||
|
// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236
|
||||||
|
|
||||||
|
namespace FoxTube.Controls.Adverts
|
||||||
|
{
|
||||||
|
public sealed partial class ChatAdvert : ListViewItem
|
||||||
|
{
|
||||||
|
readonly NativeAdsManagerV2 manager = new NativeAdsManagerV2(SecretsVault.AppId, SecretsVault.AdUnitId);
|
||||||
|
NativeAdV2 advert;
|
||||||
|
|
||||||
|
public ChatAdvert()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
manager.AdReady += AdReady;
|
||||||
|
manager.RequestAd();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdReady(object sender, NativeAdReadyEventArgs e)
|
||||||
|
{
|
||||||
|
advert = e.NativeAd;
|
||||||
|
Initialize();
|
||||||
|
if (cta.Visibility == Visibility.Collapsed)
|
||||||
|
e.NativeAd.RegisterAdContainer(grid);
|
||||||
|
else
|
||||||
|
e.NativeAd.RegisterAdContainer(grid, new List<FrameworkElement> { cta });
|
||||||
|
}
|
||||||
|
|
||||||
|
void Initialize()
|
||||||
|
{
|
||||||
|
name.Text = Methods.GuardFromNull(advert.SponsoredBy);
|
||||||
|
ToolTipService.SetToolTip(name, name.Text);
|
||||||
|
|
||||||
|
icon.ProfilePicture = advert.AdIcon == null ? null : advert.AdIcon.Source;
|
||||||
|
title.Text = advert.Title;
|
||||||
|
|
||||||
|
description.Text = Methods.GuardFromNull(advert.Description);
|
||||||
|
|
||||||
|
cta.Text = Methods.GuardFromNull(advert.CallToActionText);
|
||||||
|
cta.Visibility = string.IsNullOrWhiteSpace(advert.CallToActionText) ? Visibility.Collapsed : Visibility.Visible;
|
||||||
|
|
||||||
|
Visibility = Visibility.Visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,23 +10,17 @@ namespace FoxTube.Controls.Adverts
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed partial class CommentAdvert : UserControl
|
public sealed partial class CommentAdvert : UserControl
|
||||||
{
|
{
|
||||||
NativeAdsManagerV2 manager = new NativeAdsManagerV2(SecretsVault.AppId, SecretsVault.AdUnitId);
|
readonly NativeAdsManagerV2 manager = new NativeAdsManagerV2(SecretsVault.AppId, SecretsVault.AdUnitId);
|
||||||
public NativeAdV2 advert;
|
NativeAdV2 advert;
|
||||||
public CommentAdvert()
|
public CommentAdvert()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
manager.AdReady += AdReady;
|
manager.AdReady += AdReady;
|
||||||
manager.ErrorOccurred += ErrorOccurred;
|
|
||||||
manager.RequestAd();
|
manager.RequestAd();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ErrorOccurred(object sender, NativeAdErrorEventArgs e)
|
void AdReady(object sender, NativeAdReadyEventArgs e)
|
||||||
{
|
|
||||||
System.Diagnostics.Debug.WriteLine("Error has occured while loading ad");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AdReady(object sender, NativeAdReadyEventArgs e)
|
|
||||||
{
|
{
|
||||||
advert = e.NativeAd;
|
advert = e.NativeAd;
|
||||||
Initialize();
|
Initialize();
|
||||||
@@ -36,7 +30,7 @@ namespace FoxTube.Controls.Adverts
|
|||||||
e.NativeAd.RegisterAdContainer(grid, new List<FrameworkElement> { cta });
|
e.NativeAd.RegisterAdContainer(grid, new List<FrameworkElement> { cta });
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Initialize()
|
void Initialize()
|
||||||
{
|
{
|
||||||
title.Text = advert.Title;
|
title.Text = advert.Title;
|
||||||
description.Text = Methods.GuardFromNull(advert.Description);
|
description.Text = Methods.GuardFromNull(advert.Description);
|
||||||
|
|||||||
@@ -8,10 +8,9 @@ namespace FoxTube.Controls.Adverts
|
|||||||
{
|
{
|
||||||
public sealed partial class PlayerAdvert : UserControl
|
public sealed partial class PlayerAdvert : UserControl
|
||||||
{
|
{
|
||||||
NativeAdsManagerV2 manager = new NativeAdsManagerV2(SecretsVault.AppId, SecretsVault.AdUnitId);
|
readonly NativeAdsManagerV2 manager = new NativeAdsManagerV2(SecretsVault.AppId, SecretsVault.AdUnitId);
|
||||||
NativeAdV2 advert;
|
NativeAdV2 advert;
|
||||||
|
readonly DispatcherTimer timer = new DispatcherTimer
|
||||||
DispatcherTimer timer = new DispatcherTimer()
|
|
||||||
{
|
{
|
||||||
Interval = TimeSpan.FromMilliseconds(10000)
|
Interval = TimeSpan.FromMilliseconds(10000)
|
||||||
};
|
};
|
||||||
@@ -20,7 +19,6 @@ namespace FoxTube.Controls.Adverts
|
|||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
manager.AdReady += AdReady;
|
manager.AdReady += AdReady;
|
||||||
manager.ErrorOccurred += ErrorOccurred;
|
|
||||||
|
|
||||||
timer.Tick += (s, e) =>
|
timer.Tick += (s, e) =>
|
||||||
{
|
{
|
||||||
@@ -29,12 +27,7 @@ namespace FoxTube.Controls.Adverts
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ErrorOccurred(object sender, NativeAdErrorEventArgs e)
|
void AdReady(object sender, NativeAdReadyEventArgs arg)
|
||||||
{
|
|
||||||
System.Diagnostics.Debug.WriteLine("Error has occured while loading ad");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AdReady(object sender, NativeAdReadyEventArgs arg)
|
|
||||||
{
|
{
|
||||||
advert = arg.NativeAd;
|
advert = arg.NativeAd;
|
||||||
|
|
||||||
@@ -68,12 +61,10 @@ namespace FoxTube.Controls.Adverts
|
|||||||
show.Begin();
|
show.Begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void PushAdvert()
|
public void PushAdvert() =>
|
||||||
{
|
|
||||||
manager.RequestAd();
|
manager.RequestAd();
|
||||||
}
|
|
||||||
|
|
||||||
private void Button_Click(object sender, RoutedEventArgs e)
|
void Button_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
timer.Stop();
|
timer.Stop();
|
||||||
hide.Begin();
|
hide.Begin();
|
||||||
|
|||||||
@@ -6,25 +6,21 @@
|
|||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
VerticalAlignment="Top"
|
VerticalAlignment="Stretch"
|
||||||
d:DesignHeight="290"
|
d:DesignHeight="290"
|
||||||
d:DesignWidth="384"
|
d:DesignWidth="384"
|
||||||
MaxWidth="700"
|
MaxWidth="700"
|
||||||
|
MaxHeight="600"
|
||||||
Opacity="0"
|
Opacity="0"
|
||||||
Name="card"
|
Name="card">
|
||||||
SizeChanged="Card_SizeChanged">
|
|
||||||
|
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
<Storyboard x:Name="show">
|
<Storyboard x:Name="show">
|
||||||
<DoubleAnimation Storyboard.TargetName="card" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="{StaticResource CardOpacityDuration}"/>
|
<DoubleAnimation Storyboard.TargetName="card" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="{StaticResource CardOpacityDuration}"/>
|
||||||
</Storyboard>
|
</Storyboard>
|
||||||
<Storyboard x:Name="showThumb">
|
|
||||||
<DoubleAnimation Storyboard.TargetName="cover" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="{StaticResource CardOpacityDuration}"/>
|
|
||||||
</Storyboard>
|
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
|
|
||||||
<Button Padding="0" Margin="1" Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}" Click="Button_Click">
|
<Grid Name="grid" Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}">
|
||||||
<Grid Name="grid">
|
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="auto"/>
|
<RowDefinition Height="auto"/>
|
||||||
<RowDefinition Height="50"/>
|
<RowDefinition Height="50"/>
|
||||||
@@ -33,7 +29,7 @@
|
|||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<Image Source="/Assets/ChannelCoverTemplate.png" Stretch="UniformToFill" Opacity=".0001"/>
|
<Image Source="/Assets/ChannelCoverTemplate.png" Stretch="UniformToFill" Opacity=".0001"/>
|
||||||
<Image Name="cover" Source="/Assets/ChannelCoverTemplate.png" Stretch="UniformToFill" ImageOpened="Cover_ImageOpened" Opacity="0"/>
|
<Image Name="cover" Source="/Assets/ChannelCoverTemplate.png" Stretch="UniformToFill" ImageOpened="Cover_ImageOpened"/>
|
||||||
|
|
||||||
<StackPanel Name="liveTag" Margin="5" Background="Red" BorderBrush="White" BorderThickness="1" VerticalAlignment="Bottom" HorizontalAlignment="Right" Padding="5,2,5,3" Orientation="Horizontal" Visibility="Collapsed">
|
<StackPanel Name="liveTag" Margin="5" Background="Red" BorderBrush="White" BorderThickness="1" VerticalAlignment="Bottom" HorizontalAlignment="Right" Padding="5,2,5,3" Orientation="Horizontal" Visibility="Collapsed">
|
||||||
<TextBlock Text=" " VerticalAlignment="Center" Foreground="White" FontSize="12" FontFamily="Segoe MDL2 Assets" FontWeight="Black"/>
|
<TextBlock Text=" " VerticalAlignment="Center" Foreground="White" FontSize="12" FontFamily="Segoe MDL2 Assets" FontWeight="Black"/>
|
||||||
@@ -68,7 +64,7 @@
|
|||||||
<ToggleButton Name="notify" Height="50" Width="50" Visibility="Collapsed" FontFamily="Segoe MDL2 Assets" FontSize="18" FontWeight="SemiBold" Content="" Foreground="White" Background="Red" HorizontalAlignment="Right"/>
|
<ToggleButton Name="notify" Height="50" Width="50" Visibility="Collapsed" FontFamily="Segoe MDL2 Assets" FontSize="18" FontWeight="SemiBold" Content="" Foreground="White" Background="Red" HorizontalAlignment="Right"/>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Button>
|
|
||||||
<UserControl.ContextFlyout>
|
<UserControl.ContextFlyout>
|
||||||
<MenuFlyout>
|
<MenuFlyout>
|
||||||
<MenuFlyoutItem x:Uid="/Cards/channel" Icon="Contact" Text="View channel" Click="Button_Click"/>
|
<MenuFlyoutItem x:Uid="/Cards/channel" Icon="Contact" Text="View channel" Click="Button_Click"/>
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
using Google.Apis.YouTube.v3;
|
using FoxTube.Classes;
|
||||||
|
using Google.Apis.YouTube.v3;
|
||||||
using Google.Apis.YouTube.v3.Data;
|
using Google.Apis.YouTube.v3.Data;
|
||||||
using Microsoft.Toolkit.Uwp.UI.Controls;
|
using Microsoft.Toolkit.Uwp.UI.Controls;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Windows.ApplicationModel.DataTransfer;
|
using Windows.ApplicationModel.DataTransfer;
|
||||||
using Windows.ApplicationModel.Resources;
|
using Windows.ApplicationModel.Resources;
|
||||||
using Windows.System;
|
using Windows.System;
|
||||||
@@ -16,32 +18,33 @@ namespace FoxTube.Controls
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Channel item card
|
/// Channel item card
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed partial class ChannelCard : UserControl
|
public sealed partial class ChannelCard : UserControl, ICard
|
||||||
{
|
{
|
||||||
ResourceLoader resources = ResourceLoader.GetForCurrentView("Cards");
|
readonly ResourceLoader resources = ResourceLoader.GetForCurrentView("Cards");
|
||||||
|
|
||||||
string channelId;
|
readonly string channelId;
|
||||||
|
readonly string live;
|
||||||
Channel item;
|
Channel item;
|
||||||
|
|
||||||
public ChannelCard(string id, string live = null)
|
public ChannelCard(string id, string live = null)
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
Initialize(id, live);
|
channelId = id;
|
||||||
|
this.live = live;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void Initialize(string id, string live)
|
public async Task Initialize()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (id == SecretsVault.AccountId)
|
if (channelId == SecretsVault.AccountId)
|
||||||
grid.RowDefinitions[3].Height = new GridLength(0);
|
grid.RowDefinitions[3].Height = new GridLength(0);
|
||||||
|
|
||||||
ChannelsResource.ListRequest request = SecretsVault.Service.Channels.List("snippet,statistics,brandingSettings");
|
ChannelsResource.ListRequest request = SecretsVault.Service.Channels.List("snippet,statistics,brandingSettings");
|
||||||
request.Id = id;
|
request.Id = channelId;
|
||||||
ChannelListResponse response = await request.ExecuteAsync();
|
ChannelListResponse response = await request.ExecuteAsync();
|
||||||
|
|
||||||
item = response.Items[0];
|
item = response.Items[0];
|
||||||
channelId = id;
|
|
||||||
|
|
||||||
title.Text = item.Snippet.Title;
|
title.Text = item.Snippet.Title;
|
||||||
description.Text = item.Snippet.Description;
|
description.Text = item.Snippet.Description;
|
||||||
@@ -54,7 +57,7 @@ namespace FoxTube.Controls
|
|||||||
|
|
||||||
if (SecretsVault.IsAuthorized)
|
if (SecretsVault.IsAuthorized)
|
||||||
{
|
{
|
||||||
if (SecretsVault.Subscriptions.Exists(i => i.Snippet.ResourceId.ChannelId == id))
|
if (SecretsVault.Subscriptions.Exists(i => i.Snippet.ResourceId.ChannelId == channelId))
|
||||||
{
|
{
|
||||||
subscribe.Background = new SolidColorBrush(Colors.Transparent);
|
subscribe.Background = new SolidColorBrush(Colors.Transparent);
|
||||||
subscribe.Foreground = new SolidColorBrush(Colors.Gray);
|
subscribe.Foreground = new SolidColorBrush(Colors.Gray);
|
||||||
@@ -63,10 +66,9 @@ namespace FoxTube.Controls
|
|||||||
subscriptionPane.Visibility = Visibility.Visible;
|
subscriptionPane.Visibility = Visibility.Visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
try { avatar.ProfilePicture = new BitmapImage(new Uri(item.Snippet.Thumbnails.Medium.Url)) { DecodePixelWidth = 74, DecodePixelHeight = 74 }; }
|
|
||||||
catch { }
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
avatar.ProfilePicture = new BitmapImage(new Uri(item.Snippet.Thumbnails.Medium.Url)) { DecodePixelWidth = 74, DecodePixelHeight = 74 };
|
||||||
if (!item.BrandingSettings.Image.BannerImageUrl.Contains("default"))
|
if (!item.BrandingSettings.Image.BannerImageUrl.Contains("default"))
|
||||||
cover.Source = new BitmapImage(item.BrandingSettings.Image.BannerMobileImageUrl.ToUri());
|
cover.Source = new BitmapImage(item.BrandingSettings.Image.BannerMobileImageUrl.ToUri());
|
||||||
}
|
}
|
||||||
@@ -80,25 +82,22 @@ namespace FoxTube.Controls
|
|||||||
{
|
{
|
||||||
{ "Exception", e.GetType().ToString() },
|
{ "Exception", e.GetType().ToString() },
|
||||||
{ "Message", e.Message },
|
{ "Message", e.Message },
|
||||||
{ "Video ID", id },
|
{ "Video ID", channelId },
|
||||||
{ "StackTrace", e.StackTrace }
|
{ "StackTrace", e.StackTrace }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
show.Begin();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Button_Click(object sender, RoutedEventArgs e)
|
public void ItemClicked() =>
|
||||||
{
|
Navigation.GoToChannel(channelId);
|
||||||
Methods.MainPage.GoToChannel(channelId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Hyperlink_Click(Windows.UI.Xaml.Documents.Hyperlink sender, Windows.UI.Xaml.Documents.HyperlinkClickEventArgs args)
|
void Button_Click(object sender, RoutedEventArgs e) =>
|
||||||
{
|
ItemClicked();
|
||||||
|
|
||||||
|
void Hyperlink_Click(Windows.UI.Xaml.Documents.Hyperlink sender, Windows.UI.Xaml.Documents.HyperlinkClickEventArgs args) =>
|
||||||
SecretsVault.Authorize();
|
SecretsVault.Authorize();
|
||||||
}
|
|
||||||
|
|
||||||
private async void subscribe_Click(object sender, RoutedEventArgs e)
|
async void subscribe_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
if (await SecretsVault.ChangeSubscriptionState(channelId))
|
if (await SecretsVault.ChangeSubscriptionState(channelId))
|
||||||
{
|
{
|
||||||
@@ -114,26 +113,17 @@ namespace FoxTube.Controls
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GetLink_Click(object sender, RoutedEventArgs e)
|
void GetLink_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
DataPackage data = new DataPackage();
|
DataPackage data = new DataPackage();
|
||||||
data.SetText($"https://www.youtube.com/channel/{item.Id}");
|
data.SetText($"https://www.youtube.com/channel/{item.Id}");
|
||||||
Clipboard.SetContent(data);
|
Clipboard.SetContent(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void InBrowser_Click(object sender, RoutedEventArgs e)
|
async void InBrowser_Click(object sender, RoutedEventArgs e) =>
|
||||||
{
|
|
||||||
await Launcher.LaunchUriAsync($"https://www.youtube.com/channel/{item.Id}".ToUri());
|
await Launcher.LaunchUriAsync($"https://www.youtube.com/channel/{item.Id}".ToUri());
|
||||||
}
|
|
||||||
|
|
||||||
private void Cover_ImageOpened(object sender, RoutedEventArgs e)
|
void Cover_ImageOpened(object sender, RoutedEventArgs e) =>
|
||||||
{
|
show.Begin();
|
||||||
showThumb.Begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Card_SizeChanged(object sender, SizeChangedEventArgs e)
|
|
||||||
{
|
|
||||||
Height = e.NewSize.Width * 0.75;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using Windows.UI.Xaml;
|
using Windows.UI.Xaml;
|
||||||
using Windows.UI.Xaml.Controls;
|
using Windows.UI.Xaml.Controls;
|
||||||
using Windows.UI.Xaml.Input;
|
using Windows.UI.Xaml.Input;
|
||||||
@@ -10,6 +9,7 @@ using Windows.UI.Xaml.Media.Imaging;
|
|||||||
using Windows.UI.Popups;
|
using Windows.UI.Popups;
|
||||||
using Windows.ApplicationModel.Resources;
|
using Windows.ApplicationModel.Resources;
|
||||||
using Microsoft.AppCenter.Analytics;
|
using Microsoft.AppCenter.Analytics;
|
||||||
|
using FoxTube.Classes;
|
||||||
|
|
||||||
namespace FoxTube.Controls
|
namespace FoxTube.Controls
|
||||||
{
|
{
|
||||||
@@ -135,12 +135,10 @@ namespace FoxTube.Controls
|
|||||||
catch { }
|
catch { }
|
||||||
}
|
}
|
||||||
|
|
||||||
private void replyBtn_Click(object sender, RoutedEventArgs e)
|
void replyBtn_Click(object sender, RoutedEventArgs e) =>
|
||||||
{
|
replyEditor.Visibility = replyEditor.Visibility == Visibility.Visible? Visibility.Collapsed : Visibility.Visible;
|
||||||
replyEditor.Visibility = replyEditor.Visibility == Visibility.Visible ? Visibility.Collapsed : Visibility.Visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void showReplies_Click(object sender, RoutedEventArgs e)
|
async void showReplies_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
replies.Visibility = replies.Visibility == Visibility.Visible ? Visibility.Collapsed : Visibility.Visible;
|
replies.Visibility = replies.Visibility == Visibility.Visible ? Visibility.Collapsed : Visibility.Visible;
|
||||||
|
|
||||||
@@ -169,15 +167,11 @@ namespace FoxTube.Controls
|
|||||||
processing.Visibility = Visibility.Collapsed;
|
processing.Visibility = Visibility.Collapsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void avatar_Tapped(object sender, TappedRoutedEventArgs e)
|
void avatar_Tapped(object sender, TappedRoutedEventArgs e) =>
|
||||||
{
|
Navigation.GoToChannel(item.Snippet.AuthorChannelId.ToString().Split('"')[3]);
|
||||||
Methods.MainPage.GoToChannel(item.Snippet.AuthorChannelId.ToString().Split('"')[3]);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void reply_TextChanged(object sender, TextChangedEventArgs e)
|
private void reply_TextChanged(object sender, TextChangedEventArgs e) =>
|
||||||
{
|
|
||||||
send.IsEnabled = reply.Text.Length == 0 ? false : true;
|
send.IsEnabled = reply.Text.Length == 0 ? false : true;
|
||||||
}
|
|
||||||
|
|
||||||
private async void send_Click(object sender, RoutedEventArgs args)
|
private async void send_Click(object sender, RoutedEventArgs args)
|
||||||
{
|
{
|
||||||
@@ -283,10 +277,8 @@ namespace FoxTube.Controls
|
|||||||
processing.Visibility = Visibility.Collapsed;
|
processing.Visibility = Visibility.Collapsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void editorText_TextChanged(object sender, TextChangedEventArgs e)
|
private void editorText_TextChanged(object sender, TextChangedEventArgs e) =>
|
||||||
{
|
|
||||||
editorSend.IsEnabled = editorText.Text.Length == 0 ? false : true;
|
editorSend.IsEnabled = editorText.Text.Length == 0 ? false : true;
|
||||||
}
|
|
||||||
|
|
||||||
private void editBtn_Click(object sender, RoutedEventArgs e)
|
private void editBtn_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
<Grid
|
||||||
|
x:Class="FoxTube.Controls.Common.AccountManager"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
|
||||||
|
|
||||||
|
<Button Background="Transparent" Visibility="Collapsed" Name="manager" Height="41" Width="60" FontSize="15" Padding="0">
|
||||||
|
<Button.Flyout>
|
||||||
|
<Flyout>
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="auto"/>
|
||||||
|
<ColumnDefinition/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<PersonPicture Width="65" Name="avatar" VerticalAlignment="Top"/>
|
||||||
|
<StackPanel Grid.Column="1" Margin="5">
|
||||||
|
<TextBlock Name="name"/>
|
||||||
|
<TextBlock Style="{StaticResource CaptionTextBlockStyle}" Name="email"/>
|
||||||
|
<HyperlinkButton x:Uid="/Main/signOut" Content="Log out" Click="Logout_Click"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</Flyout>
|
||||||
|
</Button.Flyout>
|
||||||
|
<Ellipse Width="25" Height="25" Name="icon">
|
||||||
|
<Ellipse.Fill>
|
||||||
|
<ImageBrush ImageSource="/Assets/Icons/profile.png"/>
|
||||||
|
</Ellipse.Fill>
|
||||||
|
</Ellipse>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button x:Uid="/Main/signIn" Name="account" Click="SignIn_Click" Visibility="Collapsed" FontFamily="Segoe MDL2 Assets" Content="" Background="Transparent" Height="41" Width="60" FontSize="15"/>
|
||||||
|
</Grid>
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
using Microsoft.AppCenter.Analytics;
|
||||||
|
using System;
|
||||||
|
using Windows.UI.Xaml;
|
||||||
|
using Windows.UI.Xaml.Controls;
|
||||||
|
using Windows.UI.Xaml.Media;
|
||||||
|
using Windows.UI.Xaml.Media.Imaging;
|
||||||
|
|
||||||
|
namespace FoxTube.Controls.Common
|
||||||
|
{
|
||||||
|
public sealed partial class AccountManager : Grid
|
||||||
|
{
|
||||||
|
public AccountManager()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SignIn_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
SecretsVault.Authorize();
|
||||||
|
Analytics.TrackEvent("Initialized authorization sequence");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logout_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
manager.Flyout.Hide();
|
||||||
|
SecretsVault.Deauthenticate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void Logged() => await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
|
||||||
|
{
|
||||||
|
account.Visibility = Visibility.Collapsed;
|
||||||
|
|
||||||
|
ToolTipService.SetToolTip(avatar, $"{SecretsVault.UserInfo.Name} ({SecretsVault.UserInfo.Email})");
|
||||||
|
name.Text = SecretsVault.UserInfo.Name;
|
||||||
|
email.Text = SecretsVault.UserInfo.Email;
|
||||||
|
avatar.ProfilePicture = new BitmapImage(SecretsVault.UserInfo.Picture.ToUri()) { DecodePixelHeight = 65, DecodePixelWidth = 65 };
|
||||||
|
(icon.Fill as ImageBrush).ImageSource = new BitmapImage(SecretsVault.UserInfo.Picture.ToUri()) { DecodePixelHeight = 25, DecodePixelWidth = 25 };
|
||||||
|
|
||||||
|
manager.Visibility = Visibility.Visible;
|
||||||
|
});
|
||||||
|
|
||||||
|
public void Quit()
|
||||||
|
{
|
||||||
|
manager.Visibility = Visibility.Collapsed;
|
||||||
|
account.Visibility = Visibility.Visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
using Google.Apis.YouTube.v3;
|
||||||
|
using Google.Apis.YouTube.v3.Data;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Windows.ApplicationModel.Resources;
|
||||||
|
using Windows.UI.Xaml;
|
||||||
|
using Windows.UI.Xaml.Controls;
|
||||||
|
|
||||||
|
namespace FoxTube.Controls.Common
|
||||||
|
{
|
||||||
|
class AddToPlaylist
|
||||||
|
{
|
||||||
|
ResourceLoader resources = ResourceLoader.GetForCurrentView("VideoPage");
|
||||||
|
IList<MenuFlyoutItemBase> Items { get; }
|
||||||
|
string videoId;
|
||||||
|
|
||||||
|
public AddToPlaylist(IList<MenuFlyoutItemBase> items) =>
|
||||||
|
Items = items;
|
||||||
|
|
||||||
|
public async void Initialize(string id)
|
||||||
|
{
|
||||||
|
Items.Clear();
|
||||||
|
|
||||||
|
LoadDefaultItems();
|
||||||
|
|
||||||
|
videoId = id;
|
||||||
|
if (SecretsVault.WatchLater.Videos.Any(i => i.Id == id))
|
||||||
|
(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 = 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 SymbolIcon(Symbol.List)
|
||||||
|
};
|
||||||
|
menuItem.Click += Item_Click;
|
||||||
|
Items.Add(menuItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadDefaultItems()
|
||||||
|
{
|
||||||
|
MenuFlyoutItem createPlaylist = new MenuFlyoutItem
|
||||||
|
{
|
||||||
|
Text = resources.GetString("/VideoPage/newPlaylist/Text"),
|
||||||
|
Icon = new SymbolIcon(Symbol.Add)
|
||||||
|
};
|
||||||
|
createPlaylist.Click += NewPlaylist_Click;
|
||||||
|
Items.Add(createPlaylist);
|
||||||
|
ToggleMenuFlyoutItem watchLater = new ToggleMenuFlyoutItem
|
||||||
|
{
|
||||||
|
Text = resources.GetString("/VideoPage/wl"),
|
||||||
|
Icon = new SymbolIcon(Symbol.Clock)
|
||||||
|
};
|
||||||
|
watchLater.Click += Wl_Click;
|
||||||
|
Items.Add(watchLater);
|
||||||
|
Items.Add(new MenuFlyoutSeparator());
|
||||||
|
}
|
||||||
|
|
||||||
|
async void NewPlaylist_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
ToggleMenuFlyoutItem menuItem = await new CreateAndAddPlaylist().GetItem();
|
||||||
|
|
||||||
|
if (menuItem == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
menuItem.Click += Item_Click;
|
||||||
|
Items.Add(menuItem);
|
||||||
|
|
||||||
|
Item_Click(menuItem, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
async void Wl_Click(object sender, RoutedEventArgs e) =>
|
||||||
|
(sender as ToggleMenuFlyoutItem).IsChecked = await Methods.AddItemToWL(videoId);
|
||||||
|
|
||||||
|
async void Item_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(((ToggleMenuFlyoutItem)sender).IsChecked)
|
||||||
|
{
|
||||||
|
PlaylistItem playlist = new PlaylistItem
|
||||||
|
{
|
||||||
|
Snippet = new PlaylistItemSnippet
|
||||||
|
{
|
||||||
|
PlaylistId = (((ToggleMenuFlyoutItem)sender).Tag as Playlist).Id,
|
||||||
|
ResourceId = new ResourceId
|
||||||
|
{
|
||||||
|
VideoId = videoId,
|
||||||
|
Kind = "youtube#video"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
PlaylistItemsResource.InsertRequest request = SecretsVault.Service.PlaylistItems.Insert(playlist, "snippet");
|
||||||
|
|
||||||
|
await request.ExecuteAsync();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PlaylistItemsResource.ListRequest itemRequest = SecretsVault.Service.PlaylistItems.List("snippet");
|
||||||
|
itemRequest.VideoId = videoId;
|
||||||
|
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 = !((ToggleMenuFlyoutItem)sender).IsChecked;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<ContentDialog
|
||||||
|
x:Class="FoxTube.Controls.CreateAndAddPlaylist"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
x:Uid="/VideoPage/dialog"
|
||||||
|
PrimaryButtonText="Create and add" Title="New playlist" CloseButtonText="Cancel"
|
||||||
|
DefaultButton="Primary"
|
||||||
|
PrimaryButtonClick="ContentDialog_PrimaryButtonClick"
|
||||||
|
Name="playlistDialog">
|
||||||
|
|
||||||
|
<StackPanel>
|
||||||
|
<TextBox x:Uid="/VideoPage/newPlaylistName" PlaceholderText="Enter playlist name" Name="newListName"/>
|
||||||
|
<ComboBox x:Uid="/VideoPage/privacy" Header="Availablity" SelectedIndex="0" HorizontalAlignment="Stretch" Name="newListDisc">
|
||||||
|
<ComboBoxItem x:Uid="/VideoPage/public" Content="Public"/>
|
||||||
|
<ComboBoxItem x:Uid="/VideoPage/private" Content="Private"/>
|
||||||
|
<ComboBoxItem x:Uid="/VideoPage/direct" Content="Direct link"/>
|
||||||
|
</ComboBox>
|
||||||
|
</StackPanel>
|
||||||
|
</ContentDialog>
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
using Google.Apis.YouTube.v3.Data;
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Windows.UI.Xaml.Controls;
|
||||||
|
|
||||||
|
namespace FoxTube.Controls
|
||||||
|
{
|
||||||
|
public sealed partial class CreateAndAddPlaylist : ContentDialog
|
||||||
|
{
|
||||||
|
ToggleMenuFlyoutItem menuItem;
|
||||||
|
public CreateAndAddPlaylist()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ToggleMenuFlyoutItem> GetItem()
|
||||||
|
{
|
||||||
|
if (await ShowAsync() != ContentDialogResult.Primary)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
while (menuItem == null)
|
||||||
|
await Task.Delay(100);
|
||||||
|
|
||||||
|
return menuItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void ContentDialog_PrimaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args)
|
||||||
|
{
|
||||||
|
string privacy = "private";
|
||||||
|
switch (newListDisc.SelectedIndex)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
privacy = "public";
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
privacy = "private";
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
privacy = "unlisted";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Playlist newItem = new Playlist
|
||||||
|
{
|
||||||
|
Snippet = new PlaylistSnippet
|
||||||
|
{
|
||||||
|
Title = newListName.Text
|
||||||
|
},
|
||||||
|
Status = new PlaylistStatus
|
||||||
|
{
|
||||||
|
PrivacyStatus = privacy,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Playlist i;
|
||||||
|
|
||||||
|
try { i = await SecretsVault.Service.Playlists.Insert(newItem, "snippet,status").ExecuteAsync(); }
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
menuItem = new ToggleMenuFlyoutItem
|
||||||
|
{
|
||||||
|
Text = i.Snippet.Title,
|
||||||
|
IsChecked = true,
|
||||||
|
Tag = i,
|
||||||
|
Icon = new FontIcon
|
||||||
|
{
|
||||||
|
Glyph = "\xE728"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using Windows.ApplicationModel.Resources;
|
||||||
|
using Windows.UI.Xaml;
|
||||||
|
using Windows.UI.Xaml.Controls;
|
||||||
|
using YoutubeExplode;
|
||||||
|
using YoutubeExplode.Models;
|
||||||
|
using YoutubeExplode.Models.MediaStreams;
|
||||||
|
|
||||||
|
namespace FoxTube.Controls.Common
|
||||||
|
{
|
||||||
|
public class DownloadSelector
|
||||||
|
{
|
||||||
|
ResourceLoader resources = ResourceLoader.GetForCurrentView("VideoPage");
|
||||||
|
IList<MenuFlyoutItemBase> Items { get; }
|
||||||
|
|
||||||
|
public DownloadSelector(IList<MenuFlyoutItemBase> items) =>
|
||||||
|
Items = items;
|
||||||
|
|
||||||
|
public async void Initialize(Video item)
|
||||||
|
{
|
||||||
|
Items.Clear();
|
||||||
|
|
||||||
|
MediaStreamInfoSet infoSet = await new YoutubeClient(SecretsVault.HttpClient).GetVideoMediaStreamInfosAsync(item.Id);
|
||||||
|
foreach (MuxedStreamInfo i in infoSet.Muxed)
|
||||||
|
{
|
||||||
|
MenuFlyoutItem menuItem = new MenuFlyoutItem()
|
||||||
|
{
|
||||||
|
Text = i.VideoQualityLabel,
|
||||||
|
Tag = (i, item, i.VideoQualityLabel)
|
||||||
|
};
|
||||||
|
menuItem.Click += downloadItemSelected;
|
||||||
|
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;
|
||||||
|
Items.Add(audioItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
void downloadItemSelected(object sender, RoutedEventArgs e) =>
|
||||||
|
DownloadAgent.Add(((MuxedStreamInfo, Video, string))(sender as MenuFlyoutItemBase).Tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
using Windows.UI.Xaml;
|
using FoxTube.Classes;
|
||||||
|
using System;
|
||||||
|
using Windows.UI.Xaml;
|
||||||
using Windows.UI.Xaml.Controls;
|
using Windows.UI.Xaml.Controls;
|
||||||
using Windows.UI.Xaml.Navigation;
|
using Windows.UI.Xaml.Navigation;
|
||||||
|
|
||||||
@@ -10,26 +12,27 @@ namespace FoxTube.Controls
|
|||||||
public LoadingPage LoadingPage => loading;
|
public LoadingPage LoadingPage => loading;
|
||||||
public event NavigatedEventHandler Navigated;
|
public event NavigatedEventHandler Navigated;
|
||||||
|
|
||||||
|
public new object Content => content.Content;
|
||||||
|
|
||||||
public ContentFrame()
|
public ContentFrame()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
content.Navigated += (s, e) => Navigated?.Invoke(s, e);
|
content.Navigated += (s, e) => Navigated?.Invoke(s, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Content_Navigating(object sender, NavigatingCancelEventArgs e)
|
public void Navigate(Type sourcePageType, object parameter) =>
|
||||||
{
|
content.Navigate(sourcePageType, parameter);
|
||||||
loading.Refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Loading_RefreshPage(object sender, RoutedEventArgs e)
|
void Content_Navigating(object sender, NavigatingCancelEventArgs e) =>
|
||||||
|
loading.Refresh();
|
||||||
|
|
||||||
|
void Loading_RefreshPage(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
content.Navigate(content.CurrentSourcePageType, (content.Content as INavigationPage).Parameter);
|
content.Navigate(content.CurrentSourcePageType, (content.Content as INavigationPage).Parameter);
|
||||||
content.BackStack.RemoveAt(content.BackStack.Count - 1);
|
content.BackStack.RemoveAt(content.BackStack.Count - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Refresh()
|
public void Refresh() =>
|
||||||
{
|
|
||||||
Loading_RefreshPage(this, null);
|
Loading_RefreshPage(this, null);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
d:DesignHeight="100"
|
d:DesignHeight="100"
|
||||||
d:DesignWidth="1500">
|
d:DesignWidth="1500">
|
||||||
|
|
||||||
<!--<Button HorizontalAlignment="Stretch" Background="WhiteSmoke" Height="100" Padding="0" HorizontalContentAlignment="Stretch"/>-->
|
|
||||||
<Grid Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}" Height="100" HorizontalAlignment="Stretch" Margin="5">
|
<Grid Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}" Height="100" HorizontalAlignment="Stretch" Margin="5">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="auto"/>
|
<ColumnDefinition Width="auto"/>
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ using Windows.System;
|
|||||||
using YoutubeExplode.Models.MediaStreams;
|
using YoutubeExplode.Models.MediaStreams;
|
||||||
using YoutubeExplode;
|
using YoutubeExplode;
|
||||||
using Windows.Storage;
|
using Windows.Storage;
|
||||||
using Google.Apis.YouTube.v3.Data;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using Windows.UI.Popups;
|
using Windows.UI.Popups;
|
||||||
using Windows.UI.Notifications;
|
using Windows.UI.Notifications;
|
||||||
@@ -17,6 +16,8 @@ using Windows.ApplicationModel.Resources;
|
|||||||
using Microsoft.AppCenter.Analytics;
|
using Microsoft.AppCenter.Analytics;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using YoutubeExplode.Models;
|
||||||
|
using FoxTube.Classes;
|
||||||
|
|
||||||
namespace FoxTube.Controls
|
namespace FoxTube.Controls
|
||||||
{
|
{
|
||||||
@@ -52,14 +53,14 @@ namespace FoxTube.Controls
|
|||||||
|
|
||||||
Container = new DownloadItemContainer()
|
Container = new DownloadItemContainer()
|
||||||
{
|
{
|
||||||
Channel = meta.Snippet.ChannelTitle,
|
Channel = meta.Author,
|
||||||
Duration = Methods.GetDuration(meta.ContentDetails.Duration),
|
Duration = meta.Duration,
|
||||||
Extension = info.Container.GetFileExtension(),
|
Extension = info.Container.GetFileExtension(),
|
||||||
Id = meta.Id,
|
Id = meta.Id,
|
||||||
IsDownloaded = false,
|
IsDownloaded = false,
|
||||||
Quality = q,
|
Quality = q,
|
||||||
Thumbnail = meta.Snippet.Thumbnails.Medium.Url.ToUri(),
|
Thumbnail = meta.Thumbnails.MediumResUrl.ToUri(),
|
||||||
Title = meta.Snippet.Title
|
Title = meta.Title
|
||||||
};
|
};
|
||||||
|
|
||||||
Download(info);
|
Download(info);
|
||||||
@@ -102,16 +103,16 @@ namespace FoxTube.Controls
|
|||||||
timer.Tick += (s, e) => UpdateInfo();
|
timer.Tick += (s, e) => UpdateInfo();
|
||||||
|
|
||||||
#region Polling notification
|
#region Polling notification
|
||||||
ToastContent toastContent = new ToastContent()
|
ToastContent toastContent = new ToastContent
|
||||||
{
|
{
|
||||||
Visual = new ToastVisual()
|
Visual = new ToastVisual
|
||||||
{
|
{
|
||||||
BindingGeneric = new ToastBindingGeneric()
|
BindingGeneric = new ToastBindingGeneric
|
||||||
{
|
{
|
||||||
Children =
|
Children =
|
||||||
{
|
{
|
||||||
new AdaptiveText() { Text = resources.GetString("/Downloads/toastStartHeader") },
|
new AdaptiveText { Text = resources.GetString("/Downloads/toastStartHeader") },
|
||||||
new AdaptiveProgressBar()
|
new AdaptiveProgressBar
|
||||||
{
|
{
|
||||||
Title = Container.Title,
|
Title = Container.Title,
|
||||||
Status = resources.GetString("/Downloads/downloading/Text"),
|
Status = resources.GetString("/Downloads/downloading/Text"),
|
||||||
@@ -121,7 +122,7 @@ namespace FoxTube.Controls
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
Actions = new ToastActionsCustom()
|
Actions = new ToastActionsCustom
|
||||||
{
|
{
|
||||||
Buttons =
|
Buttons =
|
||||||
{
|
{
|
||||||
@@ -197,7 +198,7 @@ namespace FoxTube.Controls
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateInfo()
|
void UpdateInfo()
|
||||||
{
|
{
|
||||||
progressBar.Value = percentage;
|
progressBar.Value = percentage;
|
||||||
progressText.Text = Math.Round(percentage * 100, 1) + "%";
|
progressText.Text = Math.Round(percentage * 100, 1) + "%";
|
||||||
@@ -206,7 +207,7 @@ namespace FoxTube.Controls
|
|||||||
ToastNotificationManager.CreateToastNotifier().Update(data, $"download|{Container.Id}");
|
ToastNotificationManager.CreateToastNotifier().Update(data, $"download|{Container.Id}");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DownloadCompleted()
|
void DownloadCompleted()
|
||||||
{
|
{
|
||||||
Windows.Data.Xml.Dom.XmlDocument template = new Windows.Data.Xml.Dom.XmlDocument();
|
Windows.Data.Xml.Dom.XmlDocument template = new Windows.Data.Xml.Dom.XmlDocument();
|
||||||
template.LoadXml($@"<toast activationType='foreground' launch='download'>
|
template.LoadXml($@"<toast activationType='foreground' launch='download'>
|
||||||
@@ -229,15 +230,11 @@ namespace FoxTube.Controls
|
|||||||
progressPanel.Visibility = Visibility.Collapsed;
|
progressPanel.Visibility = Visibility.Collapsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void open_Click(object sender, RoutedEventArgs e)
|
async void open_Click(object sender, RoutedEventArgs e) =>
|
||||||
{
|
|
||||||
await Launcher.LaunchFileAsync(File);
|
await Launcher.LaunchFileAsync(File);
|
||||||
}
|
|
||||||
|
|
||||||
private void gotoOriginal_Click(object sender, RoutedEventArgs e)
|
void gotoOriginal_Click(object sender, RoutedEventArgs e) =>
|
||||||
{
|
Navigation.GoToVideo(Container.Id);
|
||||||
Methods.MainPage.GoToVideo(Container.Id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async void Cancel(bool prompt = true)
|
public async void Cancel(bool prompt = true)
|
||||||
{
|
{
|
||||||
@@ -283,9 +280,7 @@ namespace FoxTube.Controls
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Cancel_Click(object sender, RoutedEventArgs e)
|
private void Cancel_Click(object sender, RoutedEventArgs e) =>
|
||||||
{
|
|
||||||
Cancel();
|
Cancel();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using FoxTube.Controls;
|
using FoxTube.Classes;
|
||||||
|
using FoxTube.Controls;
|
||||||
using FoxTube.Controls.Adverts;
|
using FoxTube.Controls.Adverts;
|
||||||
using FoxTube.Controls.Player;
|
using FoxTube.Controls.Player;
|
||||||
using Google.Apis.YouTube.v3.Data;
|
using Google.Apis.YouTube.v3.Data;
|
||||||
@@ -6,57 +7,29 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Windows.ApplicationModel.Resources;
|
using Windows.ApplicationModel.Resources;
|
||||||
using Windows.Foundation;
|
using Windows.Foundation;
|
||||||
using Windows.Graphics.Display;
|
using Windows.Graphics.Display;
|
||||||
|
using Windows.Media;
|
||||||
using Windows.Media.Core;
|
using Windows.Media.Core;
|
||||||
|
using Windows.UI.Core;
|
||||||
using Windows.UI.Xaml;
|
using Windows.UI.Xaml;
|
||||||
using Windows.UI.Xaml.Controls;
|
using Windows.UI.Xaml.Controls;
|
||||||
using Windows.UI.Xaml.Controls.Primitives;
|
using Windows.UI.Xaml.Controls.Primitives;
|
||||||
|
using Windows.UI.Xaml.Media;
|
||||||
using YoutubeExplode;
|
using YoutubeExplode;
|
||||||
using YoutubeExplode.Models.ClosedCaptions;
|
using YoutubeExplode.Models.ClosedCaptions;
|
||||||
using YoutubeExplode.Models.MediaStreams;
|
using YoutubeExplode.Models.MediaStreams;
|
||||||
|
|
||||||
namespace FoxTube
|
namespace FoxTube.Controls.Player
|
||||||
{
|
{
|
||||||
public delegate void MinimodeChangedEventHandler(object sender, bool isOn);
|
|
||||||
|
|
||||||
public enum PlayerDisplayState { Normal, Minimized, Compact }
|
|
||||||
|
|
||||||
public class QualityComparer : IComparer<string>
|
|
||||||
{
|
|
||||||
public int Compare(string x, string y)
|
|
||||||
{
|
|
||||||
string[] xArr = x.Split('p');
|
|
||||||
string[] yArr = y.Split('p');
|
|
||||||
|
|
||||||
int qualityA = int.Parse(xArr[0]);
|
|
||||||
int qualityB = int.Parse(yArr[0]);
|
|
||||||
int framerateA = 30;
|
|
||||||
int framerateB = 30;
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(xArr[1]))
|
|
||||||
framerateA = int.Parse(xArr[1]);
|
|
||||||
if (!string.IsNullOrWhiteSpace(yArr[1]))
|
|
||||||
framerateB = int.Parse(yArr[1]);
|
|
||||||
|
|
||||||
if (qualityA > qualityB)
|
|
||||||
return 1;
|
|
||||||
else if (qualityA < qualityB)
|
|
||||||
return -1;
|
|
||||||
else
|
|
||||||
return framerateA - framerateB > 0 ? 1 : -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Custom controls for media player. MARKUP IS IN **Themes/Generic.xaml**!!!
|
/// Custom controls for media player. MARKUP IS IN **Themes/Generic.xaml**!!!
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class PlayerControls : MediaTransportControls
|
public sealed partial class PlayerControls : MediaTransportControls
|
||||||
{
|
{
|
||||||
public event RoutedEventHandler CloseRequested;
|
|
||||||
public event MinimodeChangedEventHandler MiniModeChanged;
|
|
||||||
public event RoutedEventHandler NextRequested;
|
|
||||||
|
|
||||||
#region Controls variables
|
#region Controls variables
|
||||||
Button minimize;
|
Button minimize;
|
||||||
@@ -64,6 +37,7 @@ namespace FoxTube
|
|||||||
Button miniview;
|
Button miniview;
|
||||||
Button play;
|
Button play;
|
||||||
Button next;
|
Button next;
|
||||||
|
Button prev;
|
||||||
Button volumeMenu;
|
Button volumeMenu;
|
||||||
Button mute;
|
Button mute;
|
||||||
Button live;
|
Button live;
|
||||||
@@ -97,17 +71,12 @@ namespace FoxTube
|
|||||||
Grid centerTrigger;
|
Grid centerTrigger;
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
PlayerDisplayState State { get; set; } = PlayerDisplayState.Normal;
|
|
||||||
|
|
||||||
public MediaElement Player { get; set; }
|
|
||||||
public PlayerAdvert Advert;
|
public PlayerAdvert Advert;
|
||||||
public LiveCaptions Caption;
|
public LiveCaptions Caption;
|
||||||
|
|
||||||
TimeSpan timecodeBackup;
|
TimeSpan timecodeBackup;
|
||||||
bool needUpdateTimecode = false;
|
bool needUpdateTimecode = false;
|
||||||
|
|
||||||
public Video Meta { get; set; }
|
|
||||||
|
|
||||||
public IReadOnlyList<ClosedCaptionTrackInfo> ClosedCaptions { get; set; }
|
public IReadOnlyList<ClosedCaptionTrackInfo> ClosedCaptions { get; set; }
|
||||||
public MediaStreamInfoSet MediaStreams { get; set; }
|
public MediaStreamInfoSet MediaStreams { get; set; }
|
||||||
|
|
||||||
@@ -125,11 +94,22 @@ namespace FoxTube
|
|||||||
|
|
||||||
isReady = true;
|
isReady = true;
|
||||||
|
|
||||||
|
Player.MediaOpened += Player_MediaOpened;
|
||||||
|
Player.MarkerReached += (s, e) => PushAdvert();
|
||||||
|
Player.CurrentStateChanged += Player_CurrentStateChanged;
|
||||||
|
Caption.Player = Player;
|
||||||
|
|
||||||
minimize.Click += Minimize_Click;
|
minimize.Click += Minimize_Click;
|
||||||
close.Click += Close_Click;
|
close.Click += Close_Click;
|
||||||
miniview.Click += Miniview_Click;
|
miniview.Click += Miniview_Click;
|
||||||
|
|
||||||
|
mute.Click += async (s, e) =>
|
||||||
|
{
|
||||||
|
await Task.Delay(10);
|
||||||
|
Volume_ValueChanged(this, null);
|
||||||
|
};
|
||||||
next.Click += Next_Click;
|
next.Click += Next_Click;
|
||||||
|
prev.Click += Prev_Click;
|
||||||
volume.ValueChanged += Volume_ValueChanged;
|
volume.ValueChanged += Volume_ValueChanged;
|
||||||
playbackSpeed.ValueChanged += PlaybackSpeed_ValueChanged;
|
playbackSpeed.ValueChanged += PlaybackSpeed_ValueChanged;
|
||||||
live.Click += Live_Click;
|
live.Click += Live_Click;
|
||||||
@@ -139,8 +119,19 @@ namespace FoxTube
|
|||||||
quality.SelectionChanged += Quality_SelectionChanged;
|
quality.SelectionChanged += Quality_SelectionChanged;
|
||||||
seek.ValueChanged += Seek_ValueChanged;
|
seek.ValueChanged += Seek_ValueChanged;
|
||||||
|
|
||||||
Player.Tapped += (s, e) =>
|
IsCompactOverlayButtonVisible = true;
|
||||||
|
IsCompactOverlayEnabled = true;
|
||||||
|
IsFullWindowButtonVisible = true;
|
||||||
|
IsFullWindowEnabled = true;
|
||||||
|
IsSkipBackwardButtonVisible = true;
|
||||||
|
IsSkipBackwardEnabled = true;
|
||||||
|
IsSkipForwardButtonVisible = true;
|
||||||
|
IsSkipForwardEnabled = true;
|
||||||
|
|
||||||
|
Player.Tapped += async (s, e) =>
|
||||||
{
|
{
|
||||||
|
await Task.Delay(10);
|
||||||
|
|
||||||
Rect view = new Rect(0, 0, centerTrigger.ActualWidth, centerTrigger.ActualHeight);
|
Rect view = new Rect(0, 0, centerTrigger.ActualWidth, centerTrigger.ActualHeight);
|
||||||
Point p = e.GetPosition(centerTrigger);
|
Point p = e.GetPosition(centerTrigger);
|
||||||
|
|
||||||
@@ -160,10 +151,20 @@ namespace FoxTube
|
|||||||
base.OnApplyTemplate();
|
base.OnApplyTemplate();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PlaybackSpeed_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
|
private void Player_CurrentStateChanged(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
Player.PlaybackRate = playbackSpeed.Value;
|
systemControls.PlaybackStatus = Player.CurrentState == MediaElementState.Playing ? MediaPlaybackStatus.Playing : MediaPlaybackStatus.Paused;
|
||||||
|
|
||||||
|
if (Player.CurrentState == MediaElementState.Paused)
|
||||||
|
if (!incognito && Item.Snippet.LiveBroadcastContent == "none")
|
||||||
|
{
|
||||||
|
History.LeftOn = Player.Position;
|
||||||
|
HistorySet.Update(History);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PlaybackSpeed_ValueChanged(object sender, RangeBaseValueChangedEventArgs e) =>
|
||||||
|
Player.PlaybackRate = playbackSpeed.Value;
|
||||||
|
|
||||||
void AssignControls()
|
void AssignControls()
|
||||||
{
|
{
|
||||||
@@ -172,6 +173,7 @@ namespace FoxTube
|
|||||||
miniview = GetTemplateChild("CompactOverlayButton") as Button;
|
miniview = GetTemplateChild("CompactOverlayButton") as Button;
|
||||||
play = GetTemplateChild("PlayPauseButton") as Button;
|
play = GetTemplateChild("PlayPauseButton") as Button;
|
||||||
next = GetTemplateChild("NextButton") as Button;
|
next = GetTemplateChild("NextButton") as Button;
|
||||||
|
prev = GetTemplateChild("PreviousButton") as Button;
|
||||||
volumeMenu = GetTemplateChild("VolumeMenuButton") as Button;
|
volumeMenu = GetTemplateChild("VolumeMenuButton") as Button;
|
||||||
mute = GetTemplateChild("AudioMuteButton") as Button;
|
mute = GetTemplateChild("AudioMuteButton") as Button;
|
||||||
live = GetTemplateChild("PlayLiveButton") as Button;
|
live = GetTemplateChild("PlayLiveButton") as Button;
|
||||||
@@ -207,14 +209,14 @@ namespace FoxTube
|
|||||||
centerTrigger = GetTemplateChild("centerTrigger") as Grid;
|
centerTrigger = GetTemplateChild("centerTrigger") as Grid;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Seek_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
|
private void Seek_ValueChanged(object sender, RangeBaseValueChangedEventArgs e) =>
|
||||||
{
|
|
||||||
seekIndicator.Value = seek.Value;
|
seekIndicator.Value = seek.Value;
|
||||||
}
|
|
||||||
|
|
||||||
private async void Quality_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
private async void Quality_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||||
{
|
{
|
||||||
if (Meta.Snippet.LiveBroadcastContent == "live")
|
if (e.AddedItems.Count == 0)
|
||||||
|
return;
|
||||||
|
if (Item.Snippet.LiveBroadcastContent == "live")
|
||||||
goto SetQuality;
|
goto SetQuality;
|
||||||
if(!needUpdateTimecode)
|
if(!needUpdateTimecode)
|
||||||
timecodeBackup = Player.Position;
|
timecodeBackup = Player.Position;
|
||||||
@@ -227,7 +229,7 @@ namespace FoxTube
|
|||||||
if (info is MuxedStreamInfo)
|
if (info is MuxedStreamInfo)
|
||||||
Player.SetPlaybackSource(MediaSource.CreateFromUri((info as MuxedStreamInfo).Url.ToUri()));
|
Player.SetPlaybackSource(MediaSource.CreateFromUri((info as MuxedStreamInfo).Url.ToUri()));
|
||||||
else if (info is VideoStreamInfo || info == null)
|
else if (info is VideoStreamInfo || info == null)
|
||||||
Player.SetPlaybackSource(MediaSource.CreateFromUri(await ManifestGenerator.GetManifest(Meta, info as VideoStreamInfo, MediaStreams)));
|
Player.SetPlaybackSource(MediaSource.CreateFromUri(await ManifestGenerator.GetManifest(Item, info as VideoStreamInfo, MediaStreams)));
|
||||||
else if (info is StreamQuality)
|
else if (info is StreamQuality)
|
||||||
Player.SetPlaybackSource(MediaSource.CreateFromUri((info as StreamQuality).Url));
|
Player.SetPlaybackSource(MediaSource.CreateFromUri((info as StreamQuality).Url));
|
||||||
}
|
}
|
||||||
@@ -256,9 +258,15 @@ namespace FoxTube
|
|||||||
|
|
||||||
private void Next_Click(object sender, RoutedEventArgs e)
|
private void Next_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
NextRequested.Invoke(sender, e);
|
if (Playlist == null)
|
||||||
|
NextRequested?.Invoke();
|
||||||
|
else
|
||||||
|
Playlist.Next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void Prev_Click(object sender, RoutedEventArgs e) =>
|
||||||
|
Playlist.Previous();
|
||||||
|
|
||||||
private void Miniview_Click(object sender, RoutedEventArgs e)
|
private void Miniview_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
if (State == PlayerDisplayState.Compact)
|
if (State == PlayerDisplayState.Compact)
|
||||||
@@ -267,11 +275,6 @@ namespace FoxTube
|
|||||||
EnterMiniview();
|
EnterMiniview();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateVolumeIcon()
|
|
||||||
{
|
|
||||||
Volume_ValueChanged(this, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Volume_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
|
private void Volume_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
|
||||||
{
|
{
|
||||||
double v = volume.Value;
|
double v = volume.Value;
|
||||||
@@ -289,6 +292,13 @@ namespace FoxTube
|
|||||||
|
|
||||||
private void Player_MediaOpened(object sender, RoutedEventArgs args)
|
private void Player_MediaOpened(object sender, RoutedEventArgs args)
|
||||||
{
|
{
|
||||||
|
if ((timecodeBackup == null || timecodeBackup.TotalSeconds < 3) && History.LeftOn.TotalSeconds.Belongs(30, Player.NaturalDuration.TimeSpan.TotalSeconds - 120))
|
||||||
|
{
|
||||||
|
Player.Position = History.LeftOn;
|
||||||
|
needUpdateTimecode = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!needUpdateTimecode)
|
if (!needUpdateTimecode)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -298,7 +308,10 @@ namespace FoxTube
|
|||||||
|
|
||||||
private void Close_Click(object sender, RoutedEventArgs e)
|
private void Close_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
CloseRequested?.Invoke(sender, e);
|
systemControls.IsEnabled = false;
|
||||||
|
Player.Stop();
|
||||||
|
Player.Source = null;
|
||||||
|
//Methods.MainPage.CloseVideo();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Minimize_Click(object sender, RoutedEventArgs e)
|
private void Minimize_Click(object sender, RoutedEventArgs e)
|
||||||
@@ -314,6 +327,8 @@ namespace FoxTube
|
|||||||
if (State == PlayerDisplayState.Minimized)
|
if (State == PlayerDisplayState.Minimized)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
//Methods.MainPage.MinimizeVideo(true);
|
||||||
|
|
||||||
header.Children.Remove(minimize);
|
header.Children.Remove(minimize);
|
||||||
center.Children.Add(minimize);
|
center.Children.Add(minimize);
|
||||||
rightHeader.Children.Remove(close);
|
rightHeader.Children.Remove(close);
|
||||||
@@ -331,7 +346,7 @@ namespace FoxTube
|
|||||||
|
|
||||||
minimize.Content = "\xE010";
|
minimize.Content = "\xE010";
|
||||||
|
|
||||||
MiniModeChanged.Invoke(this, true);
|
MiniModeChanged?.Invoke(true);
|
||||||
Caption.Minimize();
|
Caption.Minimize();
|
||||||
|
|
||||||
State = PlayerDisplayState.Minimized;
|
State = PlayerDisplayState.Minimized;
|
||||||
@@ -342,6 +357,8 @@ namespace FoxTube
|
|||||||
if (State == PlayerDisplayState.Normal)
|
if (State == PlayerDisplayState.Normal)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
//Methods.MainPage.MaximizeVideo(true);
|
||||||
|
|
||||||
if(State == PlayerDisplayState.Compact)
|
if(State == PlayerDisplayState.Compact)
|
||||||
{
|
{
|
||||||
center.Children.Remove(miniview);
|
center.Children.Remove(miniview);
|
||||||
@@ -370,7 +387,7 @@ namespace FoxTube
|
|||||||
centerStack.Children.Remove(bwd);
|
centerStack.Children.Remove(bwd);
|
||||||
rightFooter.Children.Insert(0, bwd);
|
rightFooter.Children.Insert(0, bwd);
|
||||||
|
|
||||||
MiniModeChanged.Invoke(this, false);
|
MiniModeChanged?.Invoke(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
drag.Visibility = Visibility.Collapsed;
|
drag.Visibility = Visibility.Collapsed;
|
||||||
@@ -413,120 +430,27 @@ namespace FoxTube
|
|||||||
State = PlayerDisplayState.Compact;
|
State = PlayerDisplayState.Compact;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void Load(Video meta)
|
void PushAdvert()
|
||||||
{
|
|
||||||
if(!isReady)
|
|
||||||
{
|
|
||||||
queue.Enqueue(() => Load(meta));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Player.MediaOpened += Player_MediaOpened;
|
|
||||||
|
|
||||||
Meta = meta;
|
|
||||||
title.Text = meta.Snippet.Title;
|
|
||||||
channel.Text = meta.Snippet.ChannelTitle;
|
|
||||||
|
|
||||||
MediaStreams = await new YoutubeClient().GetVideoMediaStreamInfosAsync(meta.Id);
|
|
||||||
|
|
||||||
if (meta.Snippet.LiveBroadcastContent == "none")
|
|
||||||
{
|
|
||||||
ClosedCaptions = await new YoutubeClient().GetVideoClosedCaptionTrackInfosAsync(meta.Id);
|
|
||||||
|
|
||||||
uint screenHeight = DisplayInformation.GetForCurrentView().ScreenHeightInRawPixels;
|
|
||||||
|
|
||||||
List<string> qualityList = MediaStreams.GetAllVideoQualityLabels().ToList();
|
|
||||||
qualityList.Sort(new QualityComparer());
|
|
||||||
qualityList.Reverse();
|
|
||||||
|
|
||||||
quality.Items.Add(new ComboBoxItem
|
|
||||||
{
|
|
||||||
Content = ResourceLoader.GetForCurrentView("VideoPage").GetString("/VideoPage/auto")
|
|
||||||
});
|
|
||||||
|
|
||||||
foreach (string i in qualityList)
|
|
||||||
{
|
|
||||||
object tag;
|
|
||||||
if (MediaStreams.Muxed.Any(m => m.VideoQualityLabel == i && m.Resolution.Height <= screenHeight))
|
|
||||||
tag = MediaStreams.Muxed.Find(m => m.VideoQualityLabel == i);
|
|
||||||
else if (MediaStreams.Video.Any(m => m.VideoQualityLabel == i && m.Resolution.Height <= screenHeight && m.Container.GetFileExtension() == "mp4"))
|
|
||||||
tag = MediaStreams.Video.Find(m => m.VideoQualityLabel == i && m.Container.GetFileExtension() == "mp4");
|
|
||||||
else
|
|
||||||
continue;
|
|
||||||
|
|
||||||
quality.Items.Add(new ComboBoxItem
|
|
||||||
{
|
|
||||||
Content = i,
|
|
||||||
Tag = tag
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
string s = SettingsStorage.VideoQuality == "remember" ? SettingsStorage.RememberedQuality : SettingsStorage.VideoQuality;
|
|
||||||
|
|
||||||
if (quality.Items.Any(i => ((i as ComboBoxItem).Content as string).Contains(s)))
|
|
||||||
quality.SelectedItem = quality.Items.Find(i => ((i as ComboBoxItem).Content as string).Contains(s));
|
|
||||||
else
|
|
||||||
quality.SelectedIndex = 0;
|
|
||||||
|
|
||||||
|
|
||||||
if (ClosedCaptions.Count == 0)
|
|
||||||
{
|
|
||||||
captionsMenu.Visibility = Visibility.Collapsed;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (ClosedCaptionTrackInfo i in ClosedCaptions)
|
|
||||||
captions.Items.Add(new ComboBoxItem
|
|
||||||
{
|
|
||||||
Content = string.Format("{0} {1}", CultureInfo.GetCultureInfo(i.Language.Code).DisplayName, i.IsAutoGenerated ? ResourceLoader.GetForCurrentView("VideoPage").GetString("/VideoPage/generatedCaption") : ""),
|
|
||||||
Tag = i
|
|
||||||
});
|
|
||||||
|
|
||||||
ClosedCaptionTrackInfo item = ClosedCaptions.Find(i => SettingsStorage.RelevanceLanguage.Contains(i.Language.Code)) ?? ClosedCaptions.Find(i => "en-US".Contains(i.Language.Code));
|
|
||||||
if (item == null)
|
|
||||||
item = ClosedCaptions.First();
|
|
||||||
|
|
||||||
captions.SelectedItem = captions.Items.Find(i => (i as ComboBoxItem).Tag as ClosedCaptionTrackInfo == item);
|
|
||||||
|
|
||||||
Caption.Player = Player;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
captionsMenu.Visibility = Visibility.Collapsed;
|
|
||||||
seek.Visibility = Visibility.Collapsed;
|
|
||||||
live.Visibility = Visibility.Visible;
|
|
||||||
remain.Visibility = Visibility.Collapsed;
|
|
||||||
elapsed.FontSize = 24;
|
|
||||||
Grid.SetRow(elapsed, 0);
|
|
||||||
Grid.SetRowSpan(elapsed, 2);
|
|
||||||
elapsed.HorizontalAlignment = HorizontalAlignment.Right;
|
|
||||||
fwd.Visibility = Visibility.Collapsed;
|
|
||||||
bwd.Visibility = Visibility.Collapsed;
|
|
||||||
|
|
||||||
List<StreamQuality> list = await ManifestGenerator.ResolveLiveSteream(MediaStreams.HlsLiveStreamUrl);
|
|
||||||
|
|
||||||
foreach (StreamQuality i in list)
|
|
||||||
quality.Items.Add(new ComboBoxItem
|
|
||||||
{
|
|
||||||
Content = i.Resolution,
|
|
||||||
Tag = i
|
|
||||||
});
|
|
||||||
|
|
||||||
string s = SettingsStorage.VideoQuality == "remember" ? SettingsStorage.RememberedQuality : SettingsStorage.VideoQuality;
|
|
||||||
|
|
||||||
if (quality.Items.Any(i => (i as ComboBoxItem).Content as string == s))
|
|
||||||
quality.SelectedItem = quality.Items.Find(i => (i as ComboBoxItem).Content as string == s);
|
|
||||||
else
|
|
||||||
quality.SelectedIndex = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Focus(FocusState.Programmatic);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PushAdvert()
|
|
||||||
{
|
{
|
||||||
if(State == PlayerDisplayState.Normal)
|
if(State == PlayerDisplayState.Normal)
|
||||||
Advert.PushAdvert();
|
Advert.PushAdvert();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async void SystemControls_Engaged(SystemMediaTransportControls sender, SystemMediaTransportControlsButtonPressedEventArgs args) =>
|
||||||
|
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
|
||||||
|
{
|
||||||
|
switch (args.Button)
|
||||||
|
{
|
||||||
|
case SystemMediaTransportControlsButton.Play:
|
||||||
|
Player.Play();
|
||||||
|
break;
|
||||||
|
case SystemMediaTransportControlsButton.Pause:
|
||||||
|
Player.Pause();
|
||||||
|
break;
|
||||||
|
case SystemMediaTransportControlsButton.Next:
|
||||||
|
Next_Click(this, null);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,208 @@
|
|||||||
|
using FoxTube.Classes;
|
||||||
|
using Google.Apis.YouTube.v3.Data;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Windows.ApplicationModel.Resources;
|
||||||
|
using Windows.Graphics.Display;
|
||||||
|
using Windows.Media;
|
||||||
|
using Windows.Storage.Streams;
|
||||||
|
using Windows.System;
|
||||||
|
using Windows.UI.Xaml;
|
||||||
|
using Windows.UI.Xaml.Controls;
|
||||||
|
using Windows.UI.Xaml.Media.Imaging;
|
||||||
|
using YoutubeExplode;
|
||||||
|
using YoutubeExplode.Models.ClosedCaptions;
|
||||||
|
using YoutubeExplode.Models.MediaStreams;
|
||||||
|
using FoxTube.Controls.VideoPage;
|
||||||
|
using Windows.UI.Xaml.Media;
|
||||||
|
|
||||||
|
namespace FoxTube.Controls.Player
|
||||||
|
{
|
||||||
|
public partial class PlayerControls : MediaTransportControls
|
||||||
|
{
|
||||||
|
public event SimpleEventHandler CloseRequested;
|
||||||
|
public event MinimodeChangedEventHandler MiniModeChanged;
|
||||||
|
public event SimpleEventHandler NextRequested;
|
||||||
|
|
||||||
|
public PlayerDisplayState State { get; set; } = PlayerDisplayState.Normal;
|
||||||
|
public Video Item { get; private set; }
|
||||||
|
HistoryItem History { get; set; }
|
||||||
|
VideoPlaylist Playlist { get; set; }
|
||||||
|
|
||||||
|
public MediaElement Player { get; set; }
|
||||||
|
|
||||||
|
SystemMediaTransportControls systemControls;
|
||||||
|
bool incognito;
|
||||||
|
|
||||||
|
public void Initialize(Video item, string avatarUrl, bool incognito = false, VideoPlaylist playlist = null)
|
||||||
|
{
|
||||||
|
this.incognito = incognito;
|
||||||
|
Playlist = playlist;
|
||||||
|
Item = item;
|
||||||
|
|
||||||
|
History = HistorySet.Items.Find(i => i.Id == Item.Id);
|
||||||
|
if (History == null && !incognito)
|
||||||
|
{
|
||||||
|
History = new HistoryItem { Id = Item.Id };
|
||||||
|
HistorySet.Update(History);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.Snippet.LiveBroadcastContent == "upcoming")
|
||||||
|
Player.AreTransportControlsEnabled = false;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LoadControls(avatarUrl);
|
||||||
|
if (item.Snippet.LiveBroadcastContent == "none")
|
||||||
|
LoadVideo();
|
||||||
|
else
|
||||||
|
LoadStream();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadControls(string avatar)
|
||||||
|
{
|
||||||
|
if (!isReady)
|
||||||
|
{
|
||||||
|
queue.Enqueue(() => LoadControls(avatar));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
prev.Visibility = Visibility.Collapsed;
|
||||||
|
captionsSwitch.IsOn = false;
|
||||||
|
|
||||||
|
Player.Volume = SettingsStorage.Volume;
|
||||||
|
Player.AutoPlay = SettingsStorage.Autoplay;
|
||||||
|
|
||||||
|
|
||||||
|
title.Text = Item.Snippet.Title;
|
||||||
|
channel.Text = Item.Snippet.ChannelTitle;
|
||||||
|
|
||||||
|
#region System Media Transport Controls
|
||||||
|
systemControls = SystemMediaTransportControls.GetForCurrentView();
|
||||||
|
systemControls.IsPauseEnabled = true;
|
||||||
|
systemControls.IsPlayEnabled = true;
|
||||||
|
|
||||||
|
if(Playlist != null)
|
||||||
|
{
|
||||||
|
next.IsEnabled = Playlist.SelectedIndex + 1 < Playlist.Items.Count;
|
||||||
|
prev.Visibility = Visibility.Visible;
|
||||||
|
prev.IsEnabled = Playlist.SelectedIndex != 0;
|
||||||
|
systemControls.IsNextEnabled = systemControls.IsPreviousEnabled = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
next.IsEnabled = systemControls.IsNextEnabled = true;
|
||||||
|
|
||||||
|
systemControls.DisplayUpdater.Type = MediaPlaybackType.Video;
|
||||||
|
systemControls.DisplayUpdater.VideoProperties.Title = Item.Snippet.Title;
|
||||||
|
systemControls.DisplayUpdater.VideoProperties.Subtitle = Item.Snippet.ChannelTitle;
|
||||||
|
systemControls.DisplayUpdater.Thumbnail = RandomAccessStreamReference.CreateFromUri(avatar.ToUri());
|
||||||
|
systemControls.DisplayUpdater.Update();
|
||||||
|
|
||||||
|
systemControls.ButtonPressed += SystemControls_Engaged;
|
||||||
|
systemControls.IsEnabled = true;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
quality.Items.Clear();
|
||||||
|
captions.Items.Clear();
|
||||||
|
Player.Markers.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
async void LoadVideo()
|
||||||
|
{
|
||||||
|
if (Methods.GetDuration(Item.ContentDetails.Duration).TotalMinutes > 5)
|
||||||
|
Player.Markers.Add(new TimelineMarker { Time = Methods.GetDuration(Item.ContentDetails.Duration) - TimeSpan.FromMinutes(1) });
|
||||||
|
if (Methods.GetDuration(Item.ContentDetails.Duration).TotalMinutes >= 60)
|
||||||
|
for (int k = 1; k < Methods.GetDuration(Item.ContentDetails.Duration).TotalMinutes / 30; k++)
|
||||||
|
Player.Markers.Add(new TimelineMarker { Time = TimeSpan.FromMinutes(k * 30) });
|
||||||
|
|
||||||
|
MediaStreamInfoSet set = await new YoutubeClient().GetVideoMediaStreamInfosAsync(Item.Id);
|
||||||
|
|
||||||
|
uint screenHeight = DisplayInformation.GetForCurrentView().ScreenHeightInRawPixels;
|
||||||
|
|
||||||
|
List<string> qualityList = set.GetAllVideoQualityLabels().ToList();
|
||||||
|
qualityList.Sort(new QualityComparer());
|
||||||
|
qualityList.Reverse();
|
||||||
|
|
||||||
|
quality.Items.Add(new ComboBoxItem
|
||||||
|
{
|
||||||
|
Content = ResourceLoader.GetForCurrentView("VideoPage").GetString("/VideoPage/auto")
|
||||||
|
});
|
||||||
|
|
||||||
|
foreach (string i in qualityList)
|
||||||
|
{
|
||||||
|
object tag = (object)set.Muxed.Find(m => m.VideoQualityLabel == i && m.Resolution.Height <= screenHeight) ?? set.Video.Find(m => m.VideoQualityLabel == i && m.Container.GetFileExtension() == "mp4");
|
||||||
|
|
||||||
|
if (tag == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
quality.Items.Add(new ComboBoxItem
|
||||||
|
{
|
||||||
|
Content = i,
|
||||||
|
Tag = tag
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
string s = SettingsStorage.VideoQuality == "remember" ? SettingsStorage.RememberedQuality : SettingsStorage.VideoQuality;
|
||||||
|
|
||||||
|
if (quality.Items.Find(i => ((i as ComboBoxItem).Content as string).Contains(s)) is ComboBoxItem item)
|
||||||
|
quality.SelectedItem = item;
|
||||||
|
else
|
||||||
|
quality.SelectedIndex = 0;
|
||||||
|
|
||||||
|
|
||||||
|
IReadOnlyList<ClosedCaptionTrackInfo> cc = await new YoutubeClient().GetVideoClosedCaptionTrackInfosAsync(Item.Id);
|
||||||
|
|
||||||
|
captionsMenu.Visibility = cc.Count == 0 ? Visibility.Collapsed : Visibility.Visible;
|
||||||
|
|
||||||
|
foreach (ClosedCaptionTrackInfo i in cc)
|
||||||
|
captions.Items.Add(new ComboBoxItem
|
||||||
|
{
|
||||||
|
Content = $"{CultureInfo.GetCultureInfo(i.Language.Code).DisplayName}{(i.IsAutoGenerated ? $" ({ResourceLoader.GetForCurrentView("VideoPage").GetString("/VideoPage/generatedCaption")})" : "")})",
|
||||||
|
Tag = i
|
||||||
|
});
|
||||||
|
|
||||||
|
ClosedCaptionTrackInfo ccItem = cc.Find(i => SettingsStorage.RelevanceLanguage.Contains(i.Language.Code)) ?? cc.Find(i => "en-US".Contains(i.Language.Code));
|
||||||
|
ccItem = ccItem ?? cc.FirstOrDefault();
|
||||||
|
|
||||||
|
captions.SelectedItem = captions.Items.Find(i => (i as ComboBoxItem).Tag as ClosedCaptionTrackInfo == ccItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
async void LoadStream()
|
||||||
|
{
|
||||||
|
List<StreamQuality> qualities = await ManifestGenerator.ResolveLiveSteream((await new YoutubeClient().GetVideoMediaStreamInfosAsync(Item.Id)).HlsLiveStreamUrl);
|
||||||
|
|
||||||
|
foreach (StreamQuality i in qualities)
|
||||||
|
quality.Items.Add(new ComboBoxItem
|
||||||
|
{
|
||||||
|
Content = i.Resolution,
|
||||||
|
Tag = i
|
||||||
|
});
|
||||||
|
|
||||||
|
string s = SettingsStorage.VideoQuality == "remember" ? SettingsStorage.RememberedQuality : SettingsStorage.VideoQuality;
|
||||||
|
|
||||||
|
if (quality.Items.Find(i => (i as ComboBoxItem).Content as string == s) is ComboBoxItem item)
|
||||||
|
quality.SelectedItem = item;
|
||||||
|
else
|
||||||
|
quality.SelectedIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Pause() =>
|
||||||
|
Player.Pause();
|
||||||
|
|
||||||
|
public async void OpenBrowser()
|
||||||
|
{
|
||||||
|
Player.Pause();
|
||||||
|
string timecode = Player.Position.TotalSeconds > 10 ?
|
||||||
|
"&t=" + (int)Player.Position.TotalSeconds + "s" : string.Empty;
|
||||||
|
|
||||||
|
await Launcher.LaunchUriAsync($"https://www.youtube.com/watch?v={Item.Id}{timecode}".ToUri());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetMargin(double offset) =>
|
||||||
|
Player.Margin = new Thickness(Player.Margin.Left, offset * -1, Player.Margin.Right, Player.Margin.Bottom);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:foxtube="using:FoxTube"
|
xmlns:foxtube="using:FoxTube.Controls.Player"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="1080"
|
d:DesignHeight="1080"
|
||||||
d:DesignWidth="1920"
|
d:DesignWidth="1920"
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ using Windows.UI.Xaml.Media.Imaging;
|
|||||||
using Windows.Media;
|
using Windows.Media;
|
||||||
using Windows.Storage.Streams;
|
using Windows.Storage.Streams;
|
||||||
using Windows.UI.Xaml.Media;
|
using Windows.UI.Xaml.Media;
|
||||||
|
using FoxTube.Controls.Player;
|
||||||
|
|
||||||
namespace FoxTube
|
namespace FoxTube
|
||||||
{
|
{
|
||||||
@@ -45,7 +46,7 @@ namespace FoxTube
|
|||||||
if (item.Snippet.LiveBroadcastContent == "none")
|
if (item.Snippet.LiveBroadcastContent == "none")
|
||||||
{
|
{
|
||||||
InitializeContols();
|
InitializeContols();
|
||||||
Controls.Load(item);
|
//Controls.Load(item);
|
||||||
|
|
||||||
if (Methods.GetDuration(item.ContentDetails.Duration).TotalMinutes > 5)
|
if (Methods.GetDuration(item.ContentDetails.Duration).TotalMinutes > 5)
|
||||||
videoSource.Markers.Add(new TimelineMarker { Time = Methods.GetDuration(item.ContentDetails.Duration) - TimeSpan.FromMinutes(1) });
|
videoSource.Markers.Add(new TimelineMarker { Time = Methods.GetDuration(item.ContentDetails.Duration) - TimeSpan.FromMinutes(1) });
|
||||||
@@ -59,7 +60,7 @@ namespace FoxTube
|
|||||||
else if (item.Snippet.LiveBroadcastContent == "live")
|
else if (item.Snippet.LiveBroadcastContent == "live")
|
||||||
{
|
{
|
||||||
InitializeContols();
|
InitializeContols();
|
||||||
Controls.Load(item);
|
//Controls.Load(item);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
videoSource.AreTransportControlsEnabled = false;
|
videoSource.AreTransportControlsEnabled = false;
|
||||||
@@ -73,9 +74,9 @@ namespace FoxTube
|
|||||||
videoSource.AutoPlay = SettingsStorage.Autoplay;
|
videoSource.AutoPlay = SettingsStorage.Autoplay;
|
||||||
|
|
||||||
Controls.CloseRequested += Controls_CloseRequested;
|
Controls.CloseRequested += Controls_CloseRequested;
|
||||||
Controls.NextRequested += (s, e) => NextClicked?.Invoke();
|
Controls.NextRequested += () => NextClicked?.Invoke();
|
||||||
Controls.MiniModeChanged += Controls_MiniModeChanged;
|
Controls.MiniModeChanged += Controls_MiniModeChanged;
|
||||||
Controls.Player = videoSource;
|
//Controls.Player = videoSource;
|
||||||
|
|
||||||
#region System Media Transport Controls
|
#region System Media Transport Controls
|
||||||
systemControls = SystemMediaTransportControls.GetForCurrentView();
|
systemControls = SystemMediaTransportControls.GetForCurrentView();
|
||||||
@@ -113,7 +114,7 @@ namespace FoxTube
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Controls_MiniModeChanged(object sender, bool e)
|
public void Controls_MiniModeChanged(bool e)
|
||||||
{
|
{
|
||||||
videoSource.IsFullWindow = false;
|
videoSource.IsFullWindow = false;
|
||||||
|
|
||||||
@@ -125,7 +126,7 @@ namespace FoxTube
|
|||||||
Controls.Minimize();
|
Controls.Minimize();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Controls_CloseRequested(object sender, RoutedEventArgs e)
|
public void Controls_CloseRequested()
|
||||||
{
|
{
|
||||||
videoSource.Pause();
|
videoSource.Pause();
|
||||||
systemControls.IsEnabled = false;
|
systemControls.IsEnabled = false;
|
||||||
@@ -137,7 +138,7 @@ namespace FoxTube
|
|||||||
HistorySet.Update(history);
|
HistorySet.Update(history);
|
||||||
}
|
}
|
||||||
|
|
||||||
Methods.MainPage.CloseVideo();
|
//Methods.MainPage.CloseVideo();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Pause()
|
public void Pause()
|
||||||
@@ -161,12 +162,12 @@ namespace FoxTube
|
|||||||
{
|
{
|
||||||
if(videoSource.Volume != 0)
|
if(videoSource.Volume != 0)
|
||||||
SettingsStorage.Volume = videoSource.Volume;
|
SettingsStorage.Volume = videoSource.Volume;
|
||||||
Controls.UpdateVolumeIcon();
|
//Controls.UpdateVolumeIcon();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void VideoSource_MarkerReached(object sender, TimelineMarkerRoutedEventArgs e)
|
private void VideoSource_MarkerReached(object sender, TimelineMarkerRoutedEventArgs e)
|
||||||
{
|
{
|
||||||
Controls.PushAdvert();
|
//Controls.PushAdvert();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,25 +6,21 @@
|
|||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
VerticalAlignment="Top"
|
VerticalAlignment="Stretch"
|
||||||
d:DesignHeight="290"
|
d:DesignHeight="290"
|
||||||
d:DesignWidth="384"
|
d:DesignWidth="384"
|
||||||
MaxWidth="700"
|
MaxWidth="700"
|
||||||
|
MaxHeight="600"
|
||||||
Opacity="0"
|
Opacity="0"
|
||||||
Name="card"
|
Name="card">
|
||||||
SizeChanged="Card_SizeChanged">
|
|
||||||
|
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
<Storyboard x:Name="show">
|
<Storyboard x:Name="show">
|
||||||
<DoubleAnimation Storyboard.TargetName="card" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="{StaticResource CardOpacityDuration}"/>
|
<DoubleAnimation Storyboard.TargetName="card" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="{StaticResource CardOpacityDuration}"/>
|
||||||
</Storyboard>
|
</Storyboard>
|
||||||
<Storyboard x:Name="showThumb">
|
|
||||||
<DoubleAnimation Storyboard.TargetName="thumbnail" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="{StaticResource CardOpacityDuration}"/>
|
|
||||||
</Storyboard>
|
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
|
|
||||||
<Button Padding="0" Margin="1" Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}" Click="Button_Click">
|
<Grid Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}">
|
||||||
<Grid>
|
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition/>
|
<RowDefinition/>
|
||||||
<RowDefinition Height="20"/>
|
<RowDefinition Height="20"/>
|
||||||
@@ -32,7 +28,7 @@
|
|||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<Image Source="/Assets/videoPlaceholder.png" Opacity=".0001" Stretch="Fill"/>
|
<Image Source="/Assets/videoPlaceholder.png" Opacity=".0001" Stretch="Fill"/>
|
||||||
<Image Name="thumbnail" Source="/Assets/videoThumbSample.png" Stretch="Fill" Opacity="0" ImageOpened="Thumbnail_ImageOpened"/>
|
<Image Name="thumbnail" Source="/Assets/videoThumbSample.png" Stretch="Fill" ImageOpened="Thumbnail_ImageOpened"/>
|
||||||
|
|
||||||
<Grid HorizontalAlignment="Right" Width="100">
|
<Grid HorizontalAlignment="Right" Width="100">
|
||||||
<Grid.Background>
|
<Grid.Background>
|
||||||
@@ -58,7 +54,7 @@
|
|||||||
|
|
||||||
<TextBlock Grid.Row="2" Name="title" Text="[Title]" TextWrapping="WrapWholeWords" TextTrimming="CharacterEllipsis" Margin="5" MaxLines="2"/>
|
<TextBlock Grid.Row="2" Name="title" Text="[Title]" TextWrapping="WrapWholeWords" TextTrimming="CharacterEllipsis" Margin="5" MaxLines="2"/>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Button>
|
|
||||||
<UserControl.ContextFlyout>
|
<UserControl.ContextFlyout>
|
||||||
<MenuFlyout>
|
<MenuFlyout>
|
||||||
<MenuFlyoutItem x:Uid="/Cards/playlist" Icon="List" Text="View playlist" Click="Button_Click"/>
|
<MenuFlyoutItem x:Uid="/Cards/playlist" Icon="List" Text="View playlist" Click="Button_Click"/>
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
using Google.Apis.YouTube.v3;
|
using FoxTube.Classes;
|
||||||
|
using Google.Apis.YouTube.v3;
|
||||||
using Google.Apis.YouTube.v3.Data;
|
using Google.Apis.YouTube.v3.Data;
|
||||||
using Microsoft.AppCenter.Analytics;
|
using Microsoft.AppCenter.Analytics;
|
||||||
using Microsoft.Toolkit.Uwp.UI.Controls;
|
using Microsoft.Toolkit.Uwp.UI.Controls;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Windows.ApplicationModel.DataTransfer;
|
using Windows.ApplicationModel.DataTransfer;
|
||||||
using Windows.System;
|
using Windows.System;
|
||||||
using Windows.UI.Xaml;
|
using Windows.UI.Xaml;
|
||||||
@@ -16,24 +18,21 @@ namespace FoxTube.Controls
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Playlist card control
|
/// Playlist card control
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed partial class PlaylistCard : UserControl
|
public sealed partial class PlaylistCard : UserControl, ICard
|
||||||
{
|
{
|
||||||
Playlist item;
|
Playlist item;
|
||||||
public string playlistId;
|
readonly string playlistId;
|
||||||
|
|
||||||
public bool NeedInitialize { get; set; } = true;
|
|
||||||
|
|
||||||
public PlaylistCard(string id)
|
public PlaylistCard(string id)
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
Initialize(id);
|
playlistId = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void Initialize(string id)
|
public async Task Initialize()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
playlistId = id;
|
|
||||||
PlaylistsResource.ListRequest request = SecretsVault.Service.Playlists.List("snippet,contentDetails");
|
PlaylistsResource.ListRequest request = SecretsVault.Service.Playlists.List("snippet,contentDetails");
|
||||||
request.Id = playlistId;
|
request.Id = playlistId;
|
||||||
request.Hl = SettingsStorage.RelevanceLanguage;
|
request.Hl = SettingsStorage.RelevanceLanguage;
|
||||||
@@ -44,17 +43,12 @@ namespace FoxTube.Controls
|
|||||||
counter.Text = item.ContentDetails.ItemCount.ToString();
|
counter.Text = item.ContentDetails.ItemCount.ToString();
|
||||||
date.Text = Methods.GetAgo(item.Snippet.PublishedAt.Value);
|
date.Text = Methods.GetAgo(item.Snippet.PublishedAt.Value);
|
||||||
|
|
||||||
ChannelsResource.ListRequest r = SecretsVault.Service.Channels.List("snippet");
|
|
||||||
r.Id = item.Snippet.ChannelId;
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
thumbnail.Source = new BitmapImage(item.Snippet.Thumbnails.Medium.Url.ToUri());
|
thumbnail.Source = new BitmapImage(item.Snippet.Thumbnails.Medium.Url.ToUri());
|
||||||
avatar.ProfilePicture = new BitmapImage((await new YoutubeClient().GetChannelAsync(item.Snippet.ChannelId)).LogoUrl.ToUri()) { DecodePixelWidth = 46, DecodePixelHeight = 46 };
|
avatar.ProfilePicture = new BitmapImage((await new YoutubeClient(SecretsVault.HttpClient).GetChannelAsync(item.Snippet.ChannelId)).LogoUrl.ToUri()) { DecodePixelHeight = 46, DecodePixelWidth = 46 };
|
||||||
}
|
}
|
||||||
catch { }
|
catch { }
|
||||||
|
|
||||||
show.Begin();
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@@ -70,36 +64,26 @@ namespace FoxTube.Controls
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Button_Click(object sender, RoutedEventArgs e)
|
public void ItemClicked() =>
|
||||||
{
|
Navigation.GoToPlaylist(item.Id);
|
||||||
Methods.MainPage.GoToPlaylist(item.Id);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OpenChannel_Click(object sender, RoutedEventArgs e)
|
public void Button_Click(object sender, RoutedEventArgs e) =>
|
||||||
{
|
ItemClicked();
|
||||||
Methods.MainPage.GoToChannel(item.Snippet.ChannelId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void GetLink_Click(object sender, RoutedEventArgs e)
|
void OpenChannel_Click(object sender, RoutedEventArgs e) =>
|
||||||
|
Navigation.GoToChannel(item.Snippet.ChannelId);
|
||||||
|
|
||||||
|
void GetLink_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
DataPackage data = new DataPackage();
|
DataPackage data = new DataPackage();
|
||||||
data.SetText($"https://www.youtube.com/playlist?list={playlistId}");
|
data.SetText($"https://www.youtube.com/playlist?list={playlistId}");
|
||||||
Clipboard.SetContent(data);
|
Clipboard.SetContent(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void InBrowser_Click(object sender, RoutedEventArgs e)
|
async void InBrowser_Click(object sender, RoutedEventArgs e) =>
|
||||||
{
|
|
||||||
await Launcher.LaunchUriAsync($"https://www.youtube.com/playlist?list={playlistId}".ToUri());
|
await Launcher.LaunchUriAsync($"https://www.youtube.com/playlist?list={playlistId}".ToUri());
|
||||||
}
|
|
||||||
|
|
||||||
private void Thumbnail_ImageOpened(object sender, RoutedEventArgs e)
|
void Thumbnail_ImageOpened(object sender, RoutedEventArgs e) =>
|
||||||
{
|
show.Begin();
|
||||||
showThumb.Begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Card_SizeChanged(object sender, SizeChangedEventArgs e)
|
|
||||||
{
|
|
||||||
Height = e.NewSize.Width * 0.75;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,10 +6,8 @@ namespace FoxTube.Controls
|
|||||||
public sealed partial class ShowMore : UserControl
|
public sealed partial class ShowMore : UserControl
|
||||||
{
|
{
|
||||||
public event Event Clicked;
|
public event Event Clicked;
|
||||||
public ShowMore()
|
public ShowMore() =>
|
||||||
{
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
|
||||||
|
|
||||||
private void btn_Click(object sender, RoutedEventArgs e)
|
private void btn_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
@@ -18,17 +16,6 @@ namespace FoxTube.Controls
|
|||||||
Clicked.Invoke();
|
Clicked.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Invoke()
|
|
||||||
{
|
|
||||||
btn_Click(this, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Show()
|
|
||||||
{
|
|
||||||
btn.Visibility = Visibility.Collapsed;
|
|
||||||
bar.Visibility = Visibility.Visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Complete()
|
public void Complete()
|
||||||
{
|
{
|
||||||
bar.Visibility = Visibility.Collapsed;
|
bar.Visibility = Visibility.Collapsed;
|
||||||
|
|||||||
@@ -6,25 +6,21 @@
|
|||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
VerticalAlignment="Top"
|
VerticalAlignment="Stretch"
|
||||||
d:DesignHeight="290"
|
d:DesignHeight="290"
|
||||||
d:DesignWidth="384"
|
d:DesignWidth="384"
|
||||||
MaxWidth="700"
|
MaxWidth="700"
|
||||||
|
MaxHeight="600"
|
||||||
Opacity="0"
|
Opacity="0"
|
||||||
Name="card"
|
Name="card">
|
||||||
SizeChanged="Card_SizeChanged">
|
|
||||||
|
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
<Storyboard x:Name="show">
|
<Storyboard x:Name="show">
|
||||||
<DoubleAnimation Storyboard.TargetName="card" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="{StaticResource CardOpacityDuration}"/>
|
<DoubleAnimation Storyboard.TargetName="card" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="{StaticResource CardOpacityDuration}"/>
|
||||||
</Storyboard>
|
</Storyboard>
|
||||||
<Storyboard x:Name="showThumb">
|
|
||||||
<DoubleAnimation Storyboard.TargetName="thumbnail" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="{StaticResource CardOpacityDuration}"/>
|
|
||||||
</Storyboard>
|
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
|
|
||||||
<Button Padding="0" Margin="1" Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}" Click="Button_Click">
|
<Grid Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}">
|
||||||
<Grid>
|
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition/>
|
<RowDefinition/>
|
||||||
<RowDefinition Height="20"/>
|
<RowDefinition Height="20"/>
|
||||||
@@ -32,20 +28,20 @@
|
|||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<Image Source="/Assets/videoPlaceholder.png" Opacity=".0001" Stretch="Fill"/>
|
<Image Source="/Assets/videoPlaceholder.png" Opacity=".0001" Stretch="Fill"/>
|
||||||
<Image Name="thumbnail" Source="/Assets/videoThumbSample.png" Stretch="Fill" ImageOpened="Thumbnail_ImageOpened" Opacity="0"/>
|
<Image Name="thumbnail" Source="/Assets/videoThumbSample.png" Stretch="Fill" ImageOpened="Thumbnail_ImageOpened"/>
|
||||||
|
|
||||||
<Grid Background="#7F000000" Name="watched" Visibility="Collapsed">
|
<Grid Background="#7F000000" Name="watched" Visibility="Collapsed">
|
||||||
<StackPanel Margin="5" Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}" VerticalAlignment="Top" HorizontalAlignment="Left" Padding="5,2,5,2" BorderBrush="Gray" BorderThickness="1">
|
<Border Margin="5" Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}" VerticalAlignment="Top" HorizontalAlignment="Left" Padding="5,2" BorderBrush="Gray" BorderThickness="1">
|
||||||
<TextBlock x:Uid="/Cards/watched" Text="Watched" Foreground="Gray" FontSize="12"/>
|
<TextBlock x:Uid="/Cards/watched" Text="Watched" Foreground="Gray" FontSize="12"/>
|
||||||
</StackPanel>
|
</Border>
|
||||||
<ProgressBar VerticalAlignment="Bottom" Margin="54,0,0,0" Foreground="Red" Name="leftOn"/>
|
<ProgressBar VerticalAlignment="Bottom" Margin="54,0,0,0" Name="leftOn"/>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<StackPanel Margin="0,0,5,5" Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}" VerticalAlignment="Bottom" HorizontalAlignment="Right" Padding="5,2,5,3">
|
<Border Margin="5" Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}" VerticalAlignment="Bottom" HorizontalAlignment="Right" Padding="5,2,5,3">
|
||||||
<TextBlock Name="info" Text="[Duration] | [Published at]" VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="Gray" FontSize="12"/>
|
<TextBlock Name="info" Text="[Duration] | [Published at]" VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="Gray" FontSize="12"/>
|
||||||
</StackPanel>
|
</Border>
|
||||||
|
|
||||||
<StackPanel Name="liveTag" Margin="0,0,5,30" Background="Red" BorderBrush="White" BorderThickness="1" VerticalAlignment="Bottom" HorizontalAlignment="Right" Padding="5,2,5,3" Orientation="Horizontal" Visibility="Collapsed">
|
<StackPanel Name="liveTag" Margin="5,30" Background="Red" BorderBrush="White" BorderThickness="1" VerticalAlignment="Bottom" HorizontalAlignment="Right" Padding="5,2,5,3" Orientation="Horizontal" Visibility="Collapsed">
|
||||||
<TextBlock Text=" " VerticalAlignment="Center" Foreground="White" FontSize="12" FontFamily="Segoe MDL2 Assets" FontWeight="Black"/>
|
<TextBlock Text=" " VerticalAlignment="Center" Foreground="White" FontSize="12" FontFamily="Segoe MDL2 Assets" FontWeight="Black"/>
|
||||||
<TextBlock x:Uid="/Cards/live" Name="liveContent" Text="LIVE" VerticalAlignment="Center" Foreground="White" FontSize="12" FontWeight="Bold"/>
|
<TextBlock x:Uid="/Cards/live" Name="liveContent" Text="LIVE" VerticalAlignment="Center" Foreground="White" FontSize="12" FontWeight="Bold"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
@@ -64,7 +60,6 @@
|
|||||||
|
|
||||||
<TextBlock Grid.Row="2" Name="title" Text="[Title]" TextWrapping="WrapWholeWords" Margin="5" MaxLines="2" TextTrimming="CharacterEllipsis"/>
|
<TextBlock Grid.Row="2" Name="title" Text="[Title]" TextWrapping="WrapWholeWords" Margin="5" MaxLines="2" TextTrimming="CharacterEllipsis"/>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Button>
|
|
||||||
<UserControl.ContextFlyout>
|
<UserControl.ContextFlyout>
|
||||||
<MenuFlyout>
|
<MenuFlyout>
|
||||||
<MenuFlyoutItem x:Uid="/Cards/play" Icon="Play" Text="Play" Name="play" Click="Button_Click"/>
|
<MenuFlyoutItem x:Uid="/Cards/play" Icon="Play" Text="Play" Name="play" Click="Button_Click"/>
|
||||||
@@ -80,11 +75,7 @@
|
|||||||
<MenuFlyoutItem x:Uid="/Cards/share" Icon="Share" Text="Share" Name="share" Click="share_Click"/>
|
<MenuFlyoutItem x:Uid="/Cards/share" Icon="Share" Text="Share" Name="share" Click="share_Click"/>
|
||||||
<MenuFlyoutSeparator/>
|
<MenuFlyoutSeparator/>
|
||||||
<MenuFlyoutSubItem x:Uid="/Cards/downloads" Icon="Download" Text="Download" Name="download"/>
|
<MenuFlyoutSubItem x:Uid="/Cards/downloads" Icon="Download" Text="Download" Name="download"/>
|
||||||
<MenuFlyoutSubItem x:Uid="/Cards/addTo" Icon="Add" Text="Add to" Name="addTo">
|
<MenuFlyoutSubItem x:Uid="/Cards/addTo" Icon="Add" Text="Add to" Name="addTo"/>
|
||||||
<MenuFlyoutItem x:Uid="/VideoPage/newPlaylist" Text="New playlist" Name="newPlaylist" Click="NewPlaylist_Click" Icon="Add"/>
|
|
||||||
<ToggleMenuFlyoutItem x:Uid="/VideoPage/wl" Text="Watch later" Name="wl" Click="Wl_Click" Icon="Clock"/>
|
|
||||||
<MenuFlyoutSeparator/>
|
|
||||||
</MenuFlyoutSubItem>
|
|
||||||
<MenuFlyoutItem x:Uid="/Cards/delete" Text="Remove from playlist" Icon="Delete" Visibility="Collapsed" Name="delete" Click="Delete_Click"/>
|
<MenuFlyoutItem x:Uid="/Cards/delete" Text="Remove from playlist" Icon="Delete" Visibility="Collapsed" Name="delete" Click="Delete_Click"/>
|
||||||
</MenuFlyout>
|
</MenuFlyout>
|
||||||
</UserControl.ContextFlyout>
|
</UserControl.ContextFlyout>
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
using Windows.UI.Xaml;
|
using Windows.UI.Xaml;
|
||||||
using Windows.UI.Xaml.Controls;
|
using Windows.UI.Xaml.Controls;
|
||||||
using Google.Apis.YouTube.v3;
|
using Google.Apis.YouTube.v3;
|
||||||
using Google.Apis.YouTube.v3.Data;
|
|
||||||
using Windows.UI.Xaml.Media.Imaging;
|
using Windows.UI.Xaml.Media.Imaging;
|
||||||
using Windows.System;
|
using Windows.System;
|
||||||
using Windows.ApplicationModel.DataTransfer;
|
using Windows.ApplicationModel.DataTransfer;
|
||||||
@@ -10,112 +9,108 @@ using Windows.ApplicationModel.Resources;
|
|||||||
using Microsoft.AppCenter.Analytics;
|
using Microsoft.AppCenter.Analytics;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using YoutubeExplode;
|
using YoutubeExplode;
|
||||||
|
using YoutubeExplode.Models;
|
||||||
using Windows.UI.Popups;
|
using Windows.UI.Popups;
|
||||||
using YoutubeExplode.Models.MediaStreams;
|
|
||||||
using Windows.Foundation;
|
using Windows.Foundation;
|
||||||
using FoxTube.Pages;
|
using FoxTube.Pages;
|
||||||
using Windows.Networking.Connectivity;
|
using Windows.Networking.Connectivity;
|
||||||
using Microsoft.Toolkit.Uwp.UI.Controls;
|
using Microsoft.Toolkit.Uwp.UI.Controls;
|
||||||
|
using FoxTube.Classes;
|
||||||
|
using FoxTube.Controls.Common;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace FoxTube.Controls
|
namespace FoxTube.Controls
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Video item card
|
/// Video item card
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed partial class VideoCard : UserControl
|
public sealed partial class VideoCard : UserControl, ICard
|
||||||
{
|
{
|
||||||
ResourceLoader resources = ResourceLoader.GetForCurrentView("Cards");
|
ResourceLoader resources = ResourceLoader.GetForCurrentView("Cards");
|
||||||
|
|
||||||
public string playlistId;
|
readonly string playlistId;
|
||||||
|
readonly string id;
|
||||||
Video item;
|
Video item;
|
||||||
HistoryItem history;
|
HistoryItem history;
|
||||||
|
|
||||||
|
Google.Apis.YouTube.v3.Data.Video liveItem;
|
||||||
|
|
||||||
public VideoCard(string id, string playlist = null)
|
public VideoCard(string id, string playlist = null)
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
Initialize(id, playlist);
|
this.id = id;
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public VideoCard(Video meta, string playlist = null)
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
item = meta;
|
|
||||||
playlistId = playlist;
|
playlistId = playlist;
|
||||||
LoadMeta();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void Initialize(string id, string playlist = null)
|
public async Task Initialize()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
playlistId = playlist;
|
item = await new YoutubeClient(SecretsVault.HttpClient).GetVideoAsync(id);
|
||||||
delete.Visibility = string.IsNullOrWhiteSpace(playlistId) ? Visibility.Collapsed : Visibility.Visible;
|
|
||||||
|
|
||||||
VideosResource.ListRequest request = SecretsVault.Service.Videos.List("snippet,contentDetails,statistics,liveStreamingDetails");
|
title.Text = item.Title;
|
||||||
|
channelName.Text = item.Author;
|
||||||
|
|
||||||
|
ValidatePlaylist();
|
||||||
|
|
||||||
|
VideosResource.ListRequest request = SecretsVault.Service.Videos.List("liveStreamingDetails,contentDetails");
|
||||||
request.Id = id;
|
request.Id = id;
|
||||||
request.Hl = SettingsStorage.RelevanceLanguage;
|
liveItem = (await request.ExecuteAsync()).Items[0];
|
||||||
item = (await request.ExecuteAsync()).Items[0];
|
|
||||||
|
|
||||||
title.Text = item.Snippet.Localized.Title;
|
|
||||||
channelName.Text = item.Snippet.ChannelTitle;
|
|
||||||
|
|
||||||
if (item.Snippet.Title == "Deleted video")
|
if(liveItem.LiveStreamingDetails.ConcurrentViewers != null)
|
||||||
{
|
{
|
||||||
ContextFlyout = null;
|
if (liveItem.LiveStreamingDetails.ActualStartTime.HasValue)
|
||||||
show.Begin();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.Snippet.LiveBroadcastContent == "live")
|
|
||||||
{
|
{
|
||||||
views.Text = $"{item.LiveStreamingDetails.ConcurrentViewers:0,0} {resources.GetString("/Cards/viewers")}";
|
views.Text = $"{liveItem.LiveStreamingDetails.ConcurrentViewers:0,0} {resources.GetString("/Cards/viewers")}";
|
||||||
if (item.LiveStreamingDetails.ScheduledStartTime.HasValue && item.LiveStreamingDetails.ScheduledEndTime.HasValue)
|
if (liveItem.LiveStreamingDetails.ScheduledStartTime.HasValue && liveItem.LiveStreamingDetails.ScheduledEndTime.HasValue)
|
||||||
info.Text = $"{item.LiveStreamingDetails.ScheduledEndTime - item.LiveStreamingDetails.ActualStartTime} | {Methods.GetAgo(item.LiveStreamingDetails.ActualStartTime.Value)}";
|
info.Text = $"{liveItem.LiveStreamingDetails.ScheduledEndTime - liveItem.LiveStreamingDetails.ActualStartTime} | {Methods.GetAgo(liveItem.LiveStreamingDetails.ActualStartTime.Value)}";
|
||||||
else
|
else
|
||||||
info.Text = Methods.GetAgo(item.LiveStreamingDetails.ActualStartTime.Value);
|
info.Text = Methods.GetAgo(liveItem.LiveStreamingDetails.ActualStartTime.Value);
|
||||||
liveTag.Visibility = Visibility.Visible;
|
|
||||||
download.Visibility = Visibility.Collapsed;
|
|
||||||
}
|
}
|
||||||
else if (item.Snippet.LiveBroadcastContent == "upcoming")
|
else
|
||||||
{
|
{
|
||||||
views.Text = "";
|
views.Text = "";
|
||||||
if (item.LiveStreamingDetails.ScheduledStartTime.HasValue && item.LiveStreamingDetails.ScheduledEndTime.HasValue)
|
if (liveItem.LiveStreamingDetails.ScheduledStartTime.HasValue && liveItem.LiveStreamingDetails.ScheduledEndTime.HasValue)
|
||||||
info.Text = $"{item.LiveStreamingDetails.ScheduledEndTime - item.LiveStreamingDetails.ScheduledStartTime} | {item.LiveStreamingDetails.ScheduledStartTime}";
|
info.Text = $"{liveItem.LiveStreamingDetails.ScheduledEndTime - liveItem.LiveStreamingDetails.ScheduledStartTime} | {liveItem.LiveStreamingDetails.ScheduledStartTime}";
|
||||||
else
|
else
|
||||||
info.Text = $"{Methods.GetAgo(item.Snippet.PublishedAt.Value)}";
|
info.Text = Methods.GetAgo(item.UploadDate.DateTime);
|
||||||
liveTag.Visibility = Visibility.Visible;
|
|
||||||
|
|
||||||
if (item.LiveStreamingDetails.ScheduledStartTime.HasValue)
|
if (liveItem.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") + (liveItem.LiveStreamingDetails.ScheduledStartTime.Value > DateTime.Now ? " " : " -") + (liveItem.LiveStreamingDetails.ScheduledStartTime.Value - DateTime.Now).ToString(@"hh\:mm\:ss");
|
||||||
else liveContent.Text = resources.GetString("/Cards/upcoming");
|
else liveContent.Text = resources.GetString("/Cards/upcoming");
|
||||||
|
}
|
||||||
|
liveTag.Visibility = Visibility.Visible;
|
||||||
download.Visibility = Visibility.Collapsed;
|
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.Duration} | {item.UploadDate}";
|
||||||
LoadDownloads();
|
|
||||||
|
try { new DownloadSelector(download.Items).Initialize(item); }
|
||||||
|
catch { download.Visibility = Visibility.Collapsed; }
|
||||||
}
|
}
|
||||||
LoadAddTo();
|
|
||||||
|
try { new AddToPlaylist(addTo.Items).Initialize(id); }
|
||||||
|
catch { addTo.Visibility = Visibility.Collapsed; }
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
thumbnail.Source = new BitmapImage(item.Snippet.Thumbnails.Medium.Url.ToUri());
|
thumbnail.Source = new BitmapImage(item.Thumbnails.MediumResUrl.ToUri());
|
||||||
avatar.ProfilePicture = new BitmapImage((await new YoutubeClient().GetChannelAsync(item.Snippet.ChannelId)).LogoUrl.ToUri()) { DecodePixelWidth = 46, DecodePixelHeight = 46 };
|
avatar.ProfilePicture = new BitmapImage((await new YoutubeClient(SecretsVault.HttpClient).GetVideoAuthorChannelAsync(id)).LogoUrl.ToUri()) { DecodePixelHeight = 46, DecodePixelWidth = 46 };
|
||||||
}
|
}
|
||||||
catch { }
|
catch { }
|
||||||
|
|
||||||
if (SecretsVault.History.Contains(item.Id))
|
if (SecretsVault.History.Videos.Any(i => i.Id == id))
|
||||||
watched.Visibility = Visibility.Visible;
|
watched.Visibility = Visibility.Visible;
|
||||||
if (HistorySet.Items.Exists(i => i.Id == item.Id))
|
if (HistorySet.Items.Exists(i => i.Id == item.Id))
|
||||||
{
|
{
|
||||||
history = HistorySet.Items.Find(i => i.Id == item.Id);
|
history = HistorySet.Items.Find(i => i.Id == item.Id);
|
||||||
watched.Visibility = Visibility.Visible;
|
watched.Visibility = Visibility.Visible;
|
||||||
leftOn.Value = 100 * HistorySet.Items.Find(i => i.Id == item.Id).LeftOn.TotalSeconds / Methods.GetDuration(item.ContentDetails.Duration).TotalSeconds;
|
leftOn.Value = 100 * history.LeftOn.TotalSeconds / item.Duration.TotalSeconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
show.Begin();
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@@ -133,95 +128,30 @@ namespace FoxTube.Controls
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async void LoadDownloads()
|
async void ValidatePlaylist()
|
||||||
{
|
{
|
||||||
try
|
if (string.IsNullOrWhiteSpace(playlistId) || !SecretsVault.IsAuthorized)
|
||||||
{
|
|
||||||
MediaStreamInfoSet infoSet = await new YoutubeClient().GetVideoMediaStreamInfosAsync(item.Id);
|
|
||||||
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()
|
|
||||||
{
|
|
||||||
title.Text = item.Snippet.Title;
|
|
||||||
channelName.Text = item.Snippet.ChannelTitle;
|
|
||||||
|
|
||||||
if (item.Snippet.Title == "Deleted video")
|
|
||||||
{
|
|
||||||
ContextFlyout = null;
|
|
||||||
show.Begin();
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
if (item.Snippet.LiveBroadcastContent == "live")
|
if (playlistId == "WL" || playlistId == SecretsVault.UserChannel.ContentDetails.RelatedPlaylists.Likes)
|
||||||
{
|
delete.Visibility = Visibility.Visible;
|
||||||
views.Text = $"{item.LiveStreamingDetails.ConcurrentViewers:0,0} {resources.GetString("/Cards/viewers")}";
|
|
||||||
if (item.LiveStreamingDetails.ScheduledStartTime.HasValue && item.LiveStreamingDetails.ScheduledEndTime.HasValue)
|
|
||||||
info.Text = $"{item.LiveStreamingDetails.ScheduledEndTime - item.LiveStreamingDetails.ActualStartTime} | {Methods.GetAgo(item.LiveStreamingDetails.ActualStartTime.Value)}";
|
|
||||||
else
|
|
||||||
info.Text = Methods.GetAgo(item.LiveStreamingDetails.ActualStartTime.Value);
|
|
||||||
liveTag.Visibility = Visibility.Visible;
|
|
||||||
}
|
|
||||||
else if (item.Snippet.LiveBroadcastContent == "upcoming")
|
|
||||||
{
|
|
||||||
views.Text = "";
|
|
||||||
if (item.LiveStreamingDetails.ScheduledStartTime.HasValue && item.LiveStreamingDetails.ScheduledEndTime.HasValue)
|
|
||||||
info.Text = $"{item.LiveStreamingDetails.ScheduledEndTime - item.LiveStreamingDetails.ScheduledStartTime} | {item.LiveStreamingDetails.ScheduledStartTime}";
|
|
||||||
else
|
|
||||||
info.Text = $"{Methods.GetAgo(item.Snippet.PublishedAt.Value)}";
|
|
||||||
liveTag.Visibility = Visibility.Visible;
|
|
||||||
|
|
||||||
if (item.LiveStreamingDetails.ScheduledStartTime.HasValue)
|
|
||||||
liveContent.Text = $"{resources.GetString("/Cards/goesLive")} {item.LiveStreamingDetails.ScheduledStartTime - DateTime.Now}";
|
|
||||||
else liveContent.Text = resources.GetString("/Cards/upcoming");
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
views.Text = $"{item.Statistics.ViewCount:0,0} {resources.GetString("/Cards/views")}";
|
PlaylistsResource.ListRequest playlistRequest = SecretsVault.Service.Playlists.List("snippet");
|
||||||
info.Text = $"{item.ContentDetails.Duration.GetDuration()} | {Methods.GetAgo(item.Snippet.PublishedAt.Value)}";
|
playlistRequest.Id = playlistId;
|
||||||
|
var response = await playlistRequest.ExecuteAsync();
|
||||||
|
|
||||||
|
if (response.Items[0].Snippet.ChannelId == SecretsVault.AccountId)
|
||||||
|
delete.Visibility = Visibility.Visible;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
thumbnail.Source = new BitmapImage(item.Snippet.Thumbnails.Medium.Url.ToUri());
|
public void ItemClicked() =>
|
||||||
avatar.ProfilePicture = new BitmapImage((await new YoutubeClient().GetChannelAsync(item.Snippet.ChannelId)).LogoUrl.ToUri()) { DecodePixelHeight = 50, DecodePixelWidth = 50 };
|
ItemClicked(false);
|
||||||
|
|
||||||
if (SecretsVault.History.Contains(item.Id))
|
async void ItemClicked(bool incognito = false)
|
||||||
watched.Visibility = Visibility.Visible;
|
|
||||||
if (HistorySet.Items.Exists(i => i.Id == item.Id))
|
|
||||||
leftOn.Value = 100 * HistorySet.Items.Find(i => i.Id == item.Id).LeftOn.TotalSeconds / Methods.GetDuration(item.ContentDetails.Duration).TotalSeconds;
|
|
||||||
|
|
||||||
show.Begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async void Button_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
{
|
||||||
if (item.ContentDetails.ContentRating != null)
|
if (liveItem.ContentDetails.ContentRating != null)
|
||||||
{
|
{
|
||||||
if (SecretsVault.IsAuthorized)
|
if (SecretsVault.IsAuthorized)
|
||||||
{
|
{
|
||||||
@@ -268,11 +198,11 @@ namespace FoxTube.Controls
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
PlaylistItem playlistItem = new PlaylistItem()
|
Google.Apis.YouTube.v3.Data.PlaylistItem playlistItem = new Google.Apis.YouTube.v3.Data.PlaylistItem
|
||||||
{
|
{
|
||||||
Snippet = new PlaylistItemSnippet()
|
Snippet = new Google.Apis.YouTube.v3.Data.PlaylistItemSnippet
|
||||||
{
|
{
|
||||||
ResourceId = new ResourceId()
|
ResourceId = new Google.Apis.YouTube.v3.Data.ResourceId
|
||||||
{
|
{
|
||||||
Kind = "youtube#video",
|
Kind = "youtube#video",
|
||||||
VideoId = item.Id
|
VideoId = item.Id
|
||||||
@@ -290,251 +220,37 @@ namespace FoxTube.Controls
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Methods.MainPage.GoToVideo(item.Id, playlistId == "HL" ? null : playlistId, ((FrameworkElement)sender).Name == "incognito" ? true : false);
|
Navigation.GoToVideo(id, playlistId == "HL" ? null : playlistId, incognito);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Share(DataTransferManager sender, DataRequestedEventArgs args)
|
void Share(DataTransferManager sender, DataRequestedEventArgs args) =>
|
||||||
{
|
|
||||||
Methods.Share(args,
|
Methods.Share(args,
|
||||||
item.Snippet.Thumbnails.Medium.Url,
|
item.Thumbnails.MediumResUrl,
|
||||||
item.Snippet.Title,
|
item.Title,
|
||||||
$"https://www.youtube.com/watch?v={item.Id}",
|
item.GetShortUrl(),
|
||||||
resources.GetString("/Cards/videoShare"));
|
resources.GetString("/Cards/videoShare"));
|
||||||
}
|
|
||||||
|
|
||||||
private void share_Click(object sender, RoutedEventArgs e)
|
void share_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
DataTransferManager.GetForCurrentView().DataRequested += new TypedEventHandler<DataTransferManager, DataRequestedEventArgs>(Share);
|
DataTransferManager.GetForCurrentView().DataRequested += new TypedEventHandler<DataTransferManager, DataRequestedEventArgs>(Share);
|
||||||
DataTransferManager.ShowShareUI();
|
DataTransferManager.ShowShareUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ViewChannel_Click(object sender, RoutedEventArgs e)
|
async void ViewChannel_Click(object sender, RoutedEventArgs e) =>
|
||||||
{
|
Navigation.GoToChannel((await new YoutubeClient(SecretsVault.HttpClient).GetVideoAuthorChannelAsync(id)).Id);
|
||||||
Methods.MainPage.GoToChannel(item.Snippet.ChannelId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void GetLink_Click(object sender, RoutedEventArgs e)
|
void GetLink_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
DataPackage data = new DataPackage();
|
DataPackage data = new DataPackage();
|
||||||
data.SetText($"https://www.youtube.com/watch?v={item.Id}");
|
data.SetText(item.GetShortUrl());
|
||||||
Clipboard.SetContent(data);
|
Clipboard.SetContent(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void InBrowser_Click(object sender, RoutedEventArgs e)
|
async void InBrowser_Click(object sender, RoutedEventArgs e) =>
|
||||||
{
|
await Launcher.LaunchUriAsync(item.GetShortUrl().ToUri());
|
||||||
await Launcher.LaunchUriAsync($"https://www.youtube.com/watch?v={item.Id}".ToUri());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Thumbnail_ImageOpened(object sender, RoutedEventArgs e)
|
void Thumbnail_ImageOpened(object sender, RoutedEventArgs e) =>
|
||||||
{
|
show.Begin();
|
||||||
showThumb.Begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void NewPlaylist_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
StackPanel stack = new StackPanel();
|
|
||||||
stack.Children.Add(new TextBox
|
|
||||||
{
|
|
||||||
PlaceholderText = resources.GetString("/VideoPage/newPlaylistName/PlaceholderText")
|
|
||||||
});
|
|
||||||
|
|
||||||
ComboBox comboBox = new ComboBox
|
|
||||||
{
|
|
||||||
Header = resources.GetString("/VideoPage/privacy/Header"),
|
|
||||||
SelectedIndex = 0,
|
|
||||||
HorizontalAlignment = HorizontalAlignment.Stretch
|
|
||||||
};
|
|
||||||
comboBox.Items.Add(new ComboBoxItem { Content = resources.GetString("/VideoPage/public/Content") });
|
|
||||||
comboBox.Items.Add(new ComboBoxItem { Content = resources.GetString("/VideoPage/private/Content") });
|
|
||||||
comboBox.Items.Add(new ComboBoxItem { Content = resources.GetString("/VideoPage/direct/Content") });
|
|
||||||
|
|
||||||
stack.Children.Add(comboBox);
|
|
||||||
|
|
||||||
ContentDialog playlistDialog = new ContentDialog
|
|
||||||
{
|
|
||||||
PrimaryButtonText = resources.GetString("/VideoPage/dialog/PrimaryButtonText"),
|
|
||||||
CloseButtonText = resources.GetString("/VideoPage/dialog/CloseButtonText"),
|
|
||||||
DefaultButton = ContentDialogButton.Primary,
|
|
||||||
Title = resources.GetString("/VideoPage/dialog/Title"),
|
|
||||||
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 async void Wl_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
if (wl.IsChecked)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
PlaylistItem playlist = new PlaylistItem
|
|
||||||
{
|
|
||||||
Snippet = new PlaylistItemSnippet
|
|
||||||
{
|
|
||||||
PlaylistId = "WL",
|
|
||||||
ResourceId = new ResourceId
|
|
||||||
{
|
|
||||||
VideoId = item.Id,
|
|
||||||
Kind = "youtube#video"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
PlaylistItemsResource.InsertRequest request = SecretsVault.Service.PlaylistItems.Insert(playlist, "snippet");
|
|
||||||
|
|
||||||
await request.ExecuteAsync();
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
wl.IsChecked = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
wl.IsChecked = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
async void LoadAddTo()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
addTo.Visibility = Visibility.Collapsed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void Delete_Click(object sender, RoutedEventArgs e)
|
private async void Delete_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
@@ -550,7 +266,7 @@ namespace FoxTube.Controls
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
HistorySet.Delete(history);
|
HistorySet.Delete(history);
|
||||||
(Methods.MainPage.PageContent.Frame.Content as History).Delete(this);
|
(Navigation.Frame.Frame.Content as History).Delete(this);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -559,23 +275,15 @@ namespace FoxTube.Controls
|
|||||||
PlaylistItemsResource.ListRequest request = SecretsVault.Service.PlaylistItems.List("snippet");
|
PlaylistItemsResource.ListRequest request = SecretsVault.Service.PlaylistItems.List("snippet");
|
||||||
request.PlaylistId = playlistId;
|
request.PlaylistId = playlistId;
|
||||||
request.VideoId = item.Id;
|
request.VideoId = item.Id;
|
||||||
PlaylistItemListResponse response = await request.ExecuteAsync();
|
|
||||||
|
|
||||||
PlaylistItem playlistItem = response.Items.Find(i => i.Snippet.PlaylistId == playlistId);
|
await SecretsVault.Service.PlaylistItems.Delete((await request.ExecuteAsync()).Items[0].Id).ExecuteAsync();
|
||||||
|
|
||||||
await SecretsVault.Service.PlaylistItems.Delete(playlistItem.Id).ExecuteAsync();
|
|
||||||
|
|
||||||
(Methods.MainPage.PageContent.Frame.Content as PlaylistPage).DeleteItem(this);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
|
|
||||||
|
(Navigation.Frame.Frame.Content as PlaylistPage).DeleteItem(this);
|
||||||
}
|
}
|
||||||
|
catch { }
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Card_SizeChanged(object sender, SizeChangedEventArgs e)
|
private void Button_Click(object sender, RoutedEventArgs e) =>
|
||||||
{
|
ItemClicked(((FrameworkElement)sender).Name == "incognito" ? true : false);
|
||||||
Height = e.NewSize.Width * 0.75;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
<UserControl
|
<UserControl
|
||||||
x:Class="FoxTube.Controls.Chat"
|
x:Class="FoxTube.Controls.VideoPage.Chat"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:controls="using:FoxTube.Controls"
|
xmlns:controls="using:FoxTube.Controls.VideoPage"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="600"
|
d:DesignHeight="600"
|
||||||
d:DesignWidth="400">
|
d:DesignWidth="400">
|
||||||
@@ -10,10 +10,11 @@ using System.Collections.Generic;
|
|||||||
using Windows.UI.Popups;
|
using Windows.UI.Popups;
|
||||||
using Windows.ApplicationModel.Resources;
|
using Windows.ApplicationModel.Resources;
|
||||||
using Microsoft.Advertising.WinRT.UI;
|
using Microsoft.Advertising.WinRT.UI;
|
||||||
using Windows.UI.Xaml.Media.Imaging;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using FoxTube.Classes;
|
||||||
|
using FoxTube.Controls.Adverts;
|
||||||
|
|
||||||
namespace FoxTube.Controls
|
namespace FoxTube.Controls.VideoPage
|
||||||
{
|
{
|
||||||
public class ChatMessage
|
public class ChatMessage
|
||||||
{
|
{
|
||||||
@@ -63,16 +64,12 @@ namespace FoxTube.Controls
|
|||||||
|
|
||||||
private LiveChatMessage message;
|
private LiveChatMessage message;
|
||||||
|
|
||||||
public ChatMessage(LiveChatMessage item)
|
public ChatMessage(LiveChatMessage item) =>
|
||||||
{
|
|
||||||
message = item;
|
message = item;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public sealed partial class Chat : UserControl
|
public sealed partial class Chat : UserControl
|
||||||
{
|
{
|
||||||
NativeAdsManagerV2 manager = new NativeAdsManagerV2(SecretsVault.AppId, SecretsVault.AdUnitId);
|
|
||||||
public NativeAdV2 advert;
|
|
||||||
string chatId;
|
string chatId;
|
||||||
DateTime lastInsert;
|
DateTime lastInsert;
|
||||||
|
|
||||||
@@ -81,7 +78,7 @@ namespace FoxTube.Controls
|
|||||||
|
|
||||||
DispatcherTimer timer = new DispatcherTimer
|
DispatcherTimer timer = new DispatcherTimer
|
||||||
{
|
{
|
||||||
Interval = TimeSpan.FromSeconds(1)
|
Interval = TimeSpan.FromSeconds(3)
|
||||||
};
|
};
|
||||||
|
|
||||||
DispatcherTimer adTimer = new DispatcherTimer
|
DispatcherTimer adTimer = new DispatcherTimer
|
||||||
@@ -104,130 +101,8 @@ namespace FoxTube.Controls
|
|||||||
if (SecretsVault.AdsDisabled)
|
if (SecretsVault.AdsDisabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
adTimer.Tick += (s, e) => manager.RequestAd();
|
adTimer.Tick += (s, e) => list.Items.Add(new ChatAdvert());
|
||||||
adTimer.Start();
|
adTimer.Start();
|
||||||
|
|
||||||
manager.AdReady += AdReady;
|
|
||||||
manager.ErrorOccurred += ErrorOccurred;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ErrorOccurred(object sender, NativeAdErrorEventArgs e)
|
|
||||||
{
|
|
||||||
System.Diagnostics.Debug.WriteLine("Error has occured while loading ad");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AdReady(object sender, NativeAdReadyEventArgs e)
|
|
||||||
{
|
|
||||||
advert = e.NativeAd;
|
|
||||||
|
|
||||||
Grid grid = new Grid
|
|
||||||
{
|
|
||||||
Margin = new Thickness(0, 5, 5, 5),
|
|
||||||
};
|
|
||||||
|
|
||||||
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Auto) });
|
|
||||||
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Auto) });
|
|
||||||
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
|
|
||||||
|
|
||||||
StackPanel iconStack = new StackPanel
|
|
||||||
{
|
|
||||||
Orientation = Orientation.Horizontal,
|
|
||||||
VerticalAlignment = VerticalAlignment.Top,
|
|
||||||
Margin = new Thickness(5, 0, 5, 0)
|
|
||||||
};
|
|
||||||
|
|
||||||
iconStack.Children.Add(new PersonPicture
|
|
||||||
{
|
|
||||||
Height = 20,
|
|
||||||
ProfilePicture = advert.AdIcon == null ? null : advert.AdIcon.Source
|
|
||||||
});
|
|
||||||
FontIcon sponsor = new FontIcon
|
|
||||||
{
|
|
||||||
Glyph = "\xE735",
|
|
||||||
Margin = new Thickness(2, 0, 2, 0)
|
|
||||||
};
|
|
||||||
ToolTipService.SetToolTip(sponsor, ResourceLoader.GetForCurrentView("Chat").GetString("/Chat/sponsor/Text"));
|
|
||||||
iconStack.Children.Add(sponsor);
|
|
||||||
|
|
||||||
StackPanel nameStack = new StackPanel
|
|
||||||
{
|
|
||||||
Orientation = Orientation.Horizontal,
|
|
||||||
VerticalAlignment = VerticalAlignment.Top,
|
|
||||||
Margin = new Thickness(0, 0, 2, 0)
|
|
||||||
};
|
|
||||||
Grid.SetColumn(nameStack, 1);
|
|
||||||
HyperlinkButton sponsorName = new HyperlinkButton
|
|
||||||
{
|
|
||||||
Margin = new Thickness(0, -6, 0, 0),
|
|
||||||
FontWeight = Windows.UI.Text.FontWeights.Bold,
|
|
||||||
Content = new TextBlock
|
|
||||||
{
|
|
||||||
TextTrimming = TextTrimming.CharacterEllipsis,
|
|
||||||
MaxWidth = 150,
|
|
||||||
Text = Methods.GuardFromNull(advert.SponsoredBy)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
ToolTipService.SetToolTip(sponsorName, Methods.GuardFromNull(advert.SponsoredBy));
|
|
||||||
nameStack.Children.Add(sponsorName);
|
|
||||||
nameStack.Children.Add(new TextBlock { Text = ":" });
|
|
||||||
|
|
||||||
StackPanel contentStack = new StackPanel
|
|
||||||
{
|
|
||||||
Padding = new Thickness(2, 0, 0, 0)
|
|
||||||
};
|
|
||||||
Grid.SetColumn(contentStack, 2);
|
|
||||||
contentStack.Children.Add(new TextBlock
|
|
||||||
{
|
|
||||||
VerticalAlignment = VerticalAlignment.Top,
|
|
||||||
TextWrapping = TextWrapping.WrapWholeWords,
|
|
||||||
FontWeight = Windows.UI.Text.FontWeights.Bold,
|
|
||||||
Text = advert.Title
|
|
||||||
});
|
|
||||||
if(!string.IsNullOrWhiteSpace(advert.Description))
|
|
||||||
contentStack.Children.Add(new TextBlock
|
|
||||||
{
|
|
||||||
VerticalAlignment = VerticalAlignment.Top,
|
|
||||||
TextWrapping = TextWrapping.WrapWholeWords,
|
|
||||||
Text = advert.Description
|
|
||||||
});
|
|
||||||
if (!string.IsNullOrWhiteSpace(advert.CallToActionText))
|
|
||||||
contentStack.Children.Add(new HyperlinkButton
|
|
||||||
{
|
|
||||||
VerticalAlignment = VerticalAlignment.Top,
|
|
||||||
Content = new TextBlock
|
|
||||||
{
|
|
||||||
TextWrapping = TextWrapping.WrapWholeWords,
|
|
||||||
Text = advert.CallToActionText
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
grid.Children.Add(iconStack);
|
|
||||||
grid.Children.Add(nameStack);
|
|
||||||
grid.Children.Add(contentStack);
|
|
||||||
|
|
||||||
Grid mainGrid = new Grid();
|
|
||||||
mainGrid.Children.Add(new Border
|
|
||||||
{
|
|
||||||
BorderBrush = new SolidColorBrush(Colors.Red),
|
|
||||||
BorderThickness = new Thickness(2),
|
|
||||||
CornerRadius = new CornerRadius(5),
|
|
||||||
HorizontalAlignment = HorizontalAlignment.Stretch,
|
|
||||||
Margin = new Thickness(0, 27, 0, 2),
|
|
||||||
Background = new SolidColorBrush(Colors.Red) { Opacity = .2 },
|
|
||||||
Child = grid
|
|
||||||
});
|
|
||||||
|
|
||||||
ListViewItem item = new ListViewItem
|
|
||||||
{
|
|
||||||
Content = mainGrid
|
|
||||||
};
|
|
||||||
|
|
||||||
list.Items.Insert(0, item);
|
|
||||||
|
|
||||||
if (contentStack.Children.Last() is HyperlinkButton)
|
|
||||||
advert.RegisterAdContainer(mainGrid, new List<FrameworkElement> { contentStack.Children.Last() as HyperlinkButton });
|
|
||||||
else
|
|
||||||
advert.RegisterAdContainer(mainGrid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void Update(object sender, object e)
|
public async void Update(object sender, object e)
|
||||||
@@ -241,10 +116,8 @@ namespace FoxTube.Controls
|
|||||||
timer.Start();
|
timer.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HyperlinkButton_Click(object sender, RoutedEventArgs e)
|
private void HyperlinkButton_Click(object sender, RoutedEventArgs e) =>
|
||||||
{
|
Navigation.GoToChannel(((HyperlinkButton)sender).Tag as string);
|
||||||
Methods.MainPage.GoToChannel(((HyperlinkButton)sender).Tag as string);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void send_Click(object sender, RoutedEventArgs args)
|
private async void send_Click(object sender, RoutedEventArgs args)
|
||||||
{
|
{
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<Page
|
<UserControl
|
||||||
x:Class="FoxTube.Pages.CommentsPage"
|
x:Class="FoxTube.Controls.VideoPage.Comments"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
@@ -50,4 +50,4 @@
|
|||||||
</StackPanel>
|
</StackPanel>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Page>
|
</UserControl>
|
||||||
@@ -9,12 +9,12 @@ using Windows.ApplicationModel.Resources;
|
|||||||
using Microsoft.AppCenter.Analytics;
|
using Microsoft.AppCenter.Analytics;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace FoxTube.Pages
|
namespace FoxTube.Controls.VideoPage
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Comments placeholder
|
/// Comments placeholder
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed partial class CommentsPage : Page
|
public sealed partial class Comments : UserControl
|
||||||
{
|
{
|
||||||
ResourceLoader resources = ResourceLoader.GetForCurrentView("CommentsPage");
|
ResourceLoader resources = ResourceLoader.GetForCurrentView("CommentsPage");
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ namespace FoxTube.Pages
|
|||||||
CommentThreadsResource.ListRequest.OrderEnum order = CommentThreadsResource.ListRequest.OrderEnum.Relevance;
|
CommentThreadsResource.ListRequest.OrderEnum order = CommentThreadsResource.ListRequest.OrderEnum.Relevance;
|
||||||
CommentThreadsResource.ListRequest request;
|
CommentThreadsResource.ListRequest request;
|
||||||
|
|
||||||
public CommentsPage()
|
public Comments()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
<UserControl
|
||||||
|
x:Class="FoxTube.Controls.VideoPage.RelatedVideos"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:local="using:FoxTube.Controls.VideoPage"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:pages="using:FoxTube.Pages"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
d:DesignWidth="400">
|
||||||
|
|
||||||
|
<ScrollViewer>
|
||||||
|
<pages:VideoGrid x:Name="list"/>
|
||||||
|
</ScrollViewer>
|
||||||
|
</UserControl>
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
using Google.Apis.YouTube.v3;
|
||||||
|
using Google.Apis.YouTube.v3.Data;
|
||||||
|
using Windows.UI.Xaml.Controls;
|
||||||
|
|
||||||
|
namespace FoxTube.Controls.VideoPage
|
||||||
|
{
|
||||||
|
public sealed partial class RelatedVideos : UserControl
|
||||||
|
{
|
||||||
|
public RelatedVideos() =>
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
public async void Initialize(string id)
|
||||||
|
{
|
||||||
|
list.Clear();
|
||||||
|
|
||||||
|
SearchResource.ListRequest request = SecretsVault.Service.Search.List("id");
|
||||||
|
request.RegionCode = SettingsStorage.Region;
|
||||||
|
request.RelevanceLanguage = SettingsStorage.RelevanceLanguage;
|
||||||
|
request.RelatedToVideoId = id;
|
||||||
|
request.SafeSearch = (SearchResource.ListRequest.SafeSearchEnum)SettingsStorage.SafeSearch;
|
||||||
|
request.MaxResults = 10;
|
||||||
|
request.Type = "video";
|
||||||
|
|
||||||
|
SearchListResponse response = await request.ExecuteAsync();
|
||||||
|
|
||||||
|
foreach (SearchResult video in response.Items)
|
||||||
|
list.Add(new VideoCard(video.Id.VideoId));
|
||||||
|
|
||||||
|
list.Children.Insert(1, new Adverts.CardAdvert());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OpenNext() =>
|
||||||
|
(list.Children[0] as VideoCard).ItemClicked();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
<UserControl
|
||||||
|
x:Class="FoxTube.Controls.VideoPage.VideoPlaylist"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
d:DesignWidth="400">
|
||||||
|
|
||||||
|
<ScrollViewer x:Name="scroll">
|
||||||
|
<StackPanel>
|
||||||
|
<StackPanel Padding="8" Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}">
|
||||||
|
<TextBlock Text="[Playlsit name]" FontSize="26" TextWrapping="WrapWholeWords" Name="playlistName"/>
|
||||||
|
<TextBlock Text="[Channel name]" Name="playlistChannel"/>
|
||||||
|
<TextBlock Text="[Counter]" Name="playlistCounter"/>
|
||||||
|
</StackPanel>
|
||||||
|
<ListBox Background="Transparent" Name="list">
|
||||||
|
<ListBox.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="auto"/>
|
||||||
|
<ColumnDefinition Width="auto"/>
|
||||||
|
<ColumnDefinition/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<TextBlock Text="{Binding Path=Number}" VerticalAlignment="Center" Margin="0,0,8,0"/>
|
||||||
|
<Image Grid.Column="1" Source="{Binding Path=Thumbnail}" Height="65"/>
|
||||||
|
<TextBlock Grid.Column="2" Margin="8,0,0,0" VerticalAlignment="Center" TextWrapping="WrapWholeWords" Text="{Binding Path=Title}"/>
|
||||||
|
</Grid>
|
||||||
|
</DataTemplate>
|
||||||
|
</ListBox.ItemTemplate>
|
||||||
|
</ListBox>
|
||||||
|
</StackPanel>
|
||||||
|
</ScrollViewer>
|
||||||
|
</UserControl>
|
||||||
@@ -0,0 +1,124 @@
|
|||||||
|
using FoxTube.Classes;
|
||||||
|
using Google.Apis.YouTube.v3;
|
||||||
|
using Google.Apis.YouTube.v3.Data;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Windows.ApplicationModel.Resources;
|
||||||
|
using Windows.UI.Xaml.Controls;
|
||||||
|
|
||||||
|
// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236
|
||||||
|
|
||||||
|
namespace FoxTube.Controls.VideoPage
|
||||||
|
{
|
||||||
|
public sealed partial class VideoPlaylist : UserControl
|
||||||
|
{
|
||||||
|
public class PlaylistItem
|
||||||
|
{
|
||||||
|
public int Number { get; }
|
||||||
|
public string Id { get; }
|
||||||
|
public string Title { get; }
|
||||||
|
public string Thumbnail { get; }
|
||||||
|
|
||||||
|
public PlaylistItem(int number, Google.Apis.YouTube.v3.Data.PlaylistItem item)
|
||||||
|
{
|
||||||
|
Number = number;
|
||||||
|
Id = item.Snippet.ResourceId.VideoId;
|
||||||
|
Title = item.Snippet.Title;
|
||||||
|
Thumbnail = item.Snippet.Thumbnails.Medium.Url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlaylistItem(int number, Video item)
|
||||||
|
{
|
||||||
|
Number = number;
|
||||||
|
Id = item.Id;
|
||||||
|
Title = item.Snippet.Title;
|
||||||
|
Thumbnail = item.Snippet.Thumbnails.Medium.Url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ResourceLoader resources = ResourceLoader.GetForCurrentView("VideoPage");
|
||||||
|
public event PlaylistItemChangedEventHandler ItemChanged;
|
||||||
|
|
||||||
|
public VideoPlaylist() =>
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
public ItemCollection Items => list.Items;
|
||||||
|
public int SelectedIndex => list.SelectedIndex;
|
||||||
|
|
||||||
|
public async Task Initialize(Video video, string playlist)
|
||||||
|
{
|
||||||
|
if (video.Id == "WL")
|
||||||
|
{
|
||||||
|
List<Video> items = new List<Video>();
|
||||||
|
SecretsVault.WatchLater = await Methods.GetLater();
|
||||||
|
|
||||||
|
/*if (SecretsVault.WatchLater.Count > 100)
|
||||||
|
throw new Exception("Too large playlist");*/
|
||||||
|
|
||||||
|
/*foreach (string i in SecretsVault.WatchLater)
|
||||||
|
{
|
||||||
|
VideosResource.ListRequest request = SecretsVault.Service.Videos.List("snippet");
|
||||||
|
request.Id = i;
|
||||||
|
items.Add((await request.ExecuteAsync()).Items[0]);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
for (int k = 1; k <= items.Count; k++)
|
||||||
|
list.Items.Add(new PlaylistItem(k, items[k - 1]));
|
||||||
|
|
||||||
|
playlistName.Text = resources.GetString("/Main/later/Content");
|
||||||
|
playlistChannel.Text = SecretsVault.UserChannel.Snippet.Title;
|
||||||
|
|
||||||
|
list.SelectedItem = list.Items.Find(i => ((PlaylistItem)i).Id == video.Id);
|
||||||
|
//playlistCounter.Text = $"{list.SelectedIndex + 1}/{SecretsVault.WatchLater.Count}";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//Retrieving data
|
||||||
|
PlaylistsResource.ListRequest playlistRequest = SecretsVault.Service.Playlists.List("snippet,contentDetails");
|
||||||
|
playlistRequest.Id = playlist;
|
||||||
|
playlistRequest.Hl = SettingsStorage.RelevanceLanguage;
|
||||||
|
Playlist playlistItem = (await playlistRequest.ExecuteAsync()).Items[0];
|
||||||
|
|
||||||
|
if (playlistItem.ContentDetails.ItemCount > 100)
|
||||||
|
throw new Exception("Too large playlist");
|
||||||
|
|
||||||
|
PlaylistItemsResource.ListRequest listRequest = SecretsVault.Service.PlaylistItems.List("snippet");
|
||||||
|
listRequest.MaxResults = 50;
|
||||||
|
listRequest.PlaylistId = playlist;
|
||||||
|
|
||||||
|
PlaylistItemListResponse listResponse;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
listResponse = await listRequest.ExecuteAsync();
|
||||||
|
listRequest.PageToken = listResponse.NextPageToken;
|
||||||
|
|
||||||
|
foreach (Google.Apis.YouTube.v3.Data.PlaylistItem i in listResponse.Items)
|
||||||
|
list.Items.Add(new PlaylistItem((int)i.Snippet.Position + 1, i));
|
||||||
|
}
|
||||||
|
while (!string.IsNullOrWhiteSpace(listRequest.PageToken));
|
||||||
|
|
||||||
|
//Setting data
|
||||||
|
playlistName.Text = playlistItem.Snippet.Localized.Title;
|
||||||
|
playlistChannel.Text = Methods.GuardFromNull(playlistItem.Snippet.ChannelTitle);
|
||||||
|
|
||||||
|
list.SelectedItem = list.Items.Find(i => ((PlaylistItem)i).Id == video.Id);
|
||||||
|
playlistCounter.Text = $"{list.SelectedIndex + 1}/{playlistItem.ContentDetails.ItemCount}";
|
||||||
|
}
|
||||||
|
|
||||||
|
list.SelectionChanged += ListBox_SelectionChanged;
|
||||||
|
|
||||||
|
await Task.Delay(500);
|
||||||
|
|
||||||
|
scroll.ChangeView(null, list.SelectedIndex * 86 + 89, null, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e) =>
|
||||||
|
ItemChanged.Invoke((e.AddedItems[0] as PlaylistItem).Id);
|
||||||
|
|
||||||
|
public void Next() =>
|
||||||
|
list.SelectedIndex++;
|
||||||
|
public void Previous() =>
|
||||||
|
list.SelectedIndex--;
|
||||||
|
}
|
||||||
|
}
|
||||||
+57
-12
@@ -2,6 +2,7 @@
|
|||||||
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
<LangVersion>8.0</LangVersion>
|
||||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
|
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
|
||||||
<ProjectGuid>{2597B816-7316-4D20-BA6C-D78001E89C1A}</ProjectGuid>
|
<ProjectGuid>{2597B816-7316-4D20-BA6C-D78001E89C1A}</ProjectGuid>
|
||||||
@@ -83,6 +84,7 @@
|
|||||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<Prefer32Bit>true</Prefer32Bit>
|
<Prefer32Bit>true</Prefer32Bit>
|
||||||
|
<LangVersion>default</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||||
<OutputPath>bin\x64\Release\</OutputPath>
|
<OutputPath>bin\x64\Release\</OutputPath>
|
||||||
@@ -104,15 +106,27 @@
|
|||||||
<DependentUpon>App.xaml</DependentUpon>
|
<DependentUpon>App.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Classes\AdaptiveCommandBar.cs" />
|
<Compile Include="Classes\AdaptiveCommandBar.cs" />
|
||||||
|
<Compile Include="Classes\Extensions.cs" />
|
||||||
<Compile Include="Classes\HistorySet.cs" />
|
<Compile Include="Classes\HistorySet.cs" />
|
||||||
<Compile Include="Classes\InboxItem.cs" />
|
<Compile Include="Classes\InboxItem.cs" />
|
||||||
<Compile Include="Classes\Methods.cs" />
|
<Compile Include="Classes\Methods.cs" />
|
||||||
|
<Compile Include="Classes\Navigation.cs" />
|
||||||
|
<Compile Include="Classes\Processes.cs" />
|
||||||
|
<Compile Include="Classes\QualityComparer.cs" />
|
||||||
<Compile Include="Classes\SearchParameters.cs" />
|
<Compile Include="Classes\SearchParameters.cs" />
|
||||||
<Compile Include="Classes\SettingsStorage.cs" />
|
<Compile Include="Classes\SettingsStorage.cs" />
|
||||||
<Compile Include="Classes\ManifestGenerator.cs" />
|
<Compile Include="Classes\ManifestGenerator.cs" />
|
||||||
|
<Compile Include="Classes\StreamInfo.cs" />
|
||||||
|
<Compile Include="Controls\Common\AccountManager.xaml.cs">
|
||||||
|
<DependentUpon>AccountManager.xaml</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Controls\Common\AddToPlaylist.cs" />
|
||||||
<Compile Include="Controls\Adverts\CardAdvert.xaml.cs">
|
<Compile Include="Controls\Adverts\CardAdvert.xaml.cs">
|
||||||
<DependentUpon>CardAdvert.xaml</DependentUpon>
|
<DependentUpon>CardAdvert.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="Controls\Adverts\ChatAdvert.xaml.cs">
|
||||||
|
<DependentUpon>ChatAdvert.xaml</DependentUpon>
|
||||||
|
</Compile>
|
||||||
<Compile Include="Controls\Adverts\CommentAdvert.xaml.cs">
|
<Compile Include="Controls\Adverts\CommentAdvert.xaml.cs">
|
||||||
<DependentUpon>CommentAdvert.xaml</DependentUpon>
|
<DependentUpon>CommentAdvert.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
@@ -122,7 +136,8 @@
|
|||||||
<Compile Include="Controls\ChannelCard.xaml.cs">
|
<Compile Include="Controls\ChannelCard.xaml.cs">
|
||||||
<DependentUpon>ChannelCard.xaml</DependentUpon>
|
<DependentUpon>ChannelCard.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Controls\Chat.xaml.cs">
|
<Compile Include="Controls\Common\DownloadSelector.cs" />
|
||||||
|
<Compile Include="Controls\VideoPage\Chat.xaml.cs">
|
||||||
<DependentUpon>Chat.xaml</DependentUpon>
|
<DependentUpon>Chat.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Controls\CommentCard.xaml.cs">
|
<Compile Include="Controls\CommentCard.xaml.cs">
|
||||||
@@ -132,34 +147,44 @@
|
|||||||
<Compile Include="Controls\ContentFrame.xaml.cs">
|
<Compile Include="Controls\ContentFrame.xaml.cs">
|
||||||
<DependentUpon>ContentFrame.xaml</DependentUpon>
|
<DependentUpon>ContentFrame.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="Controls\Common\CreateAndAddPlaylist.xaml.cs">
|
||||||
|
<DependentUpon>CreateAndAddPlaylist.xaml</DependentUpon>
|
||||||
|
</Compile>
|
||||||
<Compile Include="Controls\DownloadItem.xaml.cs">
|
<Compile Include="Controls\DownloadItem.xaml.cs">
|
||||||
<DependentUpon>DownloadItem.xaml</DependentUpon>
|
<DependentUpon>DownloadItem.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Controls\LiveCaptions.xaml.cs">
|
<Compile Include="Controls\Player\LiveCaptions.xaml.cs">
|
||||||
<DependentUpon>LiveCaptions.xaml</DependentUpon>
|
<DependentUpon>LiveCaptions.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Controls\Player\PlayerControls.cs" />
|
<Compile Include="Controls\Player\PlayerControls.cs" />
|
||||||
|
<Compile Include="Controls\Player\PlayerMain.cs" />
|
||||||
<Compile Include="Controls\PlaylistCard.xaml.cs">
|
<Compile Include="Controls\PlaylistCard.xaml.cs">
|
||||||
<DependentUpon>PlaylistCard.xaml</DependentUpon>
|
<DependentUpon>PlaylistCard.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Controls\ReportVideo.xaml.cs">
|
<Compile Include="Controls\VideoPage\ReportVideo.xaml.cs">
|
||||||
<DependentUpon>ReportVideo.xaml</DependentUpon>
|
<DependentUpon>ReportVideo.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Controls\ShowMore.xaml.cs">
|
<Compile Include="Controls\ShowMore.xaml.cs">
|
||||||
<DependentUpon>ShowMore.xaml</DependentUpon>
|
<DependentUpon>ShowMore.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Pages\Browser.xaml.cs">
|
<Compile Include="Controls\VideoPage\RelatedVideos.xaml.cs">
|
||||||
<DependentUpon>Browser.xaml</DependentUpon>
|
<DependentUpon>RelatedVideos.xaml</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Controls\VideoPage\VideoPlaylist.xaml.cs">
|
||||||
|
<DependentUpon>VideoPlaylist.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Pages\ChannelPage.xaml.cs">
|
<Compile Include="Pages\ChannelPage.xaml.cs">
|
||||||
<DependentUpon>ChannelPage.xaml</DependentUpon>
|
<DependentUpon>ChannelPage.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Pages\CommentsPage.xaml.cs">
|
<Compile Include="Controls\VideoPage\Comments.xaml.cs">
|
||||||
<DependentUpon>CommentsPage.xaml</DependentUpon>
|
<DependentUpon>Comments.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Pages\Downloads.xaml.cs">
|
<Compile Include="Pages\Downloads.xaml.cs">
|
||||||
<DependentUpon>Downloads.xaml</DependentUpon>
|
<DependentUpon>Downloads.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="Pages\MainFrame.xaml.cs">
|
||||||
|
<DependentUpon>MainFrame.xaml</DependentUpon>
|
||||||
|
</Compile>
|
||||||
<Compile Include="Pages\SettingsPages\About.xaml.cs">
|
<Compile Include="Pages\SettingsPages\About.xaml.cs">
|
||||||
<DependentUpon>About.xaml</DependentUpon>
|
<DependentUpon>About.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
@@ -293,10 +318,18 @@
|
|||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
</ApplicationDefinition>
|
</ApplicationDefinition>
|
||||||
|
<Page Include="Controls\Common\AccountManager.xaml">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Page>
|
||||||
<Page Include="Controls\Adverts\CardAdvert.xaml">
|
<Page Include="Controls\Adverts\CardAdvert.xaml">
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
</Page>
|
</Page>
|
||||||
|
<Page Include="Controls\Adverts\ChatAdvert.xaml">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Page>
|
||||||
<Page Include="Controls\Adverts\CommentAdvert.xaml">
|
<Page Include="Controls\Adverts\CommentAdvert.xaml">
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
@@ -309,7 +342,7 @@
|
|||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
</Page>
|
</Page>
|
||||||
<Page Include="Controls\Chat.xaml">
|
<Page Include="Controls\VideoPage\Chat.xaml">
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
</Page>
|
</Page>
|
||||||
@@ -321,11 +354,15 @@
|
|||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
</Page>
|
</Page>
|
||||||
|
<Page Include="Controls\Common\CreateAndAddPlaylist.xaml">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Page>
|
||||||
<Page Include="Controls\DownloadItem.xaml">
|
<Page Include="Controls\DownloadItem.xaml">
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
</Page>
|
</Page>
|
||||||
<Page Include="Controls\LiveCaptions.xaml">
|
<Page Include="Controls\Player\LiveCaptions.xaml">
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
</Page>
|
</Page>
|
||||||
@@ -333,7 +370,7 @@
|
|||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
</Page>
|
</Page>
|
||||||
<Page Include="Controls\ReportVideo.xaml">
|
<Page Include="Controls\VideoPage\ReportVideo.xaml">
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
</Page>
|
</Page>
|
||||||
@@ -341,7 +378,11 @@
|
|||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
</Page>
|
</Page>
|
||||||
<Page Include="Pages\Browser.xaml">
|
<Page Include="Controls\VideoPage\RelatedVideos.xaml">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Page>
|
||||||
|
<Page Include="Controls\VideoPage\VideoPlaylist.xaml">
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
</Page>
|
</Page>
|
||||||
@@ -349,7 +390,7 @@
|
|||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
</Page>
|
</Page>
|
||||||
<Page Include="Pages\CommentsPage.xaml">
|
<Page Include="Controls\VideoPage\Comments.xaml">
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
</Page>
|
</Page>
|
||||||
@@ -357,6 +398,10 @@
|
|||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
</Page>
|
</Page>
|
||||||
|
<Page Include="Pages\MainFrame.xaml">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Page>
|
||||||
<Page Include="Pages\SettingsPages\About.xaml">
|
<Page Include="Pages\SettingsPages\About.xaml">
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
<Page
|
|
||||||
x:Class="FoxTube.Pages.Home1"
|
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
|
||||||
mc:Ignorable="d"
|
|
||||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
|
||||||
|
|
||||||
<Grid>
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="auto"/>
|
|
||||||
<RowDefinition/>
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition/>
|
|
||||||
<ColumnDefinition/>
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<AutoSuggestBox Grid.ColumnSpan="2" Text="https://youtube.com/" QueryIcon="Forward" QuerySubmitted="Adress_QuerySubmitted" Name="adress"/>
|
|
||||||
<ScrollViewer Grid.Row="1">
|
|
||||||
<TextBlock TextWrapping="Wrap" Name="code" IsTextSelectionEnabled="True"/>
|
|
||||||
</ScrollViewer>
|
|
||||||
<WebView Name="view" Grid.Row="1" Grid.Column="1"/>
|
|
||||||
</Grid>
|
|
||||||
</Page>
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Net.Http;
|
|
||||||
using Windows.UI.Xaml.Controls;
|
|
||||||
|
|
||||||
namespace FoxTube.Pages
|
|
||||||
{
|
|
||||||
public sealed partial class Home1 : Page
|
|
||||||
{
|
|
||||||
public Home1()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
Methods.MainPage.PageContent.LoadingPage.Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async void Initialize()
|
|
||||||
{
|
|
||||||
Dictionary<string, string> postContent = new Dictionary<string, string>
|
|
||||||
{
|
|
||||||
{ "sej", "{\"clickTrackingParams\":\"COQBEJQ1GAIiEwi028HJkdrhAhWCU5sKHQVmCS0ojh4=\",\"commandMetadata\":{\"webCommandMetadata\":{\"url\":\"/service_ajax\",\"sendPost\":true}},\"playlistEditEndpoint\":{\"playlistId\":\"WL\",\"actions\":[{\"action\":\"ACTION_REMOVE_VIDEO_BY_VIDEO_ID\",\"removedVideoId\":\"_j6Os3lIQ4U\"}]}}" },
|
|
||||||
{ "csn", "2K-4XLSPG4Kn7QSFzKXoAg" },
|
|
||||||
{ "session_token", "QUFFLUhqbVF6RkxPeWI3Z2s0bGJhMExMcjNmQ3BNRG9LUXxBQ3Jtc0tuR1pwOFJGMVd2ZGplSC1tTlZXd3M5bGxiZmdCR0pDZUEta0QyN3poejZCMlI2T1pfQXFnRU1yYkc4bzk5d0hrRUZ3bWlCbVZtWFl2U0h4UUp6RS1QRmlHVmNmTDVaeExGSF9ORXFCTko4ZEp0VnBlRVJnaWNRN2VQV05GaksyZm9MZTBnLTVRYWxnandGclVpSmZteU9fTjVxNUE=" }
|
|
||||||
};
|
|
||||||
|
|
||||||
FormUrlEncodedContent encoded = new FormUrlEncodedContent(postContent);
|
|
||||||
string encodedString = await encoded.ReadAsStringAsync();
|
|
||||||
|
|
||||||
//TODO: Fuck this shit
|
|
||||||
Dictionary<string, string> header = new Dictionary<string, string>
|
|
||||||
{
|
|
||||||
{ "Cookie", "CONSENT=YES+RU.ru+20180708-12-1; PREF=f6=400&al=ru&f1=50000000; VISITOR_INFO1_LIVE=ZDgD76zHoGM; SID=TwcUCkXNM6kCpxo-8TS_8h1W5Mc7v9InTeaSc2pUhTrhtJYT3370p3EGjMt7V_zIQCsT7w.; HSID=AKgfrRj-NlJVFHs_f; SSID=A8Ix_30UlJTHAZ_wi; APISID=mhnP6tU_JCLaQbsf/AcDBnYqdpqugTs5Uv; SAPISID=Y8OdALP87rADrHbx/Ak4TOmVQHJrSt5k9G; LOGIN_INFO=AFmmF2swRQIhALLDYwBvigvNfzj2iZ5FSy4EL9BhyUqFOuTKSu00jFJfAiAi6ej1ruClPwY6h8yMALu8zplkxU1g9HO8b1gMjdXJdg:QUQ3MjNmd2RFZFNfanB2OHpBVXRTWEs5cUo1Q1NVS0NjTV9ZUG1FQzJuam95S2t4Mm0yazU1ckYxdFN2S3dSTnlRaWZnWXBhYmFTWm1PWlAzVXNXX2dzYWtLUWdJSHgycG5Ed1R4bUJEdG1Hb2ZlR1JtRkI5QnhjYzhCZkNQNDhydWdkWUtjYl9MdVBOM0Y0RDRNNEdHRXZTNllKek9UT1hQMFJIdFpMcnFWNTh2NEtDS0FFdFNJ; SIDCC=AN0-TYv_HcQWprTqyxz1eROShbpRLucFOUPyiHv8XagpVwb_GvBvRAN4MClzKZ5dUj2ptf1NWyE; YSC=6ZnsQM5SW1A; ST-893xe3=itct=COQBEJQ1GAIiEwi028HJkdrhAhWCU5sKHQVmCS0ojh4yCmctaGlnaC1yZWNaD0ZFd2hhdF90b193YXRjaA%3D%3D&csn=2K-4XLSPG4Kn7QSFzKXoAg; ST-1w9u2il=itct=COQBEJQ1GAIiEwi028HJkdrhAhWCU5sKHQVmCS0ojh4%3D&csn=2K-4XLSPG4Kn7QSFzKXoAg" },
|
|
||||||
};
|
|
||||||
|
|
||||||
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "https://www.youtube.com/service_ajax?name=playlistEditEndpoint");
|
|
||||||
request.Content = encoded;
|
|
||||||
//request.Headers.Add("Cookie", "CONSENT=YES+RU.ru+20180708-12-1; PREF=f6=400&al=ru&f1=50000000; VISITOR_INFO1_LIVE=ZDgD76zHoGM; SID=TwcUCkXNM6kCpxo-8TS_8h1W5Mc7v9InTeaSc2pUhTrhtJYT3370p3EGjMt7V_zIQCsT7w.; HSID=AKgfrRj-NlJVFHs_f; SSID=A8Ix_30UlJTHAZ_wi; APISID=mhnP6tU_JCLaQbsf/AcDBnYqdpqugTs5Uv; SAPISID=Y8OdALP87rADrHbx/Ak4TOmVQHJrSt5k9G; LOGIN_INFO=AFmmF2swRQIhALLDYwBvigvNfzj2iZ5FSy4EL9BhyUqFOuTKSu00jFJfAiAi6ej1ruClPwY6h8yMALu8zplkxU1g9HO8b1gMjdXJdg:QUQ3MjNmd2RFZFNfanB2OHpBVXRTWEs5cUo1Q1NVS0NjTV9ZUG1FQzJuam95S2t4Mm0yazU1ckYxdFN2S3dSTnlRaWZnWXBhYmFTWm1PWlAzVXNXX2dzYWtLUWdJSHgycG5Ed1R4bUJEdG1Hb2ZlR1JtRkI5QnhjYzhCZkNQNDhydWdkWUtjYl9MdVBOM0Y0RDRNNEdHRXZTNllKek9UT1hQMFJIdFpMcnFWNTh2NEtDS0FFdFNJ; SIDCC=AN0-TYv_HcQWprTqyxz1eROShbpRLucFOUPyiHv8XagpVwb_GvBvRAN4MClzKZ5dUj2ptf1NWyE; YSC=6ZnsQM5SW1A; ST-893xe3=itct=COQBEJQ1GAIiEwi028HJkdrhAhWCU5sKHQVmCS0ojh4yCmctaGlnaC1yZWNaD0ZFd2hhdF90b193YXRjaA%3D%3D&csn=2K-4XLSPG4Kn7QSFzKXoAg; ST-1w9u2il=itct=COQBEJQ1GAIiEwi028HJkdrhAhWCU5sKHQVmCS0ojh4%3D&csn=2K-4XLSPG4Kn7QSFzKXoAg");
|
|
||||||
//request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", SecretsVault.Credential.Token.AccessToken);
|
|
||||||
|
|
||||||
HttpResponseMessage response = await new HttpClient().SendAsync(request);
|
|
||||||
Debug.WriteLine("Done");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Adress_QuerySubmitted(AutoSuggestBox sender, AutoSuggestBoxQuerySubmittedEventArgs args)
|
|
||||||
{
|
|
||||||
Initialize();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -15,6 +15,7 @@ using Windows.UI;
|
|||||||
using Windows.ApplicationModel.Resources;
|
using Windows.ApplicationModel.Resources;
|
||||||
using Microsoft.AppCenter.Analytics;
|
using Microsoft.AppCenter.Analytics;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using FoxTube.Classes;
|
||||||
|
|
||||||
namespace FoxTube.Pages
|
namespace FoxTube.Pages
|
||||||
{
|
{
|
||||||
@@ -105,21 +106,21 @@ namespace FoxTube.Pages
|
|||||||
|
|
||||||
ScrollViewer_ViewChanged(this, null);
|
ScrollViewer_ViewChanged(this, null);
|
||||||
|
|
||||||
Methods.MainPage.PageContent.LoadingPage.Close();
|
Navigation.Frame.Frame.LoadingPage.Close();
|
||||||
}
|
}
|
||||||
catch (System.Net.Http.HttpRequestException)
|
catch (System.Net.Http.HttpRequestException)
|
||||||
{
|
{
|
||||||
Methods.MainPage.PageContent.LoadingPage.Error("System.Net.Http.HttpRequestException", "Unable to connect to Google servers.", true);
|
Navigation.Frame.Frame.LoadingPage.Error("System.Net.Http.HttpRequestException", "Unable to connect to Google servers.", true);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
if(item == null)
|
if(item == null)
|
||||||
{
|
{
|
||||||
Methods.MainPage.PageContent.LoadingPage.Error("ChannelNotFound", "Such channel doesn't exist");
|
Navigation.Frame.Frame.LoadingPage.Error("ChannelNotFound", "Such channel doesn't exist");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Methods.MainPage.PageContent.LoadingPage.Error(e.GetType().ToString(), e.Message);
|
Navigation.Frame.Frame.LoadingPage.Error(e.GetType().ToString(), e.Message);
|
||||||
Analytics.TrackEvent("Channel loading error", new Dictionary<string, string>()
|
Analytics.TrackEvent("Channel loading error", new Dictionary<string, string>()
|
||||||
{
|
{
|
||||||
{ "Exception", e.GetType().ToString() },
|
{ "Exception", e.GetType().ToString() },
|
||||||
@@ -267,7 +268,7 @@ namespace FoxTube.Pages
|
|||||||
|
|
||||||
private void Refresh_Click(object sender, RoutedEventArgs e)
|
private void Refresh_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
Methods.MainPage.PageContent.Refresh();
|
Navigation.Frame.Frame.Refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void InBrowser_Click(object sender, RoutedEventArgs e)
|
private async void InBrowser_Click(object sender, RoutedEventArgs e)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using FoxTube.Controls;
|
using FoxTube.Classes;
|
||||||
|
using FoxTube.Controls;
|
||||||
using System;
|
using System;
|
||||||
using Windows.System;
|
using Windows.System;
|
||||||
using Windows.UI.Xaml;
|
using Windows.UI.Xaml;
|
||||||
@@ -24,7 +25,7 @@ namespace FoxTube.Pages
|
|||||||
|
|
||||||
empty.Visibility = list.Children.Count == 0 ? Visibility.Visible : Visibility.Collapsed;
|
empty.Visibility = list.Children.Count == 0 ? Visibility.Visible : Visibility.Collapsed;
|
||||||
|
|
||||||
Methods.MainPage.PageContent.LoadingPage.Close();
|
Navigation.Frame.Frame.LoadingPage.Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnNavigatedFrom(NavigationEventArgs e)
|
protected override void OnNavigatedFrom(NavigationEventArgs e)
|
||||||
@@ -34,10 +35,8 @@ namespace FoxTube.Pages
|
|||||||
DownloadAgent.Page = null;
|
DownloadAgent.Page = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void Open_Click(object sender, RoutedEventArgs e)
|
async void Open_Click(object sender, RoutedEventArgs e) =>
|
||||||
{
|
|
||||||
await Launcher.LaunchFolderAsync(DownloadAgent.Downloads);
|
await Launcher.LaunchFolderAsync(DownloadAgent.Downloads);
|
||||||
}
|
|
||||||
|
|
||||||
public void Remove(DownloadItem item)
|
public void Remove(DownloadItem item)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -18,7 +18,6 @@
|
|||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Pivot SelectionChanged="Pivot_SelectionChanged">
|
<Pivot SelectionChanged="Pivot_SelectionChanged">
|
||||||
<PivotItem x:Uid="/Playlist/appHistory" Header="Application">
|
<PivotItem x:Uid="/Playlist/appHistory" Header="Application">
|
||||||
<Grid>
|
|
||||||
<ScrollViewer>
|
<ScrollViewer>
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<Grid Margin="0,10" BorderBrush="Red" BorderThickness="5" CornerRadius="10" Padding="10">
|
<Grid Margin="0,10" BorderBrush="Red" BorderThickness="5" CornerRadius="10" Padding="10">
|
||||||
@@ -39,9 +38,6 @@
|
|||||||
<controls:ShowMore x:Name="more" Clicked="ShowMore_Clicked"/>
|
<controls:ShowMore x:Name="more" Clicked="ShowMore_Clicked"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
|
|
||||||
<foxtube:LoadingPage x:Name="loading" Visibility="Collapsed" RefreshPage="Refresh_Click"/>
|
|
||||||
</Grid>
|
|
||||||
</PivotItem>
|
</PivotItem>
|
||||||
<PivotItem x:Uid="/Playlist/webHistory" Header="Website">
|
<PivotItem x:Uid="/Playlist/webHistory" Header="Website">
|
||||||
<Grid>
|
<Grid>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using FoxTube.Controls;
|
using FoxTube.Classes;
|
||||||
|
using FoxTube.Controls;
|
||||||
using Microsoft.AppCenter.Analytics;
|
using Microsoft.AppCenter.Analytics;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@@ -20,10 +21,8 @@ namespace FoxTube.Pages
|
|||||||
int page = 1;
|
int page = 1;
|
||||||
int webPage = 0;
|
int webPage = 0;
|
||||||
|
|
||||||
public History()
|
public History() =>
|
||||||
{
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||||
{
|
{
|
||||||
@@ -31,15 +30,14 @@ namespace FoxTube.Pages
|
|||||||
Parameter = e.Parameter;
|
Parameter = e.Parameter;
|
||||||
|
|
||||||
Initialize();
|
Initialize();
|
||||||
Methods.MainPage.PageContent.LoadingPage.Close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void Initialize()
|
public async void Initialize()
|
||||||
{
|
{
|
||||||
Methods.MainPage.VideoContent.LoadingPage.Close();
|
Navigation.Frame.Frame.LoadingPage.Close();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
loading.Refresh();
|
Navigation.Frame.Frame.LoadingPage.Refresh();
|
||||||
|
|
||||||
await Dispatcher.RunIdleAsync((command) =>
|
await Dispatcher.RunIdleAsync((command) =>
|
||||||
{
|
{
|
||||||
@@ -53,11 +51,11 @@ namespace FoxTube.Pages
|
|||||||
clear.Visibility = Visibility.Collapsed;
|
clear.Visibility = Visibility.Collapsed;
|
||||||
});
|
});
|
||||||
|
|
||||||
loading.Close();
|
Navigation.Frame.Frame.LoadingPage.Close();
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
loading.Error(e.GetType().ToString(), e.Message);
|
Navigation.Frame.Frame.LoadingPage.Error(e.GetType().ToString(), e.Message);
|
||||||
Analytics.TrackEvent("Local history loading error", new Dictionary<string, string>()
|
Analytics.TrackEvent("Local history loading error", new Dictionary<string, string>()
|
||||||
{
|
{
|
||||||
{ "Exception", e.GetType().ToString() },
|
{ "Exception", e.GetType().ToString() },
|
||||||
@@ -67,19 +65,13 @@ namespace FoxTube.Pages
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void toBrowser_Click(object sender, RoutedEventArgs e)
|
private async void toBrowser_Click(object sender, RoutedEventArgs e) =>
|
||||||
{
|
|
||||||
await Launcher.LaunchUriAsync("https://www.youtube.com/feed/history".ToUri());
|
await Launcher.LaunchUriAsync("https://www.youtube.com/feed/history".ToUri());
|
||||||
}
|
|
||||||
|
|
||||||
private void Refresh_Click(object sender, RoutedEventArgs e)
|
private void Refresh_Click(object sender, RoutedEventArgs e) =>
|
||||||
{
|
Navigation.Frame.Refresh();
|
||||||
Methods.MainPage.PageContent.Refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void ShowMore_Clicked()
|
private async void ShowMore_Clicked() => await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
|
||||||
{
|
|
||||||
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
|
|
||||||
{
|
{
|
||||||
for (int k = 25 * page++; k < 25 * page && k < HistorySet.Items.Count; k++)
|
for (int k = 25 * page++; k < 25 * page && k < HistorySet.Items.Count; k++)
|
||||||
list.Add(new VideoCard(HistorySet.Items[k].Id, "HL"));
|
list.Add(new VideoCard(HistorySet.Items[k].Id, "HL"));
|
||||||
@@ -89,7 +81,6 @@ namespace FoxTube.Pages
|
|||||||
else
|
else
|
||||||
more.Complete();
|
more.Complete();
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
private async void Clear_Click(object sender, RoutedEventArgs e)
|
private async void Clear_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
@@ -117,8 +108,6 @@ namespace FoxTube.Pages
|
|||||||
}
|
}
|
||||||
|
|
||||||
async void LoadWeb()
|
async void LoadWeb()
|
||||||
{
|
|
||||||
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () =>
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -126,10 +115,10 @@ namespace FoxTube.Pages
|
|||||||
|
|
||||||
SecretsVault.History = await Methods.GetHistory();
|
SecretsVault.History = await Methods.GetHistory();
|
||||||
|
|
||||||
for (int k = 0; k < 25 && k < SecretsVault.History.Count; k++)
|
for (int k = 0; k < 25 && k < SecretsVault.History.Videos.Count; k++)
|
||||||
websiteList.Add(new VideoCard(SecretsVault.History[k], "HL"));
|
websiteList.Add(new VideoCard(SecretsVault.History.Videos[k].Id, "HL"));
|
||||||
|
|
||||||
if (websiteList.Count >= SecretsVault.History.Count)
|
if (websiteList.Count >= SecretsVault.History.Videos.Count)
|
||||||
websiteMore.Visibility = Visibility.Collapsed;
|
websiteMore.Visibility = Visibility.Collapsed;
|
||||||
|
|
||||||
websiteLoading.Close();
|
websiteLoading.Close();
|
||||||
@@ -144,26 +133,20 @@ namespace FoxTube.Pages
|
|||||||
{ "StackTrace", e.StackTrace }
|
{ "StackTrace", e.StackTrace }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void WebsiteMore_Clicked()
|
private async void WebsiteMore_Clicked() => await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
|
||||||
{
|
{
|
||||||
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
|
for (int k = 25 * webPage++; k < 25 * webPage && k < SecretsVault.History.Videos.Count; k++)
|
||||||
{
|
websiteList.Add(new VideoCard(SecretsVault.History.Videos[k].Id, "HL"));
|
||||||
for (int k = 25 * webPage++; k < 25 * webPage && k < SecretsVault.History.Count; k++)
|
|
||||||
websiteList.Add(new VideoCard(SecretsVault.History[k], "HL"));
|
|
||||||
|
|
||||||
if (websiteList.Count >= SecretsVault.History.Count)
|
if (websiteList.Count >= SecretsVault.History.Videos.Count)
|
||||||
websiteMore.Visibility = Visibility.Collapsed;
|
websiteMore.Visibility = Visibility.Collapsed;
|
||||||
else
|
else
|
||||||
websiteMore.Complete();
|
websiteMore.Complete();
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
public void Delete (VideoCard item)
|
public void Delete (VideoCard item) =>
|
||||||
{
|
|
||||||
list.DeleteItem(item);
|
list.DeleteItem(item);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ using FoxTube.Controls;
|
|||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using Microsoft.AppCenter.Analytics;
|
using Microsoft.AppCenter.Analytics;
|
||||||
|
using FoxTube.Classes;
|
||||||
|
|
||||||
namespace FoxTube
|
namespace FoxTube
|
||||||
{
|
{
|
||||||
@@ -42,7 +43,7 @@ namespace FoxTube
|
|||||||
|
|
||||||
private void pivot_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
private void pivot_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||||
{
|
{
|
||||||
Methods.MainPage.PageContent.LoadingPage.Close();
|
Navigation.Frame.Frame.LoadingPage.Close();
|
||||||
|
|
||||||
if (pivot.SelectedItem == recommended && !recLoaded)
|
if (pivot.SelectedItem == recommended && !recLoaded)
|
||||||
LoadRecommendations();
|
LoadRecommendations();
|
||||||
@@ -96,7 +97,7 @@ namespace FoxTube
|
|||||||
{
|
{
|
||||||
trendsLoading.Refresh();
|
trendsLoading.Refresh();
|
||||||
|
|
||||||
trendsRequest = SecretsVault.Service.Videos.List("snippet,contentDetails,statistics,liveStreamingDetails");
|
trendsRequest = SecretsVault.Service.Videos.List("id");
|
||||||
trendsRequest.MaxResults = 25;
|
trendsRequest.MaxResults = 25;
|
||||||
|
|
||||||
trendsRequest.Chart = VideosResource.ListRequest.ChartEnum.MostPopular;
|
trendsRequest.Chart = VideosResource.ListRequest.ChartEnum.MostPopular;
|
||||||
@@ -108,7 +109,7 @@ namespace FoxTube
|
|||||||
trendingMore.Visibility = string.IsNullOrWhiteSpace(response.NextPageToken) ? Visibility.Collapsed : Visibility.Visible;
|
trendingMore.Visibility = string.IsNullOrWhiteSpace(response.NextPageToken) ? Visibility.Collapsed : Visibility.Visible;
|
||||||
|
|
||||||
foreach (Video i in response.Items)
|
foreach (Video i in response.Items)
|
||||||
trendGrid.Add(new VideoCard(i));
|
trendGrid.Add(new VideoCard(i.Id));
|
||||||
|
|
||||||
trendsLoading.Close();
|
trendsLoading.Close();
|
||||||
trendLoaded = true;
|
trendLoaded = true;
|
||||||
@@ -170,8 +171,7 @@ namespace FoxTube
|
|||||||
#region More requests
|
#region More requests
|
||||||
private void Recommended_More()
|
private void Recommended_More()
|
||||||
{
|
{
|
||||||
int l = 25 + recGrid.Count;
|
for (int k = recGrid.Count; k < 25 + recGrid.Count && k < homeList.Count; k++)
|
||||||
for (int k = recGrid.Count; k < l && k < homeList.Count; k++)
|
|
||||||
recGrid.Add(new VideoCard(homeList[k]));
|
recGrid.Add(new VideoCard(homeList[k]));
|
||||||
|
|
||||||
recommendedMore.Visibility = recGrid.Count >= homeList.Count ? Visibility.Collapsed : Visibility.Visible;
|
recommendedMore.Visibility = recGrid.Count >= homeList.Count ? Visibility.Collapsed : Visibility.Visible;
|
||||||
@@ -185,14 +185,13 @@ namespace FoxTube
|
|||||||
trendingMore.Visibility = string.IsNullOrWhiteSpace(response.NextPageToken) ? Visibility.Collapsed : Visibility.Visible;
|
trendingMore.Visibility = string.IsNullOrWhiteSpace(response.NextPageToken) ? Visibility.Collapsed : Visibility.Visible;
|
||||||
|
|
||||||
foreach (Video i in response.Items)
|
foreach (Video i in response.Items)
|
||||||
trendGrid.Add(new VideoCard(i));
|
trendGrid.Add(new VideoCard(i.Id));
|
||||||
|
|
||||||
trendingMore.Complete();
|
trendingMore.Complete();
|
||||||
}
|
}
|
||||||
private void Subscriptions_More()
|
private void Subscriptions_More()
|
||||||
{
|
{
|
||||||
int l = 25 + subsGrid.Count;
|
for (int k = subsGrid.Count; k < 25 + subsGrid.Count && k < subsList.Count; k++)
|
||||||
for (int k = subsGrid.Count; k < l && k < subsList.Count; k++)
|
|
||||||
subsGrid.Add(new VideoCard(subsList[k]));
|
subsGrid.Add(new VideoCard(subsList[k]));
|
||||||
|
|
||||||
subscriptionsMore.Visibility = subsGrid.Count >= subsList.Count ? Visibility.Collapsed : Visibility.Visible;
|
subscriptionsMore.Visibility = subsGrid.Count >= subsList.Count ? Visibility.Collapsed : Visibility.Visible;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using Windows.ApplicationModel.Resources;
|
using Windows.ApplicationModel.Resources;
|
||||||
|
using Windows.System;
|
||||||
using Windows.UI.Xaml;
|
using Windows.UI.Xaml;
|
||||||
using Windows.UI.Xaml.Controls;
|
using Windows.UI.Xaml.Controls;
|
||||||
|
|
||||||
@@ -12,15 +13,13 @@ namespace FoxTube
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed partial class LoadingPage : Page
|
public sealed partial class LoadingPage : Page
|
||||||
{
|
{
|
||||||
ResourceLoader resources = ResourceLoader.GetForCurrentView("LoadingPage");
|
readonly ResourceLoader resources = ResourceLoader.GetForCurrentView("LoadingPage");
|
||||||
|
|
||||||
public event RoutedEventHandler RefreshPage;
|
public event RoutedEventHandler RefreshPage;
|
||||||
public LoadingState State { get; private set; } = LoadingState.Loadnig;
|
public LoadingState State { get; private set; } = LoadingState.Loadnig;
|
||||||
|
|
||||||
public LoadingPage()
|
public LoadingPage() =>
|
||||||
{
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
|
||||||
|
|
||||||
public void Error(string exceptionId = "Unknown", string details = "N/A", bool isWifiTrouble = false)
|
public void Error(string exceptionId = "Unknown", string details = "N/A", bool isWifiTrouble = false)
|
||||||
{
|
{
|
||||||
@@ -47,39 +46,6 @@ namespace FoxTube
|
|||||||
State = LoadingState.Error;
|
State = LoadingState.Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Block()
|
|
||||||
{
|
|
||||||
Visibility = Visibility.Visible;
|
|
||||||
ring.IsActive = false;
|
|
||||||
trouble.Visibility = Visibility.Collapsed;
|
|
||||||
wifiTrouble.Visibility = Visibility.Collapsed;
|
|
||||||
|
|
||||||
blockIcon.Visibility = Visibility.Visible;
|
|
||||||
|
|
||||||
State = LoadingState.Blocked;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void openWifi_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
await Windows.System.Launcher.LaunchUriAsync(new Uri("ms-settings:network"));
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void openTroubleshoot_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
await Windows.System.Launcher.LaunchUriAsync(new Uri("ms-settings:troubleshoot"));
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void feedback_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
await Windows.System.Launcher.LaunchUriAsync(new Uri("feedback-hub:"));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void wifiRefresh_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
Refresh();
|
|
||||||
RefreshPage.Invoke(this, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Refresh()
|
public void Refresh()
|
||||||
{
|
{
|
||||||
Visibility = Visibility.Visible;
|
Visibility = Visibility.Visible;
|
||||||
@@ -97,5 +63,32 @@ namespace FoxTube
|
|||||||
|
|
||||||
State = LoadingState.Loaded;
|
State = LoadingState.Loaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Block()
|
||||||
|
{
|
||||||
|
Visibility = Visibility.Visible;
|
||||||
|
ring.IsActive = false;
|
||||||
|
trouble.Visibility = Visibility.Collapsed;
|
||||||
|
wifiTrouble.Visibility = Visibility.Collapsed;
|
||||||
|
|
||||||
|
blockIcon.Visibility = Visibility.Visible;
|
||||||
|
|
||||||
|
State = LoadingState.Blocked;
|
||||||
|
}
|
||||||
|
|
||||||
|
async void openWifi_Click(object sender, RoutedEventArgs e) =>
|
||||||
|
await Launcher.LaunchUriAsync("ms-settings:network".ToUri());
|
||||||
|
|
||||||
|
async void openTroubleshoot_Click(object sender, RoutedEventArgs e) =>
|
||||||
|
await Launcher.LaunchUriAsync("ms-settings:troubleshoot".ToUri());
|
||||||
|
|
||||||
|
async void feedback_Click(object sender, RoutedEventArgs e) =>
|
||||||
|
await Launcher.LaunchUriAsync("feedback-hub:".ToUri());
|
||||||
|
|
||||||
|
void wifiRefresh_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Refresh();
|
||||||
|
RefreshPage.Invoke(this, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
<Page
|
||||||
|
x:Class="FoxTube.Pages.MainFrame"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:controls="using:FoxTube.Controls"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||||
|
|
||||||
|
<Grid>
|
||||||
|
<controls:ContentFrame x:Name="main"/>
|
||||||
|
<controls:ContentFrame x:Name="video"/>
|
||||||
|
</Grid>
|
||||||
|
</Page>
|
||||||
@@ -0,0 +1,153 @@
|
|||||||
|
using FoxTube.Classes;
|
||||||
|
using FoxTube.Controls;
|
||||||
|
using System;
|
||||||
|
using Windows.UI.ViewManagement;
|
||||||
|
using Windows.UI.Xaml;
|
||||||
|
using Windows.UI.Xaml.Controls;
|
||||||
|
|
||||||
|
namespace FoxTube.Pages
|
||||||
|
{
|
||||||
|
public sealed partial class MainFrame : Page
|
||||||
|
{
|
||||||
|
public event NavigationEventHanlder Navigated;
|
||||||
|
|
||||||
|
public bool CanGoBack => !VideoMinimized || main.Frame.CanGoBack;
|
||||||
|
|
||||||
|
public new ContentFrame Frame => main;
|
||||||
|
public ContentFrame Video => video;
|
||||||
|
|
||||||
|
public bool VideoMinimized => video.Width != double.NaN;
|
||||||
|
|
||||||
|
public MainFrame() =>
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
public void NavigateTo(Type pageType, object parameter = null, bool isNavigationPage = false)
|
||||||
|
{
|
||||||
|
if (main.Frame.SourcePageType == pageType && parameter == (main.Content as INavigationPage).Parameter)
|
||||||
|
return;
|
||||||
|
|
||||||
|
main.Navigate(pageType, parameter);
|
||||||
|
|
||||||
|
if (video.Content != null && !VideoMinimized)
|
||||||
|
MinimizeVideo();
|
||||||
|
|
||||||
|
Methods.MainPage.UpdateView();
|
||||||
|
|
||||||
|
if (!isNavigationPage)
|
||||||
|
Navigated?.Invoke(pageType, parameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Refresh() =>
|
||||||
|
main.Refresh();
|
||||||
|
|
||||||
|
#region Video control methods
|
||||||
|
public void OpenVideo(string id, string playlistId = null, bool incognito = false)
|
||||||
|
{
|
||||||
|
if (VideoMinimized)
|
||||||
|
MaximizeVideo();
|
||||||
|
|
||||||
|
video.Navigate(typeof(VideoPage), (id, playlistId, incognito));
|
||||||
|
|
||||||
|
Methods.MainPage.UpdateView();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void MinimizeVideo(bool player = false)
|
||||||
|
{
|
||||||
|
if (video.Content == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
video.Margin = new Thickness(0, 0, 25, 50);
|
||||||
|
video.HorizontalAlignment = HorizontalAlignment.Right;
|
||||||
|
video.VerticalAlignment = VerticalAlignment.Bottom;
|
||||||
|
video.Width = 432;
|
||||||
|
|
||||||
|
if (!player)
|
||||||
|
(video.Content as VideoPage).Minimize();
|
||||||
|
|
||||||
|
Methods.MainPage.UpdateView();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void MaximizeVideo(bool player = false)
|
||||||
|
{
|
||||||
|
if (video.Content == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
video.Margin = new Thickness(0);
|
||||||
|
video.VerticalAlignment = VerticalAlignment.Stretch;
|
||||||
|
video.HorizontalAlignment = HorizontalAlignment.Stretch;
|
||||||
|
video.Width = double.NaN;
|
||||||
|
|
||||||
|
if (!player)
|
||||||
|
(video.Content as VideoPage).Maximize();
|
||||||
|
|
||||||
|
Methods.MainPage.UpdateView();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CloseVideo()
|
||||||
|
{
|
||||||
|
if (ApplicationView.GetForCurrentView().IsFullScreenMode)
|
||||||
|
ApplicationView.GetForCurrentView().ExitFullScreenMode();
|
||||||
|
|
||||||
|
video.Frame.Content = null;
|
||||||
|
video.Frame.BackStack.Clear();
|
||||||
|
|
||||||
|
if (VideoMinimized)
|
||||||
|
MaximizeVideo();
|
||||||
|
|
||||||
|
GC.Collect();
|
||||||
|
|
||||||
|
Methods.MainPage.UpdateView();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RefreshVideo()
|
||||||
|
{
|
||||||
|
if (video.Content == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (VideoMinimized)
|
||||||
|
MaximizeVideo();
|
||||||
|
|
||||||
|
video.Refresh();
|
||||||
|
|
||||||
|
Methods.MainPage.UpdateView();
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public void AuthorizationChanged(bool? isAuthorized)
|
||||||
|
{
|
||||||
|
switch (isAuthorized)
|
||||||
|
{
|
||||||
|
case true:
|
||||||
|
if (main.Content == null)
|
||||||
|
NavigateTo(typeof(Home));
|
||||||
|
else if (main.Frame.CurrentSourcePageType != typeof(Downloads) && main.Frame.CurrentSourcePageType != typeof(Settings))
|
||||||
|
main.Refresh();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case false:
|
||||||
|
NavigateTo(typeof(Home));
|
||||||
|
|
||||||
|
main.Frame.BackStack.Clear();
|
||||||
|
video.Frame.BackStack.Clear();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
RefreshVideo();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void BackRequested()
|
||||||
|
{
|
||||||
|
if (video.Content != null && !VideoMinimized)
|
||||||
|
{
|
||||||
|
if (video.Frame.CanGoBack)
|
||||||
|
video.Frame.GoBack();
|
||||||
|
else if (video.LoadingPage.State != LoadingState.Loaded)
|
||||||
|
CloseVideo();
|
||||||
|
else
|
||||||
|
MinimizeVideo();
|
||||||
|
}
|
||||||
|
else if (main.Frame.CanGoBack)
|
||||||
|
main.Frame.GoBack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+17
-37
@@ -6,7 +6,11 @@
|
|||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
xmlns:ui="using:Microsoft.UI.Xaml.Controls"
|
xmlns:ui="using:Microsoft.UI.Xaml.Controls"
|
||||||
xmlns:controls="using:FoxTube.Controls">
|
xmlns:controls="using:FoxTube.Controls"
|
||||||
|
xmlns:data="using:Google.Apis.YouTube.v3.Data"
|
||||||
|
xmlns:foxtube="using:FoxTube.Controls.Player"
|
||||||
|
xmlns:common="using:FoxTube.Controls.Common"
|
||||||
|
xmlns:pages="using:FoxTube.Pages">
|
||||||
|
|
||||||
<Grid Name="grid">
|
<Grid Name="grid">
|
||||||
<VisualStateManager.VisualStateGroups>
|
<VisualStateManager.VisualStateGroups>
|
||||||
@@ -35,43 +39,23 @@
|
|||||||
Style="{StaticResource CaptionTextBlockStyle}" />
|
Style="{StaticResource CaptionTextBlockStyle}" />
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
<ui:NavigationView SelectedItem="toHome" BackRequested="Nav_BackRequested" PaneClosing="Nav_PaneClosing" PaneOpened="Nav_PaneOpened" OpenPaneLength="300" Name="nav" SelectionChanged="Nav_SelectionChanged">
|
<ui:NavigationView Name="nav" SelectionChanged="Nav_SelectionChanged"
|
||||||
|
PaneClosing="Nav_PaneClosing" PaneOpened="Nav_PaneOpened"
|
||||||
|
BackRequested="Nav_BackRequested"
|
||||||
|
IsBackEnabled="{x:Bind content.CanGoBack}">
|
||||||
<ui:NavigationView.Header>
|
<ui:NavigationView.Header>
|
||||||
<Grid>
|
<Grid>
|
||||||
<TextBlock Name="Title" Style="{StaticResource TitleTextBlockStyle}"/>
|
<TextBlock Name="Title" Style="{StaticResource TitleTextBlockStyle}"/>
|
||||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
|
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
|
||||||
<Button x:Uid="/Main/feedback" Name="feedback" Click="Feedback_Click" Visibility="Collapsed" FontFamily="Segoe MDL2 Assets" Content="" Background="Transparent" Height="41" Width="60" FontSize="15"/>
|
<Button x:Uid="/Main/feedback" Name="feedback" Click="Feedback_Click" Visibility="Collapsed" FontFamily="Segoe MDL2 Assets" Content="" Background="Transparent" Height="41" Width="60" FontSize="15"/>
|
||||||
<Button x:Uid="/Main/signIn" Name="account" Click="SignIn_Click" Visibility="Collapsed" FontFamily="Segoe MDL2 Assets" Content="" Background="Transparent" Height="41" Width="60" FontSize="15"/>
|
<common:AccountManager x:Name="manager"/>
|
||||||
<Button Background="Transparent" Visibility="Collapsed" Name="avatar" Height="41" Width="60" FontSize="15" Padding="0">
|
|
||||||
<Button.Flyout>
|
|
||||||
<Flyout>
|
|
||||||
<Grid>
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="auto"/>
|
|
||||||
<ColumnDefinition/>
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<PersonPicture Width="65" Name="avatarFlyout" VerticalAlignment="Top"/>
|
|
||||||
<StackPanel Grid.Column="1" Margin="5">
|
|
||||||
<TextBlock Name="myNameFlyout"/>
|
|
||||||
<TextBlock Style="{StaticResource CaptionTextBlockStyle}" Name="myEmail"/>
|
|
||||||
<HyperlinkButton x:Uid="/Main/signOut" Content="Log out" Click="Logout_Click"/>
|
|
||||||
</StackPanel>
|
|
||||||
</Grid>
|
|
||||||
</Flyout>
|
|
||||||
</Button.Flyout>
|
|
||||||
<Ellipse Width="25" Height="25">
|
|
||||||
<Ellipse.Fill>
|
|
||||||
<ImageBrush ImageSource="/Assets/Icons/profile.png"/>
|
|
||||||
</Ellipse.Fill>
|
|
||||||
</Ellipse>
|
|
||||||
</Button>
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
</ui:NavigationView.Header>
|
</ui:NavigationView.Header>
|
||||||
|
|
||||||
<ui:NavigationView.MenuItemTemplate>
|
<ui:NavigationView.MenuItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate x:DataType="data:Subscription">
|
||||||
<StackPanel Orientation="Horizontal" Padding="5" Margin="-5,0,0,0" Tag="{Binding Snippet.ResourceId.ChannelId}">
|
<StackPanel Orientation="Horizontal" Padding="5" Margin="-5,0,0,0">
|
||||||
<PersonPicture Height="20" Margin="-5,0,15,0">
|
<PersonPicture Height="20" Margin="-5,0,15,0">
|
||||||
<PersonPicture.ProfilePicture>
|
<PersonPicture.ProfilePicture>
|
||||||
<BitmapImage UriSource="{Binding Snippet.Thumbnails.Medium.Url}" DecodePixelHeight="20" DecodePixelWidth="20"/>
|
<BitmapImage UriSource="{Binding Snippet.Thumbnails.Medium.Url}" DecodePixelHeight="20" DecodePixelWidth="20"/>
|
||||||
@@ -99,21 +83,17 @@
|
|||||||
</ui:NavigationView.MenuItems>
|
</ui:NavigationView.MenuItems>
|
||||||
|
|
||||||
<ui:NavigationView.PaneFooter>
|
<ui:NavigationView.PaneFooter>
|
||||||
<ui:NavigationViewItem Content="Remove ads" Visibility="Collapsed" Tapped="RemoveAds_Tapped" Name="removeAds">
|
<ui:NavigationViewList>
|
||||||
<ui:NavigationViewItem.Icon>
|
<ui:NavigationViewItemSeparator/>
|
||||||
<FontIcon Glyph=""/>
|
<ui:NavigationViewItem Content="Remove ads" Visibility="Collapsed" Tapped="RemoveAds_Tapped" Name="removeAds" Icon="Shop"/>
|
||||||
</ui:NavigationViewItem.Icon>
|
</ui:NavigationViewList>
|
||||||
</ui:NavigationViewItem>
|
|
||||||
</ui:NavigationView.PaneFooter>
|
</ui:NavigationView.PaneFooter>
|
||||||
|
|
||||||
<ui:NavigationView.AutoSuggestBox>
|
<ui:NavigationView.AutoSuggestBox>
|
||||||
<AutoSuggestBox x:Name="search" QueryIcon="Find" QuerySubmitted="Search_QuerySubmitted" TextChanged="Search_TextChanged" x:Uid="/Main/searchPlaceholder" PlaceholderText="Search"/>
|
<AutoSuggestBox x:Name="search" QueryIcon="Find" QuerySubmitted="Search_QuerySubmitted" TextChanged="Search_TextChanged" x:Uid="/Main/searchPlaceholder" PlaceholderText="Search"/>
|
||||||
</ui:NavigationView.AutoSuggestBox>
|
</ui:NavigationView.AutoSuggestBox>
|
||||||
|
|
||||||
<Grid>
|
<pages:MainFrame x:Name="content" Navigated="Content_Navigated"/>
|
||||||
<controls:ContentFrame x:Name="content" Navigated="Content_Navigated"/>
|
|
||||||
<controls:ContentFrame x:Name="videoPlaceholder"/>
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
</ui:NavigationView>
|
</ui:NavigationView>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|||||||
+131
-449
@@ -1,27 +1,19 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Windows.UI;
|
using Windows.UI;
|
||||||
using Windows.UI.ViewManagement;
|
using Windows.UI.ViewManagement;
|
||||||
using Windows.UI.Xaml;
|
using Windows.UI.Xaml;
|
||||||
using Windows.UI.Xaml.Controls;
|
using Windows.UI.Xaml.Controls;
|
||||||
using Windows.UI.Xaml.Input;
|
using Windows.UI.Xaml.Input;
|
||||||
using Windows.UI.Xaml.Navigation;
|
|
||||||
using Windows.UI.Xaml.Media.Imaging;
|
|
||||||
using Google.Apis.YouTube.v3.Data;
|
using Google.Apis.YouTube.v3.Data;
|
||||||
using Windows.ApplicationModel.Core;
|
using Windows.ApplicationModel.Core;
|
||||||
using Windows.System;
|
|
||||||
using FoxTube.Pages;
|
using FoxTube.Pages;
|
||||||
using Windows.UI.Popups;
|
using Windows.UI.Popups;
|
||||||
using Windows.ApplicationModel.Resources;
|
using Windows.ApplicationModel.Resources;
|
||||||
using Microsoft.Services.Store.Engagement;
|
using Microsoft.Services.Store.Engagement;
|
||||||
using Windows.UI.Xaml.Shapes;
|
|
||||||
using Windows.UI.Xaml.Media;
|
|
||||||
using FoxTube.Controls;
|
|
||||||
using Microsoft.AppCenter.Analytics;
|
|
||||||
using Windows.ApplicationModel.DataTransfer;
|
|
||||||
using Windows.UI.Notifications;
|
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
|
using System.Linq;
|
||||||
|
using FoxTube.Classes;
|
||||||
|
|
||||||
namespace FoxTube
|
namespace FoxTube
|
||||||
{
|
{
|
||||||
@@ -30,12 +22,10 @@ namespace FoxTube
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed partial class MainPage : Page
|
public sealed partial class MainPage : Page
|
||||||
{
|
{
|
||||||
bool wasInvoked = false;
|
|
||||||
readonly ResourceLoader resources = ResourceLoader.GetForCurrentView("Main");
|
readonly ResourceLoader resources = ResourceLoader.GetForCurrentView("Main");
|
||||||
Dictionary<Type, string> headers;
|
readonly Dictionary<Type, string> headers;
|
||||||
|
|
||||||
public ContentFrame PageContent => content;
|
public new MainFrame Content => content;
|
||||||
public ContentFrame VideoContent => videoPlaceholder;
|
|
||||||
|
|
||||||
public MainPage()
|
public MainPage()
|
||||||
{
|
{
|
||||||
@@ -70,129 +60,21 @@ namespace FoxTube
|
|||||||
}
|
}
|
||||||
|
|
||||||
MessageDialog dialog = new MessageDialog(resources.GetString("/Main/purchaseSuccess"));
|
MessageDialog dialog = new MessageDialog(resources.GetString("/Main/purchaseSuccess"));
|
||||||
dialog.Commands.Add(new UICommand(resources.GetString("/Main/close"), (command) => Methods.CloseApp()));
|
dialog.Commands.Add(new UICommand(resources.GetString("/Main/close"), (command) => CoreApplication.Exit()));
|
||||||
dialog.Commands.Add(new UICommand(resources.GetString("/Main/delay")));
|
dialog.Commands.Add(new UICommand(resources.GetString("/Main/delay")));
|
||||||
dialog.CancelCommandIndex = 1;
|
dialog.CancelCommandIndex = 1;
|
||||||
dialog.DefaultCommandIndex = 0;
|
dialog.DefaultCommandIndex = 0;
|
||||||
await dialog.ShowAsync();
|
await dialog.ShowAsync();
|
||||||
};
|
};
|
||||||
SecretsVault.Initialize();
|
|
||||||
|
if (SecretsVault.IsAuthorized)
|
||||||
|
AuthorizationStateChanged(true);
|
||||||
|
|
||||||
|
if (!SecretsVault.AdsDisabled)
|
||||||
|
SecretsVault.CheckAddons();
|
||||||
|
|
||||||
if(StoreServicesFeedbackLauncher.IsSupported())
|
if(StoreServicesFeedbackLauncher.IsSupported())
|
||||||
feedback.Visibility = Visibility.Visible;
|
feedback.Visibility = Visibility.Visible;
|
||||||
|
|
||||||
if(SettingsStorage.ProcessClipboard)
|
|
||||||
{
|
|
||||||
Clipboard.ContentChanged += ParseClipboard;
|
|
||||||
ParseClipboard(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
PromptFeedback();
|
|
||||||
}
|
|
||||||
|
|
||||||
async void ParseClipboard(object sender = null, object e = null)
|
|
||||||
{
|
|
||||||
if (sender == null && Window.Current.CoreWindow.ActivationMode != Windows.UI.Core.CoreWindowActivationMode.Deactivated)
|
|
||||||
return;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
string link = await Clipboard.GetContent().GetTextAsync();
|
|
||||||
|
|
||||||
if (!link.Contains("youtube") && !link.Contains("youtu.be"))
|
|
||||||
return;
|
|
||||||
|
|
||||||
string id;
|
|
||||||
string type;
|
|
||||||
string name;
|
|
||||||
|
|
||||||
if (YoutubeExplode.YoutubeClient.TryParseChannelId(link, out id))
|
|
||||||
{
|
|
||||||
type = "channel";
|
|
||||||
name = (await new YoutubeExplode.YoutubeClient().GetChannelAsync(id)).Title;
|
|
||||||
goto Complete;
|
|
||||||
}
|
|
||||||
else if (YoutubeExplode.YoutubeClient.TryParsePlaylistId(link, out id))
|
|
||||||
{
|
|
||||||
type = "playlist";
|
|
||||||
name = (await new YoutubeExplode.YoutubeClient().GetPlaylistAsync(id)).Title;
|
|
||||||
goto Complete;
|
|
||||||
}
|
|
||||||
else if (YoutubeExplode.YoutubeClient.TryParseUsername(link, out id))
|
|
||||||
{
|
|
||||||
id = await new YoutubeExplode.YoutubeClient().GetChannelIdAsync(id);
|
|
||||||
type = "channel";
|
|
||||||
name = (await new YoutubeExplode.YoutubeClient().GetChannelAsync(id)).Title;
|
|
||||||
goto Complete;
|
|
||||||
}
|
|
||||||
else if (YoutubeExplode.YoutubeClient.TryParseVideoId(link, out id))
|
|
||||||
{
|
|
||||||
type = "video";
|
|
||||||
name = (await new YoutubeExplode.YoutubeClient().GetVideoAsync(id)).Title;
|
|
||||||
goto Complete;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
|
|
||||||
Complete:
|
|
||||||
Windows.Data.Xml.Dom.XmlDocument toastXml = new Windows.Data.Xml.Dom.XmlDocument();
|
|
||||||
toastXml.LoadXml($@"<toast launch='clipboard|{type}|{id}'>
|
|
||||||
<visual>
|
|
||||||
<binding template='ToastGeneric'>
|
|
||||||
<text>{resources.GetString("/Main/clipboardHead")}</text>
|
|
||||||
<text>{name}</text>
|
|
||||||
<text>{resources.GetString($"/Main/{type}")}</text>
|
|
||||||
</binding>
|
|
||||||
</visual>
|
|
||||||
<actions>
|
|
||||||
<action content='{resources.GetString("/Main/clipboardOpen")}' arguments='clipboard|{type}|{id}'/>
|
|
||||||
</actions>
|
|
||||||
</toast>");
|
|
||||||
ToastNotificationManager.CreateToastNotifier().Show(new ToastNotification(toastXml));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
}
|
|
||||||
|
|
||||||
async void PromptFeedback()
|
|
||||||
{
|
|
||||||
if (SettingsStorage.Uptime.TotalHours >= 12 && SettingsStorage.PromptFeedback)
|
|
||||||
{
|
|
||||||
MessageDialog dialog = new MessageDialog(resources.GetString("/Main/feedbackMessage"));
|
|
||||||
dialog.Commands.Add(new UICommand(resources.GetString("/Main/dontAsk"), (command) => SettingsStorage.PromptFeedback = false));
|
|
||||||
dialog.Commands.Add(new UICommand(resources.GetString("/Main/promptLater")));
|
|
||||||
dialog.Commands.Add(new UICommand(resources.GetString("/Main/sure"), async (command) =>
|
|
||||||
{
|
|
||||||
SettingsStorage.PromptFeedback = false;
|
|
||||||
if (StoreServicesFeedbackLauncher.IsSupported())
|
|
||||||
await StoreServicesFeedbackLauncher.GetDefault().LaunchAsync();
|
|
||||||
else
|
|
||||||
{
|
|
||||||
MessageDialog message = new MessageDialog(resources.GetString("/Main/feedbackFail"));
|
|
||||||
message.Commands.Add(new UICommand(resources.GetString("/Main/sendEmail"), async (c) => await Launcher.LaunchUriAsync("mailto:michael.xfox@outlook.com".ToUri())));
|
|
||||||
message.Commands.Add(new UICommand(resources.GetString("/Main/goBack")));
|
|
||||||
message.CancelCommandIndex = 1;
|
|
||||||
message.DefaultCommandIndex = 0;
|
|
||||||
await message.ShowAsync();
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
dialog.DefaultCommandIndex = 2;
|
|
||||||
dialog.CancelCommandIndex = 1;
|
|
||||||
await dialog.ShowAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SettingsStorage.Uptime.TotalHours >= 24 && SettingsStorage.PromptReview)
|
|
||||||
{
|
|
||||||
MessageDialog dialog = new MessageDialog(resources.GetString("/Main/rate"));
|
|
||||||
dialog.Commands.Add(new UICommand(resources.GetString("/Main/dontAsk"), (command) => SettingsStorage.PromptReview = false));
|
|
||||||
dialog.Commands.Add(new UICommand(resources.GetString("/Main/promptLater")));
|
|
||||||
dialog.Commands.Add(new UICommand(resources.GetString("/Main/sure"), async (command) =>
|
|
||||||
{
|
|
||||||
SettingsStorage.PromptReview = false;
|
|
||||||
await Launcher.LaunchUriAsync("ms-windows-store://review/?ProductId=9NCQQXJTDLFH".ToUri());
|
|
||||||
}));
|
|
||||||
dialog.DefaultCommandIndex = 2;
|
|
||||||
dialog.CancelCommandIndex = 1;
|
|
||||||
await dialog.ShowAsync();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetTitleBar(CoreApplicationViewTitleBar coreTitleBar = null)
|
public void SetTitleBar(CoreApplicationViewTitleBar coreTitleBar = null)
|
||||||
@@ -212,49 +94,38 @@ namespace FoxTube
|
|||||||
titleBar.ButtonPressedBackgroundColor = Colors.DarkRed;
|
titleBar.ButtonPressedBackgroundColor = Colors.DarkRed;
|
||||||
titleBar.ButtonInactiveBackgroundColor = Colors.Transparent;
|
titleBar.ButtonInactiveBackgroundColor = Colors.Transparent;
|
||||||
titleBar.ButtonInactiveForegroundColor = Colors.Gray;
|
titleBar.ButtonInactiveForegroundColor = Colors.Gray;
|
||||||
|
titleBar.ButtonForegroundColor = Application.Current.RequestedTheme == ApplicationTheme.Dark ? Colors.Black : Colors.White;
|
||||||
if(RequestedTheme == ElementTheme.Dark || (RequestedTheme == ElementTheme.Default && Application.Current.RequestedTheme == ApplicationTheme.Dark))
|
|
||||||
titleBar.ButtonForegroundColor = Colors.White;
|
|
||||||
else
|
|
||||||
titleBar.ButtonForegroundColor = Colors.Black;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SecretsVault_SubscriptionsChanged(object sender, params object[] args)
|
void SecretsVault_SubscriptionsChanged(string action, Subscription subscription)
|
||||||
{
|
{
|
||||||
switch((string)args[0])
|
switch(action)
|
||||||
{
|
{
|
||||||
case "add":
|
case "add":
|
||||||
|
subsHeader.Visibility = Visibility.Visible;
|
||||||
if (nav.MenuItems.Count < 19)
|
if (nav.MenuItems.Count < 19)
|
||||||
nav.MenuItems.Add(args[1] as Subscription);
|
nav.MenuItems.Add(subscription);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "remove":
|
case "remove":
|
||||||
if(nav.MenuItems.Contains((Subscription)args[1]))
|
if(nav.MenuItems.Contains(subscription))
|
||||||
{
|
{
|
||||||
nav.MenuItems.Remove(args[1]);
|
nav.MenuItems.Remove(subscription);
|
||||||
if (SecretsVault.Subscriptions.Count >= 10)
|
if (SecretsVault.Subscriptions.Count >= 10)
|
||||||
nav.MenuItems.Add(SecretsVault.Subscriptions[9]);
|
nav.MenuItems.Add(SecretsVault.Subscriptions[9]);
|
||||||
|
else if (SecretsVault.Subscriptions.Count == 0)
|
||||||
|
subsHeader.Visibility = Visibility.Collapsed;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void AuthorizationStateChanged(object sender, params object[] e)
|
async void AuthorizationStateChanged(bool? isAuthozied)
|
||||||
{
|
{
|
||||||
wasInvoked = false;
|
switch (isAuthozied)
|
||||||
|
|
||||||
switch (e[0] as bool?)
|
|
||||||
{
|
{
|
||||||
case true:
|
case true:
|
||||||
account.Visibility = Visibility.Collapsed;
|
manager.Logged();
|
||||||
|
|
||||||
ToolTipService.SetToolTip(avatar, $"{SecretsVault.UserInfo.Name} ({SecretsVault.UserInfo.Email})");
|
|
||||||
myNameFlyout.Text = SecretsVault.UserInfo.Name;
|
|
||||||
myEmail.Text = SecretsVault.UserInfo.Email;
|
|
||||||
avatarFlyout.ProfilePicture = new BitmapImage(SecretsVault.UserInfo.Picture.ToUri()) { DecodePixelHeight = 65, DecodePixelWidth = 65 };
|
|
||||||
((avatar.Content as Ellipse).Fill as ImageBrush).ImageSource = new BitmapImage(SecretsVault.UserInfo.Picture.ToUri()) { DecodePixelHeight = 25, DecodePixelWidth = 25 };
|
|
||||||
|
|
||||||
avatar.Visibility = Visibility.Visible;
|
|
||||||
|
|
||||||
toChannel.Visibility = Visibility.Visible;
|
toChannel.Visibility = Visibility.Visible;
|
||||||
toSubscriptions.Visibility = Visibility.Visible;
|
toSubscriptions.Visibility = Visibility.Visible;
|
||||||
@@ -270,21 +141,10 @@ namespace FoxTube
|
|||||||
nav.MenuItems.Add(SecretsVault.Subscriptions[k]);
|
nav.MenuItems.Add(SecretsVault.Subscriptions[k]);
|
||||||
}
|
}
|
||||||
HistorySet.Load();
|
HistorySet.Load();
|
||||||
|
|
||||||
if (content.Frame.Content != null)
|
|
||||||
content.Refresh();
|
|
||||||
else
|
|
||||||
content.Frame.Navigate(typeof(Home));
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case false:
|
case false:
|
||||||
content.Frame.Navigate(typeof(Home));
|
manager.Quit();
|
||||||
|
|
||||||
for (int k = nav.MenuItems.Count - 1; k > 8; k--)
|
|
||||||
nav.MenuItems.RemoveAt(k);
|
|
||||||
|
|
||||||
account.Visibility = Visibility.Visible;
|
|
||||||
avatar.Visibility = Visibility.Collapsed;
|
|
||||||
|
|
||||||
toChannel.Visibility = Visibility.Collapsed;
|
toChannel.Visibility = Visibility.Collapsed;
|
||||||
toSubscriptions.Visibility = Visibility.Collapsed;
|
toSubscriptions.Visibility = Visibility.Collapsed;
|
||||||
@@ -296,8 +156,9 @@ namespace FoxTube
|
|||||||
|
|
||||||
subsHeader.Visibility = Visibility.Collapsed;
|
subsHeader.Visibility = Visibility.Collapsed;
|
||||||
|
|
||||||
content.Frame.BackStack.Clear();
|
for (int k = nav.MenuItems.Count - 1; k > 8; k--)
|
||||||
content.Frame.ForwardStack.Clear();
|
nav.MenuItems.RemoveAt(k);
|
||||||
|
HistorySet.Items.Clear();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -305,14 +166,8 @@ namespace FoxTube
|
|||||||
|
|
||||||
if (StoreServicesFeedbackLauncher.IsSupported())
|
if (StoreServicesFeedbackLauncher.IsSupported())
|
||||||
dialog.Commands.Add(new UICommand(resources.GetString("/About/feedback/Content"), async (command) => await StoreServicesFeedbackLauncher.GetDefault().LaunchAsync()));
|
dialog.Commands.Add(new UICommand(resources.GetString("/About/feedback/Content"), async (command) => await StoreServicesFeedbackLauncher.GetDefault().LaunchAsync()));
|
||||||
dialog.Commands.Add(new UICommand(resources.GetString("/Main/tryAgain"), (command) =>
|
dialog.Commands.Add(new UICommand(resources.GetString("/Main/tryAgain"), (command) => SecretsVault.Authorize()));
|
||||||
{
|
dialog.Commands.Add(new UICommand(resources.GetString("/Main/quit"), (command) => CoreApplication.Exit()));
|
||||||
SecretsVault.Authorize();
|
|
||||||
}));
|
|
||||||
dialog.Commands.Add(new UICommand(resources.GetString("/Main/quit"), (command) =>
|
|
||||||
{
|
|
||||||
Methods.CloseApp();
|
|
||||||
}));
|
|
||||||
|
|
||||||
dialog.CancelCommandIndex = 1;
|
dialog.CancelCommandIndex = 1;
|
||||||
dialog.DefaultCommandIndex = 0;
|
dialog.DefaultCommandIndex = 0;
|
||||||
@@ -321,114 +176,18 @@ namespace FoxTube
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (videoPlaceholder.Frame.Content != null)
|
content.AuthorizationChanged(isAuthozied);
|
||||||
{
|
|
||||||
MaximizeVideo();
|
|
||||||
videoPlaceholder.Refresh();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DownloadAgent.Initialize();
|
public void UpdateView()
|
||||||
}
|
|
||||||
|
|
||||||
private async void Feedback_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
{
|
||||||
await StoreServicesFeedbackLauncher.GetDefault().LaunchAsync();
|
if(content.Video.Content != null && !content.VideoMinimized)
|
||||||
}
|
|
||||||
|
|
||||||
private void SignIn_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
SecretsVault.Authorize();
|
|
||||||
Analytics.TrackEvent("Initialized authorization sequence");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Logout_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
avatar.Flyout.Hide();
|
|
||||||
SecretsVault.Deauthenticate();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void GoToSearch(SearchParameters args)
|
|
||||||
{
|
|
||||||
content.Frame.Navigate(typeof(Search), new object[] { args, content });
|
|
||||||
}
|
|
||||||
|
|
||||||
public void GoToChannel(string id)
|
|
||||||
{
|
|
||||||
content.Frame.Navigate(typeof(ChannelPage), id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void GoToHome()
|
|
||||||
{
|
|
||||||
content.Frame.Navigate(typeof(Home));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void GoToVideo(string id, string playlistId = null, bool incognito = false)
|
|
||||||
{
|
|
||||||
MaximizeVideo();
|
|
||||||
|
|
||||||
nav.IsBackEnabled = true;
|
|
||||||
nav.ExpandedModeThresholdWidth = short.MaxValue;
|
|
||||||
nav.IsPaneOpen = false;
|
|
||||||
|
|
||||||
videoPlaceholder.Frame.Navigate(typeof(VideoPage), new object[3] { id, playlistId, incognito });
|
|
||||||
|
|
||||||
Title.Text = resources.GetString("/Main/video");
|
Title.Text = resources.GetString("/Main/video");
|
||||||
}
|
|
||||||
|
|
||||||
public void GoToDeveloper(string id)
|
|
||||||
{
|
|
||||||
content.Frame.Navigate(typeof(Settings), id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void GoToPlaylist(string id)
|
|
||||||
{
|
|
||||||
content.Frame.Navigate(typeof(PlaylistPage), id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void GoToHistory()
|
|
||||||
{
|
|
||||||
content.Frame.Navigate(typeof(History));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void GoToDownloads()
|
|
||||||
{
|
|
||||||
content.Frame.Navigate(typeof(Downloads));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void MinimizeAsInitializer()
|
|
||||||
{
|
|
||||||
if (videoPlaceholder.Frame.Content == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (videoPlaceholder.LoadingPage.State != LoadingState.Loaded)
|
|
||||||
CloseVideo();
|
|
||||||
else
|
else
|
||||||
(videoPlaceholder.Frame.Content as VideoPage).Player.Minimize();
|
Title.Text = headers[content.Frame.Frame.SourcePageType];
|
||||||
|
nav.IsBackEnabled = content.CanGoBack;
|
||||||
|
|
||||||
Title.Text = headers[content.Frame.SourcePageType];
|
if (new[] { typeof(Home), typeof(Settings), typeof(Subscriptions) }.Contains(content.Frame.Frame.SourcePageType))
|
||||||
}
|
|
||||||
|
|
||||||
public void MinimizeVideo()
|
|
||||||
{
|
|
||||||
videoPlaceholder.Width = 432;
|
|
||||||
videoPlaceholder.Height = 432 * (videoPlaceholder.Frame.Content as VideoPage).Player.ActualHeight / (videoPlaceholder.Frame.Content as VideoPage).Player.ActualWidth;
|
|
||||||
videoPlaceholder.VerticalAlignment = VerticalAlignment.Bottom;
|
|
||||||
videoPlaceholder.HorizontalAlignment = HorizontalAlignment.Right;
|
|
||||||
videoPlaceholder.Margin = new Thickness(0, 0, 25, 50);
|
|
||||||
|
|
||||||
if (content.Frame.CanGoBack)
|
|
||||||
nav.IsBackEnabled = true;
|
|
||||||
else
|
|
||||||
nav.IsBackEnabled = false;
|
|
||||||
|
|
||||||
SetNavigationMenu();
|
|
||||||
|
|
||||||
Title.Text = headers[content.Frame.SourcePageType];
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetNavigationMenu()
|
|
||||||
{
|
|
||||||
if (content.Frame.SourcePageType == typeof(Home) || content.Frame.SourcePageType == typeof(Settings) || content.Frame.SourcePageType == typeof(Subscriptions))
|
|
||||||
{
|
{
|
||||||
nav.ExpandedModeThresholdWidth = 1008;
|
nav.ExpandedModeThresholdWidth = 1008;
|
||||||
nav.IsPaneOpen = nav.DisplayMode == Microsoft.UI.Xaml.Controls.NavigationViewDisplayMode.Expanded ? true : false;
|
nav.IsPaneOpen = nav.DisplayMode == Microsoft.UI.Xaml.Controls.NavigationViewDisplayMode.Expanded ? true : false;
|
||||||
@@ -440,199 +199,122 @@ namespace FoxTube
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void MaximizeVideo()
|
object GetChannelMenuItem(object parameter)
|
||||||
{
|
{
|
||||||
videoPlaceholder.Width = double.NaN;
|
if (!SecretsVault.IsAuthorized)
|
||||||
videoPlaceholder.Height = double.NaN;
|
return null;
|
||||||
videoPlaceholder.VerticalAlignment = VerticalAlignment.Stretch;
|
|
||||||
videoPlaceholder.HorizontalAlignment = HorizontalAlignment.Stretch;
|
|
||||||
videoPlaceholder.Margin = new Thickness(0);
|
|
||||||
|
|
||||||
if (videoPlaceholder.Frame.Content == null)
|
if (parameter.ToString() == SecretsVault.AccountId)
|
||||||
|
return toChannel;
|
||||||
|
else
|
||||||
|
return SecretsVault.Subscriptions.Find(i => i.Snippet.ResourceId.ChannelId == parameter.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
object GetPlaylistMenuItem(object parameter)
|
||||||
|
{
|
||||||
|
if (!SecretsVault.IsAuthorized)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if (parameter.ToString() == SecretsVault.UserChannel.ContentDetails.RelatedPlaylists.Likes)
|
||||||
|
return toLiked;
|
||||||
|
else if (parameter.Equals("WL"))
|
||||||
|
return toLater;
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Content_Navigated(Type sourcePageType, object parameter)
|
||||||
|
{
|
||||||
|
switch (sourcePageType.Name)
|
||||||
|
{
|
||||||
|
case "Settings":
|
||||||
|
nav.SelectedItem = nav.SettingsItem;
|
||||||
|
break;
|
||||||
|
case "Subscriptions":
|
||||||
|
nav.SelectedItem = toSubscriptions;
|
||||||
|
break;
|
||||||
|
case "Downloads":
|
||||||
|
nav.SelectedItem = toDownloads;
|
||||||
|
break;
|
||||||
|
case "Home":
|
||||||
|
nav.SelectedItem = toHome;
|
||||||
|
break;
|
||||||
|
case "History":
|
||||||
|
nav.SelectedItem = toHistory;
|
||||||
|
break;
|
||||||
|
case "ChannelPage":
|
||||||
|
nav.SelectedItem = GetChannelMenuItem(parameter);
|
||||||
|
break;
|
||||||
|
case "PlaylistPage":
|
||||||
|
nav.SelectedItem = GetPlaylistMenuItem(parameter);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
nav.SelectedItem = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Nav_SelectionChanged(Microsoft.UI.Xaml.Controls.NavigationView sender, Microsoft.UI.Xaml.Controls.NavigationViewSelectionChangedEventArgs args)
|
||||||
|
{
|
||||||
|
if (args.IsSettingsSelected)
|
||||||
|
content.NavigateTo(typeof(Settings));
|
||||||
|
else if (args.SelectedItem == toHome)
|
||||||
|
content.NavigateTo(typeof(Home));
|
||||||
|
else if (args.SelectedItem == toHistory)
|
||||||
|
content.NavigateTo(typeof(History));
|
||||||
|
else if (args.SelectedItem == toLiked)
|
||||||
|
content.NavigateTo(typeof(PlaylistPage), SecretsVault.UserChannel.ContentDetails.RelatedPlaylists.Likes);
|
||||||
|
else if (args.SelectedItem == toLater)
|
||||||
|
content.NavigateTo(typeof(PlaylistPage), "WL");
|
||||||
|
else if (args.SelectedItem == toSubscriptions)
|
||||||
|
content.NavigateTo(typeof(Subscriptions));
|
||||||
|
else if (args.SelectedItem == toDownloads)
|
||||||
|
content.NavigateTo(typeof(Downloads));
|
||||||
|
else if (args.SelectedItem == toChannel)
|
||||||
|
content.NavigateTo(typeof(ChannelPage), SecretsVault.UserChannel.Id);
|
||||||
|
else
|
||||||
|
content.NavigateTo(typeof(ChannelPage), (args.SelectedItem as Subscription).Snippet.ResourceId.ChannelId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Nav_BackRequested(Microsoft.UI.Xaml.Controls.NavigationView sender, Microsoft.UI.Xaml.Controls.NavigationViewBackRequestedEventArgs args) =>
|
||||||
|
content.BackRequested();
|
||||||
|
|
||||||
|
async void Search_TextChanged(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args) => await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
|
||||||
|
{
|
||||||
|
if (search.Text.Length < 3 || args.Reason != AutoSuggestionBoxTextChangeReason.UserInput)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
nav.IsBackEnabled = true;
|
|
||||||
Title.Text = resources.GetString("/Main/video");
|
|
||||||
nav.ExpandedModeThresholdWidth = short.MaxValue;
|
|
||||||
nav.IsPaneOpen = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CloseVideo()
|
|
||||||
{
|
|
||||||
if (ApplicationView.GetForCurrentView().IsFullScreenMode)
|
|
||||||
ApplicationView.GetForCurrentView().ExitFullScreenMode();
|
|
||||||
|
|
||||||
videoPlaceholder.Frame.Content = null;
|
|
||||||
GC.Collect();
|
|
||||||
MaximizeVideo();
|
|
||||||
|
|
||||||
nav.IsBackEnabled = content.Frame.CanGoBack;
|
|
||||||
|
|
||||||
SetNavigationMenu();
|
|
||||||
|
|
||||||
Title.Text = headers[content.Frame.SourcePageType];
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Search_QuerySubmitted(AutoSuggestBox sender, AutoSuggestBoxQuerySubmittedEventArgs args)
|
|
||||||
{
|
|
||||||
if(!string.IsNullOrWhiteSpace(search.Text))
|
|
||||||
GoToSearch(new SearchParameters(search.Text));
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void Search_TextChanged(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args)
|
|
||||||
{
|
|
||||||
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
|
|
||||||
{
|
|
||||||
if (search.Text.Length > 2 && args.Reason == AutoSuggestionBoxTextChangeReason.UserInput)
|
|
||||||
{
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
XmlDocument doc = new XmlDocument();
|
XmlDocument doc = new XmlDocument();
|
||||||
doc.Load($"http://suggestqueries.google.com/complete/search?ds=yt&client=toolbar&q={search.Text}&hl={SettingsStorage.RelevanceLanguage}");
|
doc.Load($"http://suggestqueries.google.com/complete/search?ds=yt&client=toolbar&q={search.Text}&hl={SettingsStorage.RelevanceLanguage}");
|
||||||
|
|
||||||
List<string> suggestions = new List<string>();
|
search.Items.Clear();
|
||||||
|
|
||||||
for (int i = 0; i < doc["toplevel"].ChildNodes.Count && i < 5; i++)
|
for (int i = 0; i < doc["toplevel"].ChildNodes.Count && i < 5; i++)
|
||||||
suggestions.Add(doc["toplevel"].ChildNodes[i]["suggestion"].GetAttribute("data"));
|
search.Items.Add(doc["toplevel"].ChildNodes[i]["suggestion"].GetAttribute("data"));
|
||||||
|
|
||||||
search.ItemsSource = suggestions;
|
|
||||||
}
|
|
||||||
catch { search.ItemsSource = new List<string>(); }
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetNavigationItem(object item)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (nav.SelectedItem != item)
|
|
||||||
nav.SelectedItem = item;
|
|
||||||
else
|
|
||||||
wasInvoked = false;
|
|
||||||
}
|
}
|
||||||
catch { }
|
catch { }
|
||||||
}
|
});
|
||||||
|
|
||||||
public void Content_Navigated(object sender, NavigationEventArgs e)
|
#region Simple UI interaction events
|
||||||
{
|
async void Feedback_Click(object sender, RoutedEventArgs e) =>
|
||||||
Title.Text = headers[content.Frame.SourcePageType];
|
await StoreServicesFeedbackLauncher.GetDefault().LaunchAsync();
|
||||||
|
|
||||||
if (!wasInvoked)
|
void RemoveAds_Tapped(object sender, TappedRoutedEventArgs e) =>
|
||||||
{
|
|
||||||
wasInvoked = true;
|
|
||||||
|
|
||||||
if (e.SourcePageType == typeof(Settings))
|
|
||||||
SetNavigationItem(nav.SettingsItem);
|
|
||||||
else if (e.SourcePageType == typeof(Subscriptions))
|
|
||||||
SetNavigationItem(toSubscriptions);
|
|
||||||
else if (e.SourcePageType == typeof(Downloads))
|
|
||||||
SetNavigationItem(toDownloads);
|
|
||||||
else if (e.SourcePageType == typeof(Home))
|
|
||||||
SetNavigationItem(toHome);
|
|
||||||
else if (e.SourcePageType == typeof(Search))
|
|
||||||
SetNavigationItem(null);
|
|
||||||
else if(e.SourcePageType == typeof(ChannelPage))
|
|
||||||
{
|
|
||||||
if (SecretsVault.IsAuthorized)
|
|
||||||
{
|
|
||||||
if (e.Parameter.ToString() == SecretsVault.AccountId)
|
|
||||||
SetNavigationItem(toChannel);
|
|
||||||
else if (nav.MenuItems.Contains(SecretsVault.Subscriptions.Find(i => i.Snippet.ResourceId.ChannelId == e.Parameter.ToString())))
|
|
||||||
SetNavigationItem(SecretsVault.Subscriptions.Find(i => i.Snippet.ResourceId.ChannelId == e.Parameter.ToString()));
|
|
||||||
else
|
|
||||||
SetNavigationItem(null);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
SetNavigationItem(null);
|
|
||||||
}
|
|
||||||
else if(e.SourcePageType == typeof(History))
|
|
||||||
SetNavigationItem(toHistory);
|
|
||||||
else if(e.SourcePageType == typeof(PlaylistPage))
|
|
||||||
{
|
|
||||||
if (SecretsVault.IsAuthorized)
|
|
||||||
{
|
|
||||||
if (e.Parameter.ToString() == SecretsVault.UserChannel.ContentDetails.RelatedPlaylists.Likes)
|
|
||||||
SetNavigationItem(toLiked);
|
|
||||||
else if (e.Parameter.Equals("WL"))
|
|
||||||
SetNavigationItem(toLater);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
SetNavigationItem(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
wasInvoked = false;
|
|
||||||
|
|
||||||
nav.IsBackEnabled = content.Frame.CanGoBack;
|
|
||||||
|
|
||||||
SetNavigationMenu();
|
|
||||||
|
|
||||||
if (videoPlaceholder.Frame.Content != null && videoPlaceholder.HorizontalAlignment == HorizontalAlignment.Stretch)
|
|
||||||
MinimizeAsInitializer();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RemoveAds_Tapped(object sender, TappedRoutedEventArgs e)
|
|
||||||
{
|
|
||||||
SecretsVault.GetAdblock();
|
SecretsVault.GetAdblock();
|
||||||
}
|
|
||||||
|
|
||||||
private void Nav_SelectionChanged(Microsoft.UI.Xaml.Controls.NavigationView sender, Microsoft.UI.Xaml.Controls.NavigationViewSelectionChangedEventArgs args)
|
void Nav_PaneClosing(Microsoft.UI.Xaml.Controls.NavigationView sender, Microsoft.UI.Xaml.Controls.NavigationViewPaneClosingEventArgs args) =>
|
||||||
{
|
|
||||||
if (!wasInvoked)
|
|
||||||
{
|
|
||||||
if (content == null)
|
|
||||||
return;
|
|
||||||
wasInvoked = true;
|
|
||||||
if (args.IsSettingsSelected)
|
|
||||||
content.Frame.Navigate(typeof(Settings));
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (args.SelectedItem == toHome)
|
|
||||||
content.Frame.Navigate(typeof(Home));
|
|
||||||
else if (args.SelectedItem == toHistory)
|
|
||||||
content.Frame.Navigate(typeof(History));
|
|
||||||
else if (args.SelectedItem == toLiked)
|
|
||||||
content.Frame.Navigate(typeof(PlaylistPage), SecretsVault.UserChannel.ContentDetails.RelatedPlaylists.Likes);
|
|
||||||
else if (args.SelectedItem == toLater)
|
|
||||||
content.Frame.Navigate(typeof(PlaylistPage), "WL");
|
|
||||||
else if (args.SelectedItem == toSubscriptions)
|
|
||||||
content.Frame.Navigate(typeof(Subscriptions));
|
|
||||||
else if (args.SelectedItem == toDownloads)
|
|
||||||
content.Frame.Navigate(typeof(Downloads));
|
|
||||||
else if (args.SelectedItem == toChannel)
|
|
||||||
content.Frame.Navigate(typeof(ChannelPage), SecretsVault.UserChannel.Id);
|
|
||||||
else
|
|
||||||
content.Frame.Navigate(typeof(ChannelPage), (args.SelectedItem as Subscription).Snippet.ResourceId.ChannelId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
wasInvoked = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Nav_BackRequested(Microsoft.UI.Xaml.Controls.NavigationView sender, Microsoft.UI.Xaml.Controls.NavigationViewBackRequestedEventArgs args)
|
|
||||||
{
|
|
||||||
if (videoPlaceholder.Frame.Content != null && double.IsNaN(videoPlaceholder.Width))
|
|
||||||
{
|
|
||||||
if (videoPlaceholder.Frame.CanGoBack)
|
|
||||||
videoPlaceholder.Frame.GoBack();
|
|
||||||
else if (videoPlaceholder.LoadingPage.State != LoadingState.Loaded)
|
|
||||||
CloseVideo();
|
|
||||||
else
|
|
||||||
MinimizeAsInitializer();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
content.Frame.GoBack();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Nav_PaneClosing(Microsoft.UI.Xaml.Controls.NavigationView sender, Microsoft.UI.Xaml.Controls.NavigationViewPaneClosingEventArgs args)
|
|
||||||
{
|
|
||||||
AppTitle.Visibility = Visibility.Collapsed;
|
AppTitle.Visibility = Visibility.Collapsed;
|
||||||
}
|
|
||||||
|
|
||||||
private void Nav_PaneOpened(Microsoft.UI.Xaml.Controls.NavigationView sender, object args)
|
void Nav_PaneOpened(Microsoft.UI.Xaml.Controls.NavigationView sender, object args) =>
|
||||||
{
|
|
||||||
AppTitle.Visibility = Visibility.Visible;
|
AppTitle.Visibility = Visibility.Visible;
|
||||||
|
|
||||||
|
void Search_QuerySubmitted(AutoSuggestBox sender, AutoSuggestBoxQuerySubmittedEventArgs args)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(search.Text))
|
||||||
|
Navigation.GoToSearch(new SearchParameters(search.Text));
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,12 +40,12 @@
|
|||||||
<RowDefinition Height="auto"/>
|
<RowDefinition Height="auto"/>
|
||||||
<RowDefinition/>
|
<RowDefinition/>
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<StackPanel Grid.Row="0" Margin="10" Grid.Column="1" x:Name="cover" HorizontalAlignment="Left">
|
<StackPanel Margin="10" Grid.Column="1" x:Name="cover" HorizontalAlignment="Left">
|
||||||
<Image Source="/Assets/videoThumbSample.png" Name="thumbnail"/>
|
<Image Source="/Assets/videoThumbSample.png" Name="thumbnail"/>
|
||||||
<TextBlock FontSize="20" Text="[Title]" TextWrapping="WrapWholeWords" Name="title"/>
|
<TextBlock FontSize="20" Text="[Title]" TextWrapping="WrapWholeWords" Name="title"/>
|
||||||
<TextBlock Foreground="Gray" Text="# videos | # views | Updated at: ##-##-## ##:##:##" TextWrapping="WrapWholeWords" Name="info"/>
|
<TextBlock Foreground="Gray" Text="# videos | # views | Updated at: ##-##-## ##:##:##" TextWrapping="WrapWholeWords" Name="info"/>
|
||||||
<TextBlock Foreground="Gray" Text="description" TextWrapping="WrapWholeWords" Name="description"/>
|
<TextBlock Foreground="Gray" Text="description" TextWrapping="WrapWholeWords" Name="description"/>
|
||||||
<Button Margin="10" Background="Transparent" Name="toChannel" Click="toChannel_Click">
|
<Button Margin="0,10" Background="Transparent" Name="toChannel" Click="toChannel_Click">
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="Auto"/>
|
<ColumnDefinition Width="Auto"/>
|
||||||
@@ -79,13 +79,6 @@
|
|||||||
|
|
||||||
<classes:AdaptiveCommandBar Grid.Row="2">
|
<classes:AdaptiveCommandBar Grid.Row="2">
|
||||||
<AppBarButton x:Uid="/Playlist/openWeb" Icon="Globe" Label="Open in browser" Name="inBrowser" Click="inBrowser_Click"/>
|
<AppBarButton x:Uid="/Playlist/openWeb" Icon="Globe" Label="Open in browser" Name="inBrowser" Click="inBrowser_Click"/>
|
||||||
<AppBarButton x:Uid="/Playlist/addTo" Icon="Add" Label="Add to" IsEnabled="False" Visibility="Collapsed">
|
|
||||||
<AppBarButton.Flyout>
|
|
||||||
<MenuFlyout>
|
|
||||||
|
|
||||||
</MenuFlyout>
|
|
||||||
</AppBarButton.Flyout>
|
|
||||||
</AppBarButton>
|
|
||||||
<AppBarButton x:Uid="/Playlist/refresh" Icon="Refresh" Label="Refresh" Name="refresh" Click="refresh_Click"/>
|
<AppBarButton x:Uid="/Playlist/refresh" Icon="Refresh" Label="Refresh" Name="refresh" Click="refresh_Click"/>
|
||||||
<AppBarButton x:Uid="/Playlist/share" Icon="Share" Label="Share" Name="share" Click="share_Click"/>
|
<AppBarButton x:Uid="/Playlist/share" Icon="Share" Label="Share" Name="share" Click="share_Click"/>
|
||||||
</classes:AdaptiveCommandBar>
|
</classes:AdaptiveCommandBar>
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
using FoxTube.Controls;
|
using FoxTube.Classes;
|
||||||
using Google.Apis.YouTube.v3;
|
using FoxTube.Controls;
|
||||||
using Google.Apis.YouTube.v3.Data;
|
|
||||||
using Microsoft.AppCenter.Analytics;
|
using Microsoft.AppCenter.Analytics;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using Windows.ApplicationModel.DataTransfer;
|
using Windows.ApplicationModel.DataTransfer;
|
||||||
using Windows.ApplicationModel.Resources;
|
using Windows.ApplicationModel.Resources;
|
||||||
using Windows.Foundation;
|
using Windows.Foundation;
|
||||||
@@ -13,6 +11,8 @@ using Windows.UI.Xaml;
|
|||||||
using Windows.UI.Xaml.Controls;
|
using Windows.UI.Xaml.Controls;
|
||||||
using Windows.UI.Xaml.Media.Imaging;
|
using Windows.UI.Xaml.Media.Imaging;
|
||||||
using Windows.UI.Xaml.Navigation;
|
using Windows.UI.Xaml.Navigation;
|
||||||
|
using YoutubeExplode.Models;
|
||||||
|
using YoutubeExplode;
|
||||||
|
|
||||||
namespace FoxTube.Pages
|
namespace FoxTube.Pages
|
||||||
{
|
{
|
||||||
@@ -22,196 +22,120 @@ namespace FoxTube.Pages
|
|||||||
public sealed partial class PlaylistPage : Page, INavigationPage
|
public sealed partial class PlaylistPage : Page, INavigationPage
|
||||||
{
|
{
|
||||||
public object Parameter { get; set; } = null;
|
public object Parameter { get; set; } = null;
|
||||||
public string playlistId;
|
|
||||||
|
string authorId;
|
||||||
Playlist item;
|
Playlist item;
|
||||||
|
|
||||||
PlaylistItemsResource.ListRequest request;
|
|
||||||
string token;
|
|
||||||
int page = 1;
|
int page = 1;
|
||||||
|
|
||||||
public PlaylistPage()
|
public PlaylistPage() =>
|
||||||
{
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||||
{
|
{
|
||||||
base.OnNavigatedTo(e);
|
base.OnNavigatedTo(e);
|
||||||
Parameter = e.Parameter;
|
Parameter = e.Parameter;
|
||||||
|
|
||||||
if (e.Parameter as string == "WL")
|
|
||||||
LoadWL();
|
|
||||||
else
|
|
||||||
Initialize(e.Parameter as string);
|
Initialize(e.Parameter as string);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void Initialize(string id)
|
async void Initialize(string id)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
playlistId = id;
|
SecretsVault.RefreshToken();
|
||||||
|
item = await new YoutubeClient(SecretsVault.HttpClient).GetPlaylistAsync(id);
|
||||||
|
|
||||||
PlaylistsResource.ListRequest infoRequest = SecretsVault.Service.Playlists.List("snippet,contentDetails");
|
if (id == "WL")
|
||||||
|
{
|
||||||
|
SecretsVault.WatchLater = item;
|
||||||
|
share.Visibility = Visibility.Collapsed;
|
||||||
|
wlAlert.Visibility = Visibility.Visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
title.Text = item.Title;
|
||||||
|
info.Text = $"{item.Videos.Count} {ResourceLoader.GetForCurrentView("Playlist").GetString("/Playlist/videos")} | {item.Statistics.ViewCount} {ResourceLoader.GetForCurrentView("Cards").GetString("/Cards/views")}";
|
||||||
|
description.Text = item.Description;
|
||||||
|
|
||||||
|
channelName.Text = item.Author;
|
||||||
|
|
||||||
|
Google.Apis.YouTube.v3.PlaylistsResource.ListRequest infoRequest = SecretsVault.Service.Playlists.List("snippet");
|
||||||
infoRequest.Id = id;
|
infoRequest.Id = id;
|
||||||
infoRequest.Hl = SettingsStorage.RelevanceLanguage;
|
authorId = (await infoRequest.ExecuteAsync()).Items[0].Snippet.ChannelId;
|
||||||
|
|
||||||
item = (await infoRequest.ExecuteAsync()).Items[0];
|
|
||||||
|
|
||||||
title.Text = item.Snippet.Localized.Title;
|
|
||||||
info.Text = $"{item.ContentDetails.ItemCount} {ResourceLoader.GetForCurrentView("Playlist").GetString("/Playlist/videos")}";
|
|
||||||
description.Text = item.Snippet.Localized.Description;
|
|
||||||
|
|
||||||
channelName.Text = Methods.GuardFromNull(item.Snippet.ChannelTitle);
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
thumbnail.Source = new BitmapImage(item.Snippet.Thumbnails.Medium.Url.ToUri());
|
thumbnail.Source = new BitmapImage((item.Videos.Count > 0 ? item.Videos[0].Thumbnails.MediumResUrl : "/Assets/videoThumbSample.png").ToUri());
|
||||||
avatar.ProfilePicture = new BitmapImage((await new YoutubeExplode.YoutubeClient().GetChannelAsync(item.Snippet.ChannelId)).LogoUrl.ToUri()) { DecodePixelWidth = 50, DecodePixelHeight = 50 };
|
avatar.ProfilePicture = new BitmapImage((await new YoutubeClient(SecretsVault.HttpClient).GetChannelAsync(authorId)).LogoUrl.ToUri()) { DecodePixelHeight = 50, DecodePixelWidth = 50 };
|
||||||
}
|
}
|
||||||
catch { }
|
catch { }
|
||||||
|
|
||||||
request = SecretsVault.Service.PlaylistItems.List("contentDetails");
|
for (int k = 0; k < 25 && k < item.Videos.Count; k++)
|
||||||
request.PlaylistId = id;
|
list.Add(new VideoCard(item.Videos[k].Id, "WL"));
|
||||||
request.MaxResults = 25;
|
|
||||||
|
|
||||||
PlaylistItemListResponse response = await request.ExecuteAsync();
|
if (list.Count >= item.Videos.Count)
|
||||||
token = response.NextPageToken;
|
|
||||||
if (string.IsNullOrWhiteSpace(token))
|
|
||||||
more.Visibility = Visibility.Collapsed;
|
more.Visibility = Visibility.Collapsed;
|
||||||
|
|
||||||
foreach (PlaylistItem i in response.Items)
|
Navigation.Frame.Frame.LoadingPage.Close();
|
||||||
list.Add(new VideoCard(i.ContentDetails.VideoId, playlistId));
|
|
||||||
|
|
||||||
Methods.MainPage.PageContent.LoadingPage.Close();
|
|
||||||
}
|
}
|
||||||
catch (System.Net.Http.HttpRequestException)
|
catch (System.Net.Http.HttpRequestException)
|
||||||
{
|
{
|
||||||
Methods.MainPage.PageContent.LoadingPage.Error("System.Net.Http.HttpRequestException", "Unable to connect to Google servers.", true);
|
Navigation.Frame.Frame.LoadingPage.Error("System.Net.Http.HttpRequestException", "Unable to connect to Google servers.", true);
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Methods.MainPage.PageContent.LoadingPage.Error(e.GetType().ToString(), e.Message);
|
|
||||||
Analytics.TrackEvent("Playlist loading error", new Dictionary<string, string>()
|
|
||||||
{
|
|
||||||
{ "Exception", e.GetType().ToString() },
|
|
||||||
{ "Message", e.Message },
|
|
||||||
{ "Playlist ID", playlistId },
|
|
||||||
{ "StackTrace", e.StackTrace }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async void LoadWL()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
playlistId = "WL";
|
|
||||||
share.Visibility = Visibility.Collapsed;
|
|
||||||
wlAlert.Visibility = Visibility.Visible;
|
|
||||||
|
|
||||||
SecretsVault.WatchLater = await Methods.GetLater();
|
|
||||||
|
|
||||||
title.Text = ResourceLoader.GetForCurrentView("Main").GetString("/Main/later/Content");
|
|
||||||
info.Text = $"{SecretsVault.WatchLater.Count} {ResourceLoader.GetForCurrentView("Playlist").GetString("/Playlist/videos")}";
|
|
||||||
description.Text = "";
|
|
||||||
|
|
||||||
channelName.Text = SecretsVault.UserChannel.Snippet.Title;
|
|
||||||
|
|
||||||
avatar.ProfilePicture = new BitmapImage(SecretsVault.UserChannel.Snippet.Thumbnails.Medium.Url.ToUri()) { DecodePixelWidth = 50, DecodePixelHeight = 50 };
|
|
||||||
thumbnail.Source = new BitmapImage((await new YoutubeExplode.YoutubeClient().GetVideoAsync(SecretsVault.WatchLater.First())).Thumbnails.HighResUrl.ToUri());
|
|
||||||
|
|
||||||
for (int k = 0; k < 25 && k < SecretsVault.WatchLater.Count; k++)
|
|
||||||
list.Add(new VideoCard(SecretsVault.WatchLater[k], "WL"));
|
|
||||||
|
|
||||||
if (list.Count >= SecretsVault.WatchLater.Count)
|
|
||||||
more.Visibility = Visibility.Collapsed;
|
|
||||||
|
|
||||||
Methods.MainPage.PageContent.LoadingPage.Close();
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
if (item == null)
|
if (item == null)
|
||||||
{
|
{
|
||||||
Methods.MainPage.PageContent.LoadingPage.Error("PlaylistNotFound", "Such playlist doesn't exist");
|
Navigation.Frame.Frame.LoadingPage.Error("PlaylistNotFound", "Such playlist doesn't exist");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Methods.MainPage.PageContent.LoadingPage.Error(e.GetType().ToString(), e.Message);
|
Navigation.Frame.Frame.LoadingPage.Error(e.GetType().ToString(), e.Message);
|
||||||
Analytics.TrackEvent("WL playlist loading error", new Dictionary<string, string>()
|
Analytics.TrackEvent("Playlist loading error", new Dictionary<string, string>()
|
||||||
{
|
{
|
||||||
{ "Exception", e.GetType().ToString() },
|
{ "Exception", e.GetType().ToString() },
|
||||||
{ "Message", e.Message },
|
{ "Message", e.Message },
|
||||||
|
{ "Playlist ID", item.Id },
|
||||||
{ "StackTrace", e.StackTrace }
|
{ "StackTrace", e.StackTrace }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void toChannel_Click(object sender, RoutedEventArgs e)
|
void toChannel_Click(object sender, RoutedEventArgs e) =>
|
||||||
{
|
Navigation.GoToChannel(authorId);
|
||||||
Methods.MainPage.GoToChannel(item.Snippet.ChannelId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void inBrowser_Click(object sender, RoutedEventArgs e)
|
async void inBrowser_Click(object sender, RoutedEventArgs e) =>
|
||||||
{
|
await Launcher.LaunchUriAsync(item.GetUrl().ToUri());
|
||||||
await Launcher.LaunchUriAsync(new Uri($"https://www.youtube.com/playlist?list={item.Id}"));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void refresh_Click(object sender, RoutedEventArgs e)
|
void refresh_Click(object sender, RoutedEventArgs e) =>
|
||||||
{
|
Navigation.Frame.Refresh();
|
||||||
Methods.MainPage.PageContent.Refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void share_Click(object sender, RoutedEventArgs e)
|
void share_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
DataTransferManager.GetForCurrentView().DataRequested += new TypedEventHandler<DataTransferManager, DataRequestedEventArgs>(Share);
|
DataTransferManager.GetForCurrentView().DataRequested += new TypedEventHandler<DataTransferManager, DataRequestedEventArgs>(Share);
|
||||||
DataTransferManager.ShowShareUI();
|
DataTransferManager.ShowShareUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Share(DataTransferManager sender, DataRequestedEventArgs args)
|
void Share(DataTransferManager sender, DataRequestedEventArgs args)
|
||||||
{
|
{
|
||||||
Methods.Share(args,
|
Methods.Share(args,
|
||||||
item.Snippet.Thumbnails.Medium.Url,
|
(thumbnail.Source as BitmapImage).UriSource.AbsoluteUri,
|
||||||
item.Snippet.Title,
|
item.Title,
|
||||||
$"https://www.youtube.com/playlist?list={item.Id}",
|
item.GetUrl(),
|
||||||
ResourceLoader.GetForCurrentView("Cards").GetString("/Cards/playlistShare"));
|
ResourceLoader.GetForCurrentView("Cards").GetString("/Cards/playlistShare"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void ShowMore_Clicked()
|
void ShowMore_Clicked()
|
||||||
{
|
{
|
||||||
if(playlistId == "WL")
|
for (int k = 25 * page++; k < 25 * page && k < item.Videos.Count; k++)
|
||||||
{
|
list.Add(new VideoCard(item.Videos[k].Id, "WL"));
|
||||||
MoreWL();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
request.PageToken = token;
|
if (list.Count >= item.Videos.Count)
|
||||||
PlaylistItemListResponse response = await request.ExecuteAsync();
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(request.PageToken))
|
|
||||||
more.Visibility = Visibility.Collapsed;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
token = response.NextPageToken;
|
|
||||||
more.Complete();
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (PlaylistItem i in response.Items)
|
|
||||||
list.Add(new VideoCard(i.ContentDetails.VideoId, playlistId));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MoreWL()
|
|
||||||
{
|
|
||||||
for (int k = 25 * page++; k < 25 * page && k < SecretsVault.WatchLater.Count; k++)
|
|
||||||
list.Add(new VideoCard(SecretsVault.WatchLater[k], "WL"));
|
|
||||||
|
|
||||||
if (list.Count >= SecretsVault.WatchLater.Count)
|
|
||||||
more.Visibility = Visibility.Collapsed;
|
more.Visibility = Visibility.Collapsed;
|
||||||
else
|
else
|
||||||
more.Complete();
|
more.Complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DeleteItem(FrameworkElement card)
|
public void DeleteItem(FrameworkElement card) =>
|
||||||
{
|
|
||||||
list.DeleteItem(card);
|
list.DeleteItem(card);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
x:Class="FoxTube.Search"
|
x:Class="FoxTube.Search"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:local="using:FoxTube"
|
|
||||||
xmlns:pages="using:FoxTube.Pages"
|
xmlns:pages="using:FoxTube.Pages"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ using Windows.System;
|
|||||||
using Windows.ApplicationModel.Resources;
|
using Windows.ApplicationModel.Resources;
|
||||||
using Microsoft.AppCenter.Analytics;
|
using Microsoft.AppCenter.Analytics;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using FoxTube.Classes;
|
||||||
|
|
||||||
namespace FoxTube
|
namespace FoxTube
|
||||||
{
|
{
|
||||||
@@ -26,41 +27,9 @@ namespace FoxTube
|
|||||||
SearchResource.ListRequest request;
|
SearchResource.ListRequest request;
|
||||||
string nextToken;
|
string nextToken;
|
||||||
|
|
||||||
public Search()
|
public Search() =>
|
||||||
{
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
|
||||||
|
|
||||||
public string SetResults(int? count)
|
|
||||||
{
|
|
||||||
if (count == 1000000)
|
|
||||||
return count + "+";
|
|
||||||
else if (count == null)
|
|
||||||
return "0";
|
|
||||||
else
|
|
||||||
return count.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddItem(SearchResult result)
|
|
||||||
{
|
|
||||||
switch (result.Id.Kind)
|
|
||||||
{
|
|
||||||
case "youtube#video":
|
|
||||||
VideoCard vCard = new VideoCard(result.Id.VideoId);
|
|
||||||
list.Add(vCard);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "youtube#channel":
|
|
||||||
if(Parameters.Channel == null)
|
|
||||||
list.Add(new ChannelCard(result.Id.ChannelId, result.Snippet.LiveBroadcastContent));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "youtube#playlist":
|
|
||||||
PlaylistCard pCard = new PlaylistCard(result.Id.PlaylistId);
|
|
||||||
list.Add(pCard);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||||
{
|
{
|
||||||
@@ -128,7 +97,7 @@ namespace FoxTube
|
|||||||
features.SelectedItems.Add(features.Items[4]);
|
features.SelectedItems.Add(features.Items[4]);
|
||||||
|
|
||||||
SearchListResponse response = await request.ExecuteAsync();
|
SearchListResponse response = await request.ExecuteAsync();
|
||||||
resultsCount.Text = $"{resources.GetString("/Search/found")}: {SetResults(response.PageInfo.TotalResults)} {resources.GetString("/Search/items")}";
|
resultsCount.Text = $"{resources.GetString("/Search/found")}: {GetResultsCout(response.PageInfo.TotalResults)} {resources.GetString("/Search/items")}";
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(response.NextPageToken))
|
if (!string.IsNullOrWhiteSpace(response.NextPageToken))
|
||||||
nextToken = response.NextPageToken;
|
nextToken = response.NextPageToken;
|
||||||
@@ -158,7 +127,38 @@ namespace FoxTube
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ToggleFilters_Click(object sender, RoutedEventArgs e)
|
public void AddItem(SearchResult result)
|
||||||
|
{
|
||||||
|
switch (result.Id.Kind)
|
||||||
|
{
|
||||||
|
case "youtube#video":
|
||||||
|
VideoCard vCard = new VideoCard(result.Id.VideoId);
|
||||||
|
list.Add(vCard);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "youtube#channel":
|
||||||
|
if (Parameters.Channel == null)
|
||||||
|
list.Add(new ChannelCard(result.Id.ChannelId, result.Snippet.LiveBroadcastContent));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "youtube#playlist":
|
||||||
|
PlaylistCard pCard = new PlaylistCard(result.Id.PlaylistId);
|
||||||
|
list.Add(pCard);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetResultsCout(int? count)
|
||||||
|
{
|
||||||
|
if (count == 1000000)
|
||||||
|
return count + "+";
|
||||||
|
else if (count == null)
|
||||||
|
return "0";
|
||||||
|
else
|
||||||
|
return count.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToggleFilters_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
if(filters.Visibility == Visibility.Collapsed)
|
if(filters.Visibility == Visibility.Collapsed)
|
||||||
{
|
{
|
||||||
@@ -172,28 +172,25 @@ namespace FoxTube
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AppBarButton_Click(object sender, RoutedEventArgs e)
|
void AppBarButton_Click(object sender, RoutedEventArgs e) =>
|
||||||
{
|
|
||||||
frame.Refresh();
|
frame.Refresh();
|
||||||
}
|
|
||||||
|
|
||||||
private async void More_Clicked()
|
async void More_Clicked()
|
||||||
{
|
{
|
||||||
request.PageToken = nextToken;
|
request.PageToken = nextToken;
|
||||||
SearchListResponse response = await request.ExecuteAsync();
|
SearchListResponse response = await request.ExecuteAsync();
|
||||||
|
nextToken = response.NextPageToken;
|
||||||
|
|
||||||
foreach (SearchResult item in response.Items)
|
foreach (SearchResult item in response.Items)
|
||||||
AddItem(item);
|
AddItem(item);
|
||||||
|
|
||||||
if (response.NextPageToken != null)
|
if (!string.IsNullOrWhiteSpace(nextToken))
|
||||||
{
|
|
||||||
nextToken = response.NextPageToken;
|
|
||||||
more.Complete();
|
more.Complete();
|
||||||
}
|
|
||||||
else
|
else
|
||||||
more.Visibility = Visibility.Collapsed;
|
more.Visibility = Visibility.Collapsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Type_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
void Type_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -213,12 +210,7 @@ namespace FoxTube
|
|||||||
catch (NullReferenceException) { }
|
catch (NullReferenceException) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void InBrowser_Click(object sender, RoutedEventArgs e)
|
void Apply_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
|
||||||
await Launcher.LaunchUriAsync(new Uri($"https://www.youtube.com/results?search_query={searchTerm}"));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Apply_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
{
|
||||||
Parameters.Filter.HD = features.SelectedItems.Contains(features.Items[0]);
|
Parameters.Filter.HD = features.SelectedItems.Contains(features.Items[0]);
|
||||||
Parameters.Filter.Is3D = features.SelectedItems.Contains(features.Items[1]);
|
Parameters.Filter.Is3D = features.SelectedItems.Contains(features.Items[1]);
|
||||||
@@ -231,7 +223,11 @@ namespace FoxTube
|
|||||||
Parameters.Filter.Date = (SearchParameters.Filters.Enumerations.Date)date.SelectedIndex;
|
Parameters.Filter.Date = (SearchParameters.Filters.Enumerations.Date)date.SelectedIndex;
|
||||||
Parameters.Filter.Duration = (SearchParameters.Filters.Enumerations.Duration)duration.SelectedIndex;
|
Parameters.Filter.Duration = (SearchParameters.Filters.Enumerations.Duration)duration.SelectedIndex;
|
||||||
|
|
||||||
|
frame.LoadingPage.Refresh();
|
||||||
Initialize(Parameters);
|
Initialize(Parameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async void InBrowser_Click(object sender, RoutedEventArgs e) =>
|
||||||
|
await Launcher.LaunchUriAsync($"https://www.youtube.com/results?search_query={searchTerm}".ToUri());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,9 +5,9 @@
|
|||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:settingspages="using:FoxTube.Pages.SettingsPages"
|
xmlns:settingspages="using:FoxTube.Pages.SettingsPages"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d"
|
||||||
|
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||||
|
|
||||||
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
|
||||||
<Pivot SelectedIndex="0" Name="pivot" IsHeaderItemsCarouselEnabled="False" SelectionChanged="Pivot_SelectionChanged">
|
<Pivot SelectedIndex="0" Name="pivot" IsHeaderItemsCarouselEnabled="False" SelectionChanged="Pivot_SelectionChanged">
|
||||||
<PivotItem Name="generalTab" Header="General" x:Uid="/Settings/general">
|
<PivotItem Name="generalTab" Header="General" x:Uid="/Settings/general">
|
||||||
<ScrollViewer>
|
<ScrollViewer>
|
||||||
@@ -30,5 +30,4 @@
|
|||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</PivotItem>
|
</PivotItem>
|
||||||
</Pivot>
|
</Pivot>
|
||||||
</Grid>
|
|
||||||
</Page>
|
</Page>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using Windows.UI.Xaml.Controls;
|
using Windows.UI.Xaml.Controls;
|
||||||
using Windows.UI.Xaml.Navigation;
|
using Windows.UI.Xaml.Navigation;
|
||||||
using FoxTube.Pages.SettingsPages;
|
using FoxTube.Pages.SettingsPages;
|
||||||
|
using FoxTube.Classes;
|
||||||
|
|
||||||
namespace FoxTube
|
namespace FoxTube
|
||||||
{
|
{
|
||||||
@@ -13,10 +14,8 @@ namespace FoxTube
|
|||||||
|
|
||||||
bool inboxLoaded = false;
|
bool inboxLoaded = false;
|
||||||
string inboxId = null;
|
string inboxId = null;
|
||||||
public Settings()
|
public Settings() =>
|
||||||
{
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||||
{
|
{
|
||||||
@@ -38,10 +37,10 @@ namespace FoxTube
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Methods.MainPage.PageContent.LoadingPage.Close();
|
Navigation.Frame.Frame.LoadingPage.Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Pivot_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
void Pivot_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||||
{
|
{
|
||||||
if (pivot.SelectedItem == inboxTab && !inboxLoaded)
|
if (pivot.SelectedItem == inboxTab && !inboxLoaded)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -24,9 +24,7 @@ namespace FoxTube.Pages.SettingsPages
|
|||||||
feedback.Visibility = Visibility.Visible;
|
feedback.Visibility = Visibility.Visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void Button_Click(object sender, RoutedEventArgs e)
|
async void Button_Click(object sender, RoutedEventArgs e) =>
|
||||||
{
|
|
||||||
await StoreServicesFeedbackLauncher.GetDefault().LaunchAsync();
|
await StoreServicesFeedbackLauncher.GetDefault().LaunchAsync();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ namespace FoxTube.Pages.SettingsPages
|
|||||||
relLanguage.SelectedItem = relLanguage.Items.Find(i => ((ComboBoxItem)i).Tag as string == SettingsStorage.RelevanceLanguage);
|
relLanguage.SelectedItem = relLanguage.Items.Find(i => ((ComboBoxItem)i).Tag as string == SettingsStorage.RelevanceLanguage);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void language_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
void language_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||||
{
|
{
|
||||||
if ((language.SelectedItem as ComboBoxItem).Tag.ToString() == SettingsStorage.Language)
|
if ((language.SelectedItem as ComboBoxItem).Tag.ToString() == SettingsStorage.Language)
|
||||||
return;
|
return;
|
||||||
@@ -88,47 +88,31 @@ namespace FoxTube.Pages.SettingsPages
|
|||||||
restartNote.Visibility = Visibility.Visible;
|
restartNote.Visibility = Visibility.Visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void quality_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
void quality_SelectionChanged(object sender, SelectionChangedEventArgs e) =>
|
||||||
{
|
|
||||||
SettingsStorage.VideoQuality = (quality.SelectedItem as ComboBoxItem).Tag as string;
|
SettingsStorage.VideoQuality = (quality.SelectedItem as ComboBoxItem).Tag as string;
|
||||||
}
|
|
||||||
|
|
||||||
private void mobileWarning_Toggled(object sender, RoutedEventArgs e)
|
void mobileWarning_Toggled(object sender, RoutedEventArgs e) =>
|
||||||
{
|
|
||||||
SettingsStorage.CheckConnection = mobileWarning.IsOn;
|
SettingsStorage.CheckConnection = mobileWarning.IsOn;
|
||||||
}
|
|
||||||
|
|
||||||
private void autoplay_Toggled(object sender, RoutedEventArgs e)
|
void autoplay_Toggled(object sender, RoutedEventArgs e) =>
|
||||||
{
|
|
||||||
SettingsStorage.Autoplay = autoplay.IsOn;
|
SettingsStorage.Autoplay = autoplay.IsOn;
|
||||||
}
|
|
||||||
|
|
||||||
private void notification_IsEnabledChanged(object sender, RoutedEventArgs e)
|
void notification_IsEnabledChanged(object sender, RoutedEventArgs e) =>
|
||||||
{
|
|
||||||
SettingsStorage.VideoNotifications = newVideo.IsOn;
|
SettingsStorage.VideoNotifications = newVideo.IsOn;
|
||||||
}
|
|
||||||
|
|
||||||
private void devNews_Toggled(object sender, RoutedEventArgs e)
|
void devNews_Toggled(object sender, RoutedEventArgs e) =>
|
||||||
{
|
|
||||||
SettingsStorage.DevNotifications = devNews.IsOn;
|
SettingsStorage.DevNotifications = devNews.IsOn;
|
||||||
}
|
|
||||||
|
|
||||||
private void RelLanguage_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
void RelLanguage_SelectionChanged(object sender, SelectionChangedEventArgs e) =>
|
||||||
{
|
|
||||||
SettingsStorage.RelevanceLanguage = ((ComboBoxItem)relLanguage.SelectedItem).Tag.ToString();
|
SettingsStorage.RelevanceLanguage = ((ComboBoxItem)relLanguage.SelectedItem).Tag.ToString();
|
||||||
}
|
|
||||||
|
|
||||||
private void region_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
void region_SelectionChanged(object sender, SelectionChangedEventArgs e) =>
|
||||||
{
|
|
||||||
SettingsStorage.Region = ((ComboBoxItem)region.SelectedItem).Tag.ToString();
|
SettingsStorage.Region = ((ComboBoxItem)region.SelectedItem).Tag.ToString();
|
||||||
}
|
|
||||||
|
|
||||||
private void safeSearch_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
void safeSearch_SelectionChanged(object sender, SelectionChangedEventArgs e) =>
|
||||||
{
|
|
||||||
SettingsStorage.SafeSearch = safeSearch.SelectedIndex;
|
SettingsStorage.SafeSearch = safeSearch.SelectedIndex;
|
||||||
}
|
|
||||||
|
|
||||||
private void RadioButton_Checked(object sender, RoutedEventArgs e)
|
void RadioButton_Checked(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
if (sender == light)
|
if (sender == light)
|
||||||
{
|
{
|
||||||
@@ -151,19 +135,13 @@ namespace FoxTube.Pages.SettingsPages
|
|||||||
Methods.MainPage.SetTitleBar();
|
Methods.MainPage.SetTitleBar();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Button_Click(object sender, RoutedEventArgs e)
|
void Button_Click(object sender, RoutedEventArgs e) =>
|
||||||
{
|
|
||||||
CoreApplication.Exit();
|
CoreApplication.Exit();
|
||||||
}
|
|
||||||
|
|
||||||
private void MinimizedCB_Toggled(object sender, RoutedEventArgs e)
|
void MinimizedCB_Toggled(object sender, RoutedEventArgs e) =>
|
||||||
{
|
|
||||||
SettingsStorage.AppBarClosedMode = minimizedCB.IsOn ? AppBarClosedDisplayMode.Minimal : AppBarClosedDisplayMode.Compact;
|
SettingsStorage.AppBarClosedMode = minimizedCB.IsOn ? AppBarClosedDisplayMode.Minimal : AppBarClosedDisplayMode.Compact;
|
||||||
}
|
|
||||||
|
|
||||||
private void ClipboardProcessing_Toggled(object sender, RoutedEventArgs e)
|
void ClipboardProcessing_Toggled(object sender, RoutedEventArgs e) =>
|
||||||
{
|
|
||||||
SettingsStorage.ProcessClipboard = clipboardProcessing.IsOn;
|
SettingsStorage.ProcessClipboard = clipboardProcessing.IsOn;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ namespace FoxTube.Pages.SettingsPages
|
|||||||
list.SelectedItem = items.Find(i => i.Id == id);
|
list.SelectedItem = items.Find(i => i.Id == id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void filter_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
void filter_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||||
{
|
{
|
||||||
if (list == null)
|
if (list == null)
|
||||||
return;
|
return;
|
||||||
@@ -98,7 +98,7 @@ namespace FoxTube.Pages.SettingsPages
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void list_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
void list_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||||
{
|
{
|
||||||
if (!(list.SelectedItem is InboxItem item))
|
if (!(list.SelectedItem is InboxItem item))
|
||||||
return;
|
return;
|
||||||
@@ -133,20 +133,16 @@ namespace FoxTube.Pages.SettingsPages
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void close_Click(object sender, RoutedEventArgs e)
|
void close_Click(object sender, RoutedEventArgs e) =>
|
||||||
{
|
|
||||||
CloseView();
|
CloseView();
|
||||||
}
|
|
||||||
|
|
||||||
private void VisualStateGroup_CurrentStateChanged(object sender, VisualStateChangedEventArgs e)
|
void VisualStateGroup_CurrentStateChanged(object sender, VisualStateChangedEventArgs e)
|
||||||
{
|
{
|
||||||
if (e.NewState == null)
|
if (e.NewState == null)
|
||||||
CloseView();
|
CloseView();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Content_LinkClicked(object sender, Microsoft.Toolkit.Uwp.UI.Controls.LinkClickedEventArgs e)
|
void Content_LinkClicked(object sender, Microsoft.Toolkit.Uwp.UI.Controls.LinkClickedEventArgs e) =>
|
||||||
{
|
|
||||||
Methods.ProcessLink(e.Link);
|
Methods.ProcessLink(e.Link);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ namespace FoxTube.Pages.SettingsPages
|
|||||||
{
|
{
|
||||||
public sealed partial class Translate : Page
|
public sealed partial class Translate : Page
|
||||||
{
|
{
|
||||||
//TODO: Localize page
|
|
||||||
ResourceLoader resources = ResourceLoader.GetForCurrentView("Translate");
|
ResourceLoader resources = ResourceLoader.GetForCurrentView("Translate");
|
||||||
StorageFile submission;
|
StorageFile submission;
|
||||||
public Translate()
|
public Translate()
|
||||||
@@ -31,7 +30,7 @@ namespace FoxTube.Pages.SettingsPages
|
|||||||
LangList.Items.Add(culture);
|
LangList.Items.Add(culture);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void export_Click(object sender, RoutedEventArgs e)
|
async void export_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
FileSavePicker picker = new FileSavePicker();
|
FileSavePicker picker = new FileSavePicker();
|
||||||
picker.CommitButtonText = resources.GetString("/Translate/exportPicker");
|
picker.CommitButtonText = resources.GetString("/Translate/exportPicker");
|
||||||
@@ -49,7 +48,7 @@ namespace FoxTube.Pages.SettingsPages
|
|||||||
await Launcher.LaunchFileAsync(file);
|
await Launcher.LaunchFileAsync(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LangList_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
void LangList_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||||
{
|
{
|
||||||
greenResult.Visibility = Visibility.Collapsed;
|
greenResult.Visibility = Visibility.Collapsed;
|
||||||
certification.Visibility = Visibility.Collapsed;
|
certification.Visibility = Visibility.Collapsed;
|
||||||
@@ -59,7 +58,7 @@ namespace FoxTube.Pages.SettingsPages
|
|||||||
export.IsEnabled = true;
|
export.IsEnabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void upload_Click(object sender, RoutedEventArgs e)
|
async void upload_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
FileOpenPicker picker = new FileOpenPicker()
|
FileOpenPicker picker = new FileOpenPicker()
|
||||||
{
|
{
|
||||||
@@ -156,12 +155,10 @@ namespace FoxTube.Pages.SettingsPages
|
|||||||
return report;
|
return report;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void Log_Click(object sender, RoutedEventArgs e)
|
async void Log_Click(object sender, RoutedEventArgs e) =>
|
||||||
{
|
|
||||||
await Launcher.LaunchFileAsync(((Button)sender).Tag as StorageFile);
|
await Launcher.LaunchFileAsync(((Button)sender).Tag as StorageFile);
|
||||||
}
|
|
||||||
|
|
||||||
private async void Submit_Click(object sender, RoutedEventArgs e)
|
async void Submit_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
uploadingProgress.Visibility = Visibility.Visible;
|
uploadingProgress.Visibility = Visibility.Visible;
|
||||||
submit.IsEnabled = false;
|
submit.IsEnabled = false;
|
||||||
|
|||||||
@@ -8,12 +8,10 @@
|
|||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||||
|
|
||||||
<ScrollViewer>
|
<controls:AdaptiveGridView ItemsSource="{x:Bind list}" DesiredWidth="250" ItemClick="AdaptiveGridView_ItemClick">
|
||||||
<controls:AdaptiveGridView ItemsSource="{x:Bind list}" DesiredWidth="250">
|
|
||||||
<controls:AdaptiveGridView.ItemTemplate>
|
<controls:AdaptiveGridView.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<Button HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" Padding="5" Tag="{Binding Path=Snippet.ResourceId.ChannelId}" Click="Button_Click">
|
<Grid HorizontalAlignment="Stretch" Padding="5" Background="{StaticResource ButtonBackgroundThemeBrush}">
|
||||||
<Grid>
|
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="55"/>
|
<ColumnDefinition Width="55"/>
|
||||||
<ColumnDefinition/>
|
<ColumnDefinition/>
|
||||||
@@ -25,9 +23,7 @@
|
|||||||
</PersonPicture>
|
</PersonPicture>
|
||||||
<TextBlock Grid.Column="1" TextWrapping="Wrap" VerticalAlignment="Center" TextTrimming="CharacterEllipsis" Text="{Binding Path=Snippet.Title}"/>
|
<TextBlock Grid.Column="1" TextWrapping="Wrap" VerticalAlignment="Center" TextTrimming="CharacterEllipsis" Text="{Binding Path=Snippet.Title}"/>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Button>
|
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</controls:AdaptiveGridView.ItemTemplate>
|
</controls:AdaptiveGridView.ItemTemplate>
|
||||||
</controls:AdaptiveGridView>
|
</controls:AdaptiveGridView>
|
||||||
</ScrollViewer>
|
|
||||||
</Page>
|
</Page>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using Google.Apis.YouTube.v3.Data;
|
using FoxTube.Classes;
|
||||||
|
using Google.Apis.YouTube.v3.Data;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Windows.UI.Xaml;
|
|
||||||
using Windows.UI.Xaml.Controls;
|
using Windows.UI.Xaml.Controls;
|
||||||
|
|
||||||
namespace FoxTube.Pages
|
namespace FoxTube.Pages
|
||||||
@@ -16,12 +16,10 @@ namespace FoxTube.Pages
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
Methods.MainPage.PageContent.LoadingPage.Close();
|
Navigation.Frame.Frame.LoadingPage.Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Button_Click(object sender, RoutedEventArgs e)
|
void AdaptiveGridView_ItemClick(object sender, ItemClickEventArgs e) =>
|
||||||
{
|
Navigation.GoToChannel(((Subscription)e.ClickedItem).Snippet.ResourceId.ChannelId);
|
||||||
Methods.MainPage.GoToChannel(((Button)sender).Tag.ToString());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
|
|
||||||
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||||
<ui:AdaptiveGridView Name="list" DesiredWidth="400" SelectionMode="None" HorizontalContentAlignment="Left">
|
<ui:AdaptiveGridView Name="list" DesiredWidth="400" SelectionMode="None" ItemClick="List_ItemClick" HorizontalContentAlignment="Left">
|
||||||
<ui:AdaptiveGridView.ItemContainerTransitions>
|
<ui:AdaptiveGridView.ItemContainerTransitions>
|
||||||
<TransitionCollection>
|
<TransitionCollection>
|
||||||
<EntranceThemeTransition IsStaggeringEnabled="True"/>
|
<EntranceThemeTransition IsStaggeringEnabled="True"/>
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
using FoxTube.Controls;
|
using FoxTube.Classes;
|
||||||
using FoxTube.Controls.Adverts;
|
using FoxTube.Controls.Adverts;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Windows.UI.Xaml;
|
using Windows.UI.Xaml;
|
||||||
using Windows.UI.Xaml.Controls;
|
using Windows.UI.Xaml.Controls;
|
||||||
|
|
||||||
@@ -12,17 +14,27 @@ namespace FoxTube.Pages
|
|||||||
{
|
{
|
||||||
public int Count => list.Items.Count;
|
public int Count => list.Items.Count;
|
||||||
public ItemCollection Children => list.Items;
|
public ItemCollection Children => list.Items;
|
||||||
private int ItemsCount => Children.FindAll(i => i is VideoCard).Count + Children.FindAll(i => i is ChannelCard).Count + Children.FindAll(i => i is PlaylistCard).Count + Children.FindAll(i => i is CardAdvert).Count;
|
int ItemsCount => Children.FindAll(i => i is ICard).Count;
|
||||||
|
|
||||||
public VideoGrid()
|
Queue<ICard> queue = new Queue<ICard>();
|
||||||
{
|
|
||||||
|
public VideoGrid() =>
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
|
public void Add(ICard card)
|
||||||
|
{
|
||||||
|
if (card == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
queue.Enqueue(card);
|
||||||
|
if (LoadItems().Status != TaskStatus.Running)
|
||||||
|
LoadItems().Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Add(UIElement card)
|
void Insert(ICard item)
|
||||||
{
|
{
|
||||||
list.Items.Add(card);
|
list.Items.Add(item);
|
||||||
if ((list.Items.Count - 5) % 25 == 0)
|
if ((ItemsCount - 5) % 25 == 0)
|
||||||
list.Items.Add(new CardAdvert());
|
list.Items.Add(new CardAdvert());
|
||||||
empty.Visibility = Visibility.Collapsed;
|
empty.Visibility = Visibility.Collapsed;
|
||||||
}
|
}
|
||||||
@@ -33,9 +45,20 @@ namespace FoxTube.Pages
|
|||||||
empty.Visibility = Visibility.Visible;
|
empty.Visibility = Visibility.Visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DeleteItem(FrameworkElement item)
|
public void DeleteItem(FrameworkElement item) =>
|
||||||
{
|
|
||||||
Children.Remove(item);
|
Children.Remove(item);
|
||||||
|
|
||||||
|
void List_ItemClick(object sender, ItemClickEventArgs e) =>
|
||||||
|
(e.ClickedItem as ICard).ItemClicked();
|
||||||
|
|
||||||
|
async Task LoadItems()
|
||||||
|
{
|
||||||
|
while(queue.Count > 0)
|
||||||
|
{
|
||||||
|
ICard item = queue.Dequeue();
|
||||||
|
await item.Initialize();
|
||||||
|
Insert(item);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,11 @@
|
|||||||
x:Class="FoxTube.Pages.VideoPage"
|
x:Class="FoxTube.Pages.VideoPage"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:local="using:FoxTube"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:pages="using:FoxTube.Pages"
|
|
||||||
xmlns:classes="using:FoxTube.Classes"
|
xmlns:classes="using:FoxTube.Classes"
|
||||||
|
xmlns:videopage="using:FoxTube.Controls.VideoPage"
|
||||||
|
xmlns:controls="using:FoxTube.Controls"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
|
|
||||||
<Grid Name="grid" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" SizeChanged="grid_SizeChanged">
|
<Grid Name="grid" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" SizeChanged="grid_SizeChanged">
|
||||||
@@ -25,6 +25,7 @@
|
|||||||
</VisualState>
|
</VisualState>
|
||||||
</VisualStateGroup>
|
</VisualStateGroup>
|
||||||
</VisualStateManager.VisualStateGroups>
|
</VisualStateManager.VisualStateGroups>
|
||||||
|
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="*"/>
|
<ColumnDefinition Width="*"/>
|
||||||
<ColumnDefinition Width="400"/>
|
<ColumnDefinition Width="400"/>
|
||||||
@@ -34,7 +35,7 @@
|
|||||||
<RowDefinition/>
|
<RowDefinition/>
|
||||||
<RowDefinition Height="auto"/>
|
<RowDefinition Height="auto"/>
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<ScrollViewer Name="mainScroll" VerticalScrollBarVisibility="Hidden">
|
<ScrollViewer Name="mainScroll" VerticalScrollBarVisibility="Hidden" ViewChanged="MainScroll_ViewChanged">
|
||||||
<StackPanel Name="mainContent">
|
<StackPanel Name="mainContent">
|
||||||
<Border BorderBrush="Red" BorderThickness="5" CornerRadius="10" Margin="10" Name="upcoming" Visibility="Collapsed">
|
<Border BorderBrush="Red" BorderThickness="5" CornerRadius="10" Margin="10" Name="upcoming" Visibility="Collapsed">
|
||||||
<Grid Margin="10">
|
<Grid Margin="10">
|
||||||
@@ -61,10 +62,8 @@
|
|||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Border>
|
</Border>
|
||||||
<local:VideoPlayer x:Name="player" NextClicked="Player_NextClicked" MiniMode="Player_Minimize"/>
|
|
||||||
<PivotItem Header="Description" Name="descriptionPanel">
|
<PivotItem Header="Description" Name="descriptionPanel">
|
||||||
<StackPanel Margin="0,10">
|
<StackPanel Margin="0,10">
|
||||||
<Button FontFamily="Segoe UI, Segoe MDL2 Assets" Content=" Continue from: 00:10:37" Name="left" Click="Left_Click" Visibility="Collapsed"/>
|
|
||||||
<TextBlock IsTextSelectionEnabled="True" Name="title" Text="[Video title]" FontSize="25" TextWrapping="WrapWholeWords" HorizontalTextAlignment="Start"/>
|
<TextBlock IsTextSelectionEnabled="True" Name="title" Text="[Video title]" FontSize="25" TextWrapping="WrapWholeWords" HorizontalTextAlignment="Start"/>
|
||||||
<TextBlock Text="Published at: " Name="meta"/>
|
<TextBlock Text="Published at: " Name="meta"/>
|
||||||
<Grid>
|
<Grid>
|
||||||
@@ -72,13 +71,13 @@
|
|||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto"/>
|
||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto"/>
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Button Padding="0" Background="Transparent" Margin="5" Name="gotoChannel" Click="gotoChannel_Click">
|
<Button Padding="0" Background="Transparent" Margin="5" Click="gotoChannel_Click">
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<PersonPicture Name="channelAvatar" Width="90"/>
|
<PersonPicture Name="channelAvatar" Width="90"/>
|
||||||
<StackPanel Orientation="Vertical" Grid.Column="1" Padding="5" VerticalAlignment="Center">
|
<StackPanel Padding="5" VerticalAlignment="Center">
|
||||||
<TextBlock Name="channelName" Text="[Channel name]" FontSize="18"/>
|
<TextBlock Name="channelName" Text="[Channel name]" FontSize="18"/>
|
||||||
<TextBlock Name="subscribers" Text="[subscribers]" Foreground="Gray" Margin="0,0,0,5"/>
|
<TextBlock Name="subscribers" Text="[subscribers]" Foreground="Gray" Margin="0,0,0,5"/>
|
||||||
<Button x:Uid="/Cards/subscribe" Click="subscribe_Click" Grid.Column="2" Height="30" Width="200" Background="Red" Foreground="White" FontSize="14" FontWeight="SemiBold" Content="Subscirbe" Name="subscribe"/>
|
<Button x:Uid="/Cards/subscribe" Click="subscribe_Click" Height="30" Width="200" Background="Red" Foreground="White" FontSize="14" FontWeight="SemiBold" Content="Subscirbe" Name="subscribe"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Button>
|
</Button>
|
||||||
@@ -89,7 +88,7 @@
|
|||||||
<TextBlock Foreground="Gray" Text="[dislikes]" Name="dislikes"/>
|
<TextBlock Foreground="Gray" Text="[dislikes]" Name="dislikes"/>
|
||||||
<TextBlock HorizontalAlignment="Right" Foreground="Gray" Text="[likes]" Name="likes"/>
|
<TextBlock HorizontalAlignment="Right" Foreground="Gray" Text="[likes]" Name="likes"/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid BorderBrush="{StaticResource SystemControlBackgroundListMediumRevealBorderBrush}">
|
<Grid>
|
||||||
<FontIcon Foreground="Gray"
|
<FontIcon Foreground="Gray"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
FontSize="40"
|
FontSize="40"
|
||||||
@@ -113,16 +112,12 @@
|
|||||||
<classes:AdaptiveCommandBar Grid.Row="1" VerticalAlignment="Bottom" x:Name="commandbar">
|
<classes:AdaptiveCommandBar Grid.Row="1" VerticalAlignment="Bottom" x:Name="commandbar">
|
||||||
<AppBarButton x:Uid="/VideoPage/download" Icon="Download" Label="Download video" Name="download">
|
<AppBarButton x:Uid="/VideoPage/download" Icon="Download" Label="Download video" Name="download">
|
||||||
<AppBarButton.Flyout>
|
<AppBarButton.Flyout>
|
||||||
<MenuFlyout x:Name="downloadSelector"/>
|
<Flyout x:Name="downloadSelector"/>
|
||||||
</AppBarButton.Flyout>
|
</AppBarButton.Flyout>
|
||||||
</AppBarButton>
|
</AppBarButton>
|
||||||
<AppBarButton x:Uid="/VideoPage/addTo" Name="addTo" Label="Add to" Icon="Add" Visibility="Visible">
|
<AppBarButton x:Uid="/VideoPage/addTo" Name="addTo" Label="Add to" Icon="Add" Visibility="Visible">
|
||||||
<AppBarButton.Flyout>
|
<AppBarButton.Flyout>
|
||||||
<MenuFlyout x:Name="addList">
|
<Flyout x:Name="addToSelector"/>
|
||||||
<MenuFlyoutItem x:Uid="/VideoPage/newPlaylist" Text="New playlist" Name="newPlaylist" Click="NewPlaylist_Click" Icon="Add"/>
|
|
||||||
<ToggleMenuFlyoutItem x:Uid="/VideoPage/wl" Text="Watch later" Name="wl" Click="Wl_Click" Icon="Clock"/>
|
|
||||||
<MenuFlyoutSeparator/>
|
|
||||||
</MenuFlyout>
|
|
||||||
</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"/>
|
||||||
@@ -138,52 +133,15 @@
|
|||||||
<Grid Grid.Column="1" Name="tabsPlaceholder">
|
<Grid Grid.Column="1" Name="tabsPlaceholder">
|
||||||
<Pivot Name="pivot" SelectedIndex="0" IsHeaderItemsCarouselEnabled="False">
|
<Pivot Name="pivot" SelectedIndex="0" IsHeaderItemsCarouselEnabled="False">
|
||||||
<PivotItem x:Uid="/VideoPage/related" Header="Suggestions">
|
<PivotItem x:Uid="/VideoPage/related" Header="Suggestions">
|
||||||
<ScrollViewer>
|
<videopage:RelatedVideos x:Name="suggestions"/>
|
||||||
<pages:VideoGrid x:Name="relatedVideos"/>
|
|
||||||
</ScrollViewer>
|
|
||||||
</PivotItem>
|
</PivotItem>
|
||||||
<PivotItem x:Uid="/VideoPage/comments" Header="Comments" Name="commentsPlaceholder">
|
<PivotItem x:Uid="/VideoPage/comments" Header="Comments" Name="commentsTab">
|
||||||
<pages:CommentsPage x:Name="comments"/>
|
<videopage:Comments x:Name="comments"/>
|
||||||
</PivotItem>
|
</PivotItem>
|
||||||
<PivotItem x:Uid="/VideoPage/playlist" Header="Playlist" Name="playlist">
|
<PivotItem x:Uid="/VideoPage/playlist" Header="Playlist" Name="playlistTab">
|
||||||
<ScrollViewer Name="playlistScroll">
|
<videopage:VideoPlaylist x:Name="playlist" ItemChanged="Playlist_ItemChanged"/>
|
||||||
<StackPanel>
|
|
||||||
<StackPanel Padding="8" Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}">
|
|
||||||
<TextBlock Text="[Playlsit name]" FontSize="26" TextWrapping="WrapWholeWords" Name="playlistName"/>
|
|
||||||
<TextBlock Text="[Channel name]" Name="playlistChannel"/>
|
|
||||||
<TextBlock Text="[Counter]" Name="playlistCounter"/>
|
|
||||||
</StackPanel>
|
|
||||||
<ListBox Background="Transparent" SelectionChanged="ListBox_SelectionChanged" Name="playlistList">
|
|
||||||
<ListBox.ItemTemplate>
|
|
||||||
<DataTemplate>
|
|
||||||
<Grid Tag="{Binding Path=Id}">
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="auto"/>
|
|
||||||
<ColumnDefinition Width="auto"/>
|
|
||||||
<ColumnDefinition/>
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<TextBlock Text="{Binding Path=Number}" VerticalAlignment="Center" Margin="0,0,8,0"/>
|
|
||||||
<Image Grid.Column="1" Source="{Binding Path=Thumbnail}" Height="65"/>
|
|
||||||
<TextBlock Grid.Column="2" Margin="8,0,0,0" VerticalAlignment="Center" TextWrapping="WrapWholeWords" Text="{Binding Path=Title}"/>
|
|
||||||
</Grid>
|
|
||||||
</DataTemplate>
|
|
||||||
</ListBox.ItemTemplate>
|
|
||||||
</ListBox>
|
|
||||||
</StackPanel>
|
|
||||||
</ScrollViewer>
|
|
||||||
</PivotItem>
|
</PivotItem>
|
||||||
</Pivot>
|
</Pivot>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<ContentDialog x:Uid="/VideoPage/dialog" PrimaryButtonText="Create and add" Title="New playlist" CloseButtonText="Cancel" DefaultButton="Primary" PrimaryButtonClick="ContentDialog_PrimaryButtonClick" Name="playlistDialog">
|
|
||||||
<StackPanel>
|
|
||||||
<TextBox x:Uid="/VideoPage/newPlaylistName" PlaceholderText="Enter playlist name" Name="newListName"/>
|
|
||||||
<ComboBox x:Uid="/VideoPage/privacy" Header="Availablity" SelectedIndex="0" HorizontalAlignment="Stretch" Name="newListDisc">
|
|
||||||
<ComboBoxItem x:Uid="/VideoPage/public" Content="Public"/>
|
|
||||||
<ComboBoxItem x:Uid="/VideoPage/private" Content="Private"/>
|
|
||||||
<ComboBoxItem x:Uid="/VideoPage/direct" Content="Direct link"/>
|
|
||||||
</ComboBox>
|
|
||||||
</StackPanel>
|
|
||||||
</ContentDialog>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</Page>
|
</Page>
|
||||||
|
|||||||
+129
-469
@@ -1,4 +1,6 @@
|
|||||||
using FoxTube.Controls;
|
using FoxTube.Classes;
|
||||||
|
using FoxTube.Controls;
|
||||||
|
using FoxTube.Controls.VideoPage;
|
||||||
using Google.Apis.YouTube.v3;
|
using Google.Apis.YouTube.v3;
|
||||||
using Google.Apis.YouTube.v3.Data;
|
using Google.Apis.YouTube.v3.Data;
|
||||||
using Microsoft.AppCenter.Analytics;
|
using Microsoft.AppCenter.Analytics;
|
||||||
@@ -25,21 +27,6 @@ namespace FoxTube.Pages
|
|||||||
{
|
{
|
||||||
public enum Rating { None, Like, Dislike }
|
public enum Rating { None, Like, Dislike }
|
||||||
|
|
||||||
public class VideoPlaylistItem
|
|
||||||
{
|
|
||||||
public int Number { get; set; }
|
|
||||||
public string Thumbnail { get; private set; } = "/Assets/videoThumbSample.png";
|
|
||||||
public string Id { get; private set; }
|
|
||||||
public string Title { get; private set; }
|
|
||||||
|
|
||||||
public VideoPlaylistItem(string image, string title, string id)
|
|
||||||
{
|
|
||||||
Thumbnail = image;
|
|
||||||
Title = title;
|
|
||||||
Id = id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Video page
|
/// Video page
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -49,27 +36,25 @@ namespace FoxTube.Pages
|
|||||||
|
|
||||||
public object Parameter { get; set; } = null;
|
public object Parameter { get; set; } = null;
|
||||||
|
|
||||||
public string playlistId = null;
|
string playlistItem = null;
|
||||||
public Video item;
|
Video item;
|
||||||
public HistoryItem history;
|
Channel channelItem;
|
||||||
public bool incognito = false;
|
bool incognito = false;
|
||||||
|
|
||||||
bool isExtended = false;
|
|
||||||
|
|
||||||
Rating userRating = Rating.None;
|
Rating userRating = Rating.None;
|
||||||
|
|
||||||
DispatcherTimer liveTimer;
|
DispatcherTimer liveTimer;
|
||||||
DispatcherTimer countdownTimer;
|
DispatcherTimer countdownTimer;
|
||||||
|
|
||||||
public VideoPlayer Player => player;
|
|
||||||
|
|
||||||
public VideoPage()
|
public VideoPage()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
if (Window.Current.Bounds.Width <= 1000)
|
//Methods.Player.SizeChanged += Player_SizeChanged;
|
||||||
{
|
|
||||||
Debug.WriteLine("Correcting layout...");
|
if (Window.Current.Bounds.Width > 1000)
|
||||||
|
return;
|
||||||
|
|
||||||
mainContent.Children.Remove(descriptionPanel);
|
mainContent.Children.Remove(descriptionPanel);
|
||||||
pivot.Items.Insert(0, descriptionPanel);
|
pivot.Items.Insert(0, descriptionPanel);
|
||||||
|
|
||||||
@@ -78,65 +63,87 @@ namespace FoxTube.Pages
|
|||||||
|
|
||||||
grid.ColumnDefinitions[1].Width = new GridLength(0);
|
grid.ColumnDefinitions[1].Width = new GridLength(0);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void Player_NextClicked()
|
|
||||||
{
|
|
||||||
if (playlistId != null && playlistList.SelectedIndex + 1 < playlistList.Items.Count)
|
|
||||||
playlistList.SelectedIndex++;
|
|
||||||
else
|
|
||||||
(relatedVideos.Children[0] as VideoCard).Button_Click(this, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||||
{
|
{
|
||||||
base.OnNavigatedTo(e);
|
base.OnNavigatedTo(e);
|
||||||
Parameter = e.Parameter;
|
Parameter = e.Parameter;
|
||||||
|
|
||||||
Initialize(e.Parameter as object[]);
|
Initialize(((object, Channel, bool, string))e.Parameter);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnNavigatedFrom(NavigationEventArgs e)
|
async void Initialize((object video, Channel channel, bool incognito, string playlist) parameter, bool playlistItemSwitch = false)
|
||||||
{
|
|
||||||
base.OnNavigatedFrom(e);
|
|
||||||
Player.Player.Stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async void Initialize(object[] ids)
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
incognito = (bool)ids[2];
|
incognito = parameter.incognito;
|
||||||
|
channelItem = parameter.channel;
|
||||||
|
|
||||||
if (ids[1] != null)
|
if (parameter.video is Video)
|
||||||
LoadPlaylist(ids[1] as string);
|
item = parameter.video as Video;
|
||||||
else
|
else
|
||||||
pivot.Items.Remove(playlist);
|
{
|
||||||
|
|
||||||
VideosResource.ListRequest request = SecretsVault.Service.Videos.List("snippet,statistics,status,contentDetails,liveStreamingDetails");
|
VideosResource.ListRequest request = SecretsVault.Service.Videos.List("snippet,statistics,status,contentDetails,liveStreamingDetails");
|
||||||
request.Id = ids[0] as string;
|
request.Id = parameter.video as string;
|
||||||
request.Hl = SettingsStorage.RelevanceLanguage;
|
request.Hl = SettingsStorage.RelevanceLanguage;
|
||||||
item = (await request.ExecuteAsync()).Items[0];
|
item = (await request.ExecuteAsync()).Items[0];
|
||||||
|
|
||||||
|
ChannelsResource.ListRequest channelRequest = SecretsVault.Service.Channels.List("snippet, statistics");
|
||||||
|
channelRequest.Id = item.Snippet.ChannelId;
|
||||||
|
channelItem = (await channelRequest.ExecuteAsync()).Items[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Methods.Player.Player.Visibility = Visibility.Visible;
|
||||||
|
Methods.Player.Player.PosterSource = new BitmapImage((item.Snippet.Thumbnails.Maxres ?? item.Snippet.Thumbnails.Medium).Url.ToUri());
|
||||||
|
Methods.Player.NextRequested += suggestions.OpenNext;*/
|
||||||
|
|
||||||
|
LoadDescription();
|
||||||
|
|
||||||
|
|
||||||
|
if (!playlistItemSwitch)
|
||||||
|
{
|
||||||
|
if (parameter.playlist != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await playlist.Initialize(item, parameter.playlist);
|
||||||
|
playlistItem = parameter.playlist;
|
||||||
|
pivot.SelectedItem = playlistTab;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{ pivot.Items.Remove(playlistTab); }
|
||||||
|
}
|
||||||
|
else
|
||||||
|
pivot.Items.Remove(playlistTab);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Initializing player
|
||||||
|
// Methods.MainPage.Player.Initialize(item, channelItem.Snippet.Thumbnails.Medium.Url, incognito, parameter.playlist == null ? null : playlist);
|
||||||
|
|
||||||
if (item.Snippet.LiveBroadcastContent == "none")
|
if (item.Snippet.LiveBroadcastContent == "none")
|
||||||
LoadStats();
|
{
|
||||||
|
views.Text = $"{item.Statistics.ViewCount:0,0} {resources.GetString("/Cards/views")}";
|
||||||
|
comments.Initialize(item);
|
||||||
|
/*try { downloadSelector.Initialize(item); }
|
||||||
|
catch { download.Visibility = Visibility.Collapsed; }*/
|
||||||
|
}
|
||||||
else
|
else
|
||||||
LoadStream();
|
LoadStream();
|
||||||
|
|
||||||
if (item.Snippet.LiveBroadcastContent == "upcoming")
|
if (item.Snippet.LiveBroadcastContent == "upcoming")
|
||||||
SetSchedule();
|
SetSchedule();
|
||||||
|
|
||||||
LoadInfo();
|
suggestions.Initialize(item.Id);
|
||||||
LoadAddTo();
|
|
||||||
|
|
||||||
Methods.MainPage.VideoContent.LoadingPage.Close();
|
//Methods.MainPage.VideoContent.LoadingPage.Close();
|
||||||
}
|
}
|
||||||
catch (System.Net.Http.HttpRequestException)
|
catch (System.Net.Http.HttpRequestException)
|
||||||
{
|
{
|
||||||
Methods.MainPage.VideoContent.LoadingPage.Error("System.Net.Http.HttpRequestException", "Unable to connect to Google servers.", true);
|
//Methods.MainPage.VideoContent.LoadingPage.Error("System.Net.Http.HttpRequestException", "Unable to connect to Google servers.", true);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
/*Methods.Player.Player.Visibility = Visibility.Collapsed;
|
||||||
if (item == null)
|
if (item == null)
|
||||||
{
|
{
|
||||||
Methods.MainPage.PageContent.LoadingPage.Error("VideoNotFound", "Such video doesn't exist");
|
Methods.MainPage.PageContent.LoadingPage.Error("VideoNotFound", "Such video doesn't exist");
|
||||||
@@ -150,7 +157,7 @@ namespace FoxTube.Pages
|
|||||||
{ "Message", e.Message },
|
{ "Message", e.Message },
|
||||||
{ "Video ID", item.Id },
|
{ "Video ID", item.Id },
|
||||||
{ "StackTrace", e.StackTrace }
|
{ "StackTrace", e.StackTrace }
|
||||||
});
|
});*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,95 +190,35 @@ namespace FoxTube.Pages
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async void LoadPlaylist(string id)
|
async void LoadDescription()
|
||||||
{
|
|
||||||
playlistId = id;
|
|
||||||
List<VideoPlaylistItem> items = new List<VideoPlaylistItem>();
|
|
||||||
VideoPlaylistItem selection = null;
|
|
||||||
|
|
||||||
if (id == "WL")
|
|
||||||
{
|
|
||||||
SecretsVault.WatchLater = await Methods.GetLater();
|
|
||||||
|
|
||||||
foreach (string i in SecretsVault.WatchLater)
|
|
||||||
{
|
|
||||||
VideosResource.ListRequest request = SecretsVault.Service.Videos.List("snippet");
|
|
||||||
request.Id = i;
|
|
||||||
Video v = (await request.ExecuteAsync()).Items[0];
|
|
||||||
items.Add(new VideoPlaylistItem(v.Snippet.Thumbnails.Medium.Url, v.Snippet.Title, i));
|
|
||||||
}
|
|
||||||
|
|
||||||
selection = items.Find(i => i.Id == item.Id);
|
|
||||||
|
|
||||||
for (int k = 0; k < items.Count; k++)
|
|
||||||
items[k].Number = k + 1;
|
|
||||||
|
|
||||||
playlistName.Text = resources.GetString("/Main/later/Content");
|
|
||||||
playlistChannel.Text = SecretsVault.UserChannel.Snippet.Title;
|
|
||||||
|
|
||||||
playlistCounter.Text = $"{items.IndexOf(selection) + 1}/{SecretsVault.WatchLater.Count}";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//Retrieving data
|
|
||||||
PlaylistsResource.ListRequest playlistRequest = SecretsVault.Service.Playlists.List("snippet,contentDetails");
|
|
||||||
playlistRequest.Id = id;
|
|
||||||
playlistRequest.Hl = SettingsStorage.RelevanceLanguage;
|
|
||||||
Playlist playlistItem = (await playlistRequest.ExecuteAsync()).Items[0];
|
|
||||||
|
|
||||||
PlaylistItemsResource.ListRequest listRequest = SecretsVault.Service.PlaylistItems.List("snippet");
|
|
||||||
listRequest.MaxResults = 50;
|
|
||||||
listRequest.PlaylistId = id;
|
|
||||||
|
|
||||||
PlaylistItemListResponse listResponse;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
listResponse = await listRequest.ExecuteAsync();
|
|
||||||
listRequest.PageToken = listResponse.NextPageToken;
|
|
||||||
|
|
||||||
foreach (PlaylistItem i in listResponse.Items)
|
|
||||||
items.Add(new VideoPlaylistItem(i.Snippet.Thumbnails.Medium.Url, i.Snippet.Title, i.Snippet.ResourceId.VideoId));
|
|
||||||
}
|
|
||||||
while (!string.IsNullOrWhiteSpace(listRequest.PageToken));
|
|
||||||
|
|
||||||
selection = items.Find(i => i.Id == item.Id);
|
|
||||||
|
|
||||||
for (int k = 0; k < items.Count; k++)
|
|
||||||
items[k].Number = k + 1;
|
|
||||||
|
|
||||||
//Setting data
|
|
||||||
playlistName.Text = playlistItem.Snippet.Localized.Title;
|
|
||||||
playlistChannel.Text = Methods.GuardFromNull(playlistItem.Snippet.ChannelTitle);
|
|
||||||
|
|
||||||
playlistCounter.Text = $"{items.IndexOf(selection) + 1}/{playlistItem.ContentDetails.ItemCount}";
|
|
||||||
}
|
|
||||||
|
|
||||||
playlistList.ItemsSource = items;
|
|
||||||
playlistList.SelectedItem = selection;
|
|
||||||
pivot.SelectedItem = playlist;
|
|
||||||
|
|
||||||
await Task.Delay(500);
|
|
||||||
|
|
||||||
playlistScroll.ChangeView(null, playlistList.SelectedIndex * 86 + 89, null, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
async void LoadInfo()
|
|
||||||
{
|
{
|
||||||
//Setting meta
|
//Setting meta
|
||||||
title.Text = item.Snippet.Localized.Title;
|
title.Text = item.Snippet.Localized.Title;
|
||||||
|
description.FormatText(item.Snippet.Localized.Description);
|
||||||
|
|
||||||
|
//Setting channel button
|
||||||
|
channelAvatar.ProfilePicture = new BitmapImage(channelItem.Snippet.Thumbnails.Medium.Url.ToUri()) { DecodePixelHeight = 90, DecodePixelWidth = 90 };
|
||||||
|
channelName.Text = item.Snippet.ChannelTitle;
|
||||||
|
subscribers.Text = $"{channelItem.Statistics.SubscriberCount:0,0} {resources.GetString("/Cards/subscribers")}";
|
||||||
|
|
||||||
|
//Setting ratings
|
||||||
|
dislikes.Text = $"{item.Statistics.DislikeCount:0,0}";
|
||||||
|
likes.Text = $"{item.Statistics.LikeCount:0,0}";
|
||||||
|
try { rating.Value = (double)item.Statistics.DislikeCount / (double)(item.Statistics.DislikeCount + item.Statistics.LikeCount) * 100; }
|
||||||
|
catch { rating.Visibility = Visibility.Collapsed; }
|
||||||
|
|
||||||
meta.Text = "";
|
meta.Text = "";
|
||||||
meta.Inlines.Add(new Run
|
meta.Inlines.Add(new Run
|
||||||
{
|
{
|
||||||
Text = $"{resources.GetString("/VideoPage/publishedAt")}: {item.Snippet.PublishedAt} ({Methods.GetAgo(item.Snippet.PublishedAt.Value)})"
|
Text = $"{resources.GetString("/VideoPage/publishedAt")}: {item.Snippet.PublishedAt} ({Methods.GetAgo(item.Snippet.PublishedAt.Value)})"
|
||||||
});
|
});
|
||||||
if(!string.IsNullOrWhiteSpace(item.Snippet.CategoryId))
|
if (!string.IsNullOrWhiteSpace(item.Snippet.CategoryId))
|
||||||
{
|
{
|
||||||
VideoCategoriesResource.ListRequest request = SecretsVault.Service.VideoCategories.List("snippet,id");
|
VideoCategoriesResource.ListRequest request = SecretsVault.Service.VideoCategories.List("snippet,id");
|
||||||
request.Id = item.Snippet.CategoryId;
|
request.Id = item.Snippet.CategoryId;
|
||||||
request.Hl = SettingsStorage.RelevanceLanguage;
|
request.Hl = SettingsStorage.RelevanceLanguage;
|
||||||
VideoCategoryListResponse response = await request.ExecuteAsync();
|
VideoCategoryListResponse response = await request.ExecuteAsync();
|
||||||
if(response.Items.Count != 0)
|
|
||||||
{
|
|
||||||
meta.Inlines.Add(new Run
|
meta.Inlines.Add(new Run
|
||||||
{
|
{
|
||||||
Text = $" {resources.GetString("/VideoPage/inCat")} "
|
Text = $" {resources.GetString("/VideoPage/inCat")} "
|
||||||
@@ -281,26 +228,9 @@ namespace FoxTube.Pages
|
|||||||
{
|
{
|
||||||
Text = response.Items[0].Snippet.Title
|
Text = response.Items[0].Snippet.Title
|
||||||
});
|
});
|
||||||
hl.Click += (s, e) => Methods.MainPage.GoToSearch(new SearchParameters(response.Items[0]));
|
hl.Click += (s, e) => Navigation.GoToSearch(new SearchParameters(response.Items[0]));
|
||||||
meta.Inlines.Add(hl);
|
meta.Inlines.Add(hl);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
description.FormatText(item.Snippet.Localized.Description);
|
|
||||||
|
|
||||||
//Setting channel button
|
|
||||||
ChannelsResource.ListRequest channelRequest = SecretsVault.Service.Channels.List("snippet, statistics");
|
|
||||||
channelRequest.Id = item.Snippet.ChannelId;
|
|
||||||
var item1 = (await channelRequest.ExecuteAsync()).Items[0];
|
|
||||||
|
|
||||||
channelAvatar.ProfilePicture = new BitmapImage(item1.Snippet.Thumbnails.Medium.Url.ToUri()) { DecodePixelHeight = 90, DecodePixelWidth = 90 };
|
|
||||||
channelName.Text = item.Snippet.ChannelTitle;
|
|
||||||
subscribers.Text = $"{item1.Statistics.SubscriberCount:0,0} {resources.GetString("/Cards/subscribers")}";
|
|
||||||
|
|
||||||
//Setting ratings
|
|
||||||
dislikes.Text = $"{item.Statistics.DislikeCount:0,0}";
|
|
||||||
likes.Text = $"{item.Statistics.LikeCount:0,0}";
|
|
||||||
try { rating.Value = (double)item.Statistics.DislikeCount / (double)(item.Statistics.DislikeCount + item.Statistics.LikeCount) * 100; }
|
|
||||||
catch { rating.Visibility = Visibility.Collapsed; }
|
|
||||||
|
|
||||||
//Setting User's rate
|
//Setting User's rate
|
||||||
if (SecretsVault.IsAuthorized)
|
if (SecretsVault.IsAuthorized)
|
||||||
@@ -323,8 +253,11 @@ namespace FoxTube.Pages
|
|||||||
subscribe.Foreground = new SolidColorBrush(Colors.Gray);
|
subscribe.Foreground = new SolidColorBrush(Colors.Gray);
|
||||||
subscribe.Content = resources.GetString("/Cards/unsubscribe");
|
subscribe.Content = resources.GetString("/Cards/unsubscribe");
|
||||||
}
|
}
|
||||||
if (item.Snippet.ChannelId == SecretsVault.AccountId)
|
else if (item.Snippet.ChannelId == SecretsVault.AccountId)
|
||||||
subscribe.Visibility = Visibility.Collapsed;
|
subscribe.Visibility = Visibility.Collapsed;
|
||||||
|
|
||||||
|
/*try { addToSelector.Initialize(item); }
|
||||||
|
catch { addTo.Visibility = Visibility.Collapsed; }*/
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -332,34 +265,22 @@ namespace FoxTube.Pages
|
|||||||
addTo.Visibility = Visibility.Collapsed;
|
addTo.Visibility = Visibility.Collapsed;
|
||||||
subscribe.Visibility = Visibility.Collapsed;
|
subscribe.Visibility = Visibility.Collapsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if ((history = HistorySet.Items.Find(i => i.Id == item.Id)) != null && history.LeftOn.TotalSeconds >= 30 && Methods.GetDuration(item.ContentDetails.Duration).TotalSeconds - history.LeftOn.TotalSeconds >= 30)
|
|
||||||
{
|
|
||||||
left.Visibility = Visibility.Visible;
|
|
||||||
left.Content = $"\xE122 {resources.GetString("/VideoPage/continue")}: {history.LeftOn.ToString(@"hh\:mm\:ss")}";
|
|
||||||
}
|
|
||||||
|
|
||||||
//Initializing player
|
|
||||||
player.Initialize(item, item1.Snippet.Thumbnails.Medium.Url, incognito);
|
|
||||||
|
|
||||||
LoadRelatedVideos();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoadStream()
|
void LoadStream()
|
||||||
{
|
{
|
||||||
liveTimer = new DispatcherTimer() { Interval = TimeSpan.FromSeconds(10) };
|
liveTimer = new DispatcherTimer() { Interval = TimeSpan.FromMinutes(1) };
|
||||||
liveTimer.Tick += LiveStatsUpdate;
|
liveTimer.Tick += LiveStatsUpdate;
|
||||||
liveTimer.Start();
|
liveTimer.Start();
|
||||||
LiveStatsUpdate();
|
views.Text = $"{item.LiveStreamingDetails.ConcurrentViewers} {resources.GetString("/Cards/viewers")}";
|
||||||
|
|
||||||
if(string.IsNullOrWhiteSpace(item.LiveStreamingDetails.ActiveLiveChatId))
|
if (string.IsNullOrWhiteSpace(item.LiveStreamingDetails.ActiveLiveChatId))
|
||||||
pivot.Items.Remove(commentsPlaceholder);
|
comments.Initialize(item);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
commentsPlaceholder.Header = resources.GetString("/VideoPage/chat");
|
commentsTab.Header = resources.GetString("/VideoPage/chat");
|
||||||
commentsPlaceholder.Content = new Chat(item.LiveStreamingDetails.ActiveLiveChatId);
|
commentsTab.Content = new Chat(item.LiveStreamingDetails.ActiveLiveChatId);
|
||||||
pivot.SelectedItem = commentsPlaceholder;
|
pivot.SelectedItem = commentsTab;
|
||||||
}
|
}
|
||||||
download.Visibility = Visibility.Collapsed;
|
download.Visibility = Visibility.Collapsed;
|
||||||
}
|
}
|
||||||
@@ -372,117 +293,14 @@ namespace FoxTube.Pages
|
|||||||
views.Text = $"{(await request.ExecuteAsync()).Items[0].LiveStreamingDetails.ConcurrentViewers} {resources.GetString("/Cards/viewers")}";
|
views.Text = $"{(await request.ExecuteAsync()).Items[0].LiveStreamingDetails.ConcurrentViewers} {resources.GetString("/Cards/viewers")}";
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoadStats()
|
private void gotoChannel_Click(object sender, RoutedEventArgs e) =>
|
||||||
{
|
Navigation.GoToChannel(channelItem.Id);
|
||||||
views.Text = $"{item.Statistics.ViewCount:0,0} {resources.GetString("/Cards/views")}";
|
|
||||||
|
|
||||||
comments.Initialize(item);
|
private void openBrowser_Click(object sender, RoutedEventArgs e) => Methods.GuardFromNull("");
|
||||||
LoadDownloads();
|
//Methods.Player.OpenBrowser();
|
||||||
}
|
|
||||||
|
|
||||||
async void LoadDownloads()
|
void refresh_Click(object sender, RoutedEventArgs e) => Methods.GuardFromNull("");
|
||||||
{
|
//Methods.MainPage.VideoContent.Refresh();
|
||||||
try
|
|
||||||
{
|
|
||||||
MediaStreamInfoSet infoSet = await new YoutubeClient().GetVideoMediaStreamInfosAsync(item.Id);
|
|
||||||
foreach (MuxedStreamInfo i in infoSet.Muxed)
|
|
||||||
{
|
|
||||||
MenuFlyoutItem menuItem = new MenuFlyoutItem()
|
|
||||||
{
|
|
||||||
Text = i.VideoQualityLabel,
|
|
||||||
Tag = new object[] { i, i.VideoQualityLabel }
|
|
||||||
};
|
|
||||||
menuItem.Click += downloadItemSelected;
|
|
||||||
downloadSelector.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;
|
|
||||||
downloadSelector.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);
|
|
||||||
}
|
|
||||||
|
|
||||||
async void LoadRelatedVideos()
|
|
||||||
{
|
|
||||||
SearchResource.ListRequest request = SecretsVault.Service.Search.List("snippet");
|
|
||||||
request.RegionCode = SettingsStorage.Region;
|
|
||||||
request.RelevanceLanguage = SettingsStorage.RelevanceLanguage;
|
|
||||||
request.RelatedToVideoId = item.Id;
|
|
||||||
request.SafeSearch = (SearchResource.ListRequest.SafeSearchEnum)SettingsStorage.SafeSearch;
|
|
||||||
request.MaxResults = 20;
|
|
||||||
request.Type = "video";
|
|
||||||
|
|
||||||
SearchListResponse response = await request.ExecuteAsync();
|
|
||||||
|
|
||||||
foreach (SearchResult video in response.Items)
|
|
||||||
relatedVideos.Add(new VideoCard(video.Id.VideoId));
|
|
||||||
|
|
||||||
relatedVideos.Children.Insert(1, new Controls.Adverts.CardAdvert());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Player_Minimize(object sender, params object[] e)
|
|
||||||
{
|
|
||||||
isExtended = (bool)e[0];
|
|
||||||
if(isExtended)
|
|
||||||
{
|
|
||||||
grid.ColumnDefinitions[1].Width = new GridLength(0);
|
|
||||||
commandbar.Visibility = Visibility.Collapsed;
|
|
||||||
|
|
||||||
mainScroll.ChangeView(0, 0, null);
|
|
||||||
|
|
||||||
mainScroll.Margin = new Thickness(0);
|
|
||||||
mainScroll.VerticalScrollMode = ScrollMode.Disabled;
|
|
||||||
|
|
||||||
Methods.MainPage.MinimizeVideo();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
grid.ColumnDefinitions[1].Width = new GridLength(400);
|
|
||||||
commandbar.Visibility = Visibility.Visible;
|
|
||||||
|
|
||||||
mainScroll.Margin = new Thickness(0,0,0,50);
|
|
||||||
mainScroll.VerticalScrollMode = ScrollMode.Auto;
|
|
||||||
|
|
||||||
Methods.MainPage.MaximizeVideo();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void gotoChannel_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
Methods.MainPage.GoToChannel(item.Snippet.ChannelId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void openBrowser_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
player.Pause();
|
|
||||||
string timecode = player.Player.Position.TotalSeconds > 10 ?
|
|
||||||
"&t=" + (int)player.Player.Position.TotalSeconds + "s" : string.Empty;
|
|
||||||
|
|
||||||
await Launcher.LaunchUriAsync($"https://www.youtube.com/watch?v={item.Id}{timecode}".ToUri());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void refresh_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
Methods.MainPage.VideoContent.Refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CloseVideo()
|
|
||||||
{
|
|
||||||
player.Controls_CloseRequested(this, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void grid_SizeChanged(object sender, SizeChangedEventArgs e)
|
private void grid_SizeChanged(object sender, SizeChangedEventArgs e)
|
||||||
{
|
{
|
||||||
@@ -516,7 +334,7 @@ namespace FoxTube.Pages
|
|||||||
|
|
||||||
private void Share(DataTransferManager sender, DataRequestedEventArgs args)
|
private void Share(DataTransferManager sender, DataRequestedEventArgs args)
|
||||||
{
|
{
|
||||||
player.Pause();
|
//Methods.Player.Pause();
|
||||||
|
|
||||||
Methods.Share(args,
|
Methods.Share(args,
|
||||||
item.Snippet.Thumbnails.Medium.Url,
|
item.Snippet.Thumbnails.Medium.Url,
|
||||||
@@ -531,6 +349,9 @@ namespace FoxTube.Pages
|
|||||||
DataTransferManager.ShowShareUI();
|
DataTransferManager.ShowShareUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async void Report_Click(object sender, RoutedEventArgs e) =>
|
||||||
|
await new ReportVideo(item.Id).ShowAsync();
|
||||||
|
|
||||||
private async void dislike_Click(object sender, RoutedEventArgs e)
|
private async void dislike_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
if (SecretsVault.IsAuthorized)
|
if (SecretsVault.IsAuthorized)
|
||||||
@@ -603,16 +424,6 @@ namespace FoxTube.Pages
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if ((e.AddedItems[0] as VideoPlaylistItem).Id != item.Id)
|
|
||||||
Methods.MainPage.GoToVideo((e.AddedItems[0] as VideoPlaylistItem).Id, playlistId);
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void subscribe_Click(object sender, RoutedEventArgs e)
|
private async void subscribe_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
if (await SecretsVault.ChangeSubscriptionState(item.Snippet.ChannelId))
|
if (await SecretsVault.ChangeSubscriptionState(item.Snippet.ChannelId))
|
||||||
@@ -629,194 +440,43 @@ namespace FoxTube.Pages
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async void LoadAddTo()
|
private void MainScroll_ViewChanged(object sender, ScrollViewerViewChangedEventArgs e) => Methods.GuardFromNull("");
|
||||||
|
//Methods.Player.SetMargin(mainScroll.VerticalOffset);
|
||||||
|
|
||||||
|
private void Player_SizeChanged(object sender, SizeChangedEventArgs e)
|
||||||
{
|
{
|
||||||
try
|
//if(Methods.Player.State != PlayerDisplayState.Compact)
|
||||||
|
mainContent.Margin = new Thickness(mainContent.Margin.Left, e.NewSize.Height, mainContent.Margin.Right, mainContent.Margin.Bottom);
|
||||||
|
}
|
||||||
|
public void Maximize()
|
||||||
{
|
{
|
||||||
if (SecretsVault.UserChannel == null)
|
|
||||||
|
}
|
||||||
|
public void Minimize()
|
||||||
{
|
{
|
||||||
addTo.Visibility = Visibility.Collapsed;
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SecretsVault.WatchLater.Contains(item.Id))
|
private void ResetControl()
|
||||||
(addList.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;
|
mainScroll.ChangeView(0, 0, null);
|
||||||
ToggleMenuFlyoutItem menuItem = new ToggleMenuFlyoutItem
|
upcoming.Visibility = Visibility.Collapsed;
|
||||||
{
|
schedule.Visibility = Visibility.Collapsed;
|
||||||
Text = i.Snippet.Title,
|
start.Visibility = Visibility.Collapsed;
|
||||||
IsChecked = (await itemRequest.ExecuteAsync()).Items.Count > 0,
|
end.Visibility = Visibility.Collapsed;
|
||||||
Tag = i,
|
|
||||||
Icon = new FontIcon
|
countdownPanel.Visibility = Visibility.Collapsed;
|
||||||
{
|
|
||||||
Glyph = "\xE728"
|
download.Visibility = Visibility.Visible;
|
||||||
}
|
addTo.Visibility = Visibility.Visible;
|
||||||
};
|
|
||||||
menuItem.Click += Item_Click;
|
comments = new Comments();
|
||||||
addList.Items.Add(menuItem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
addTo.Visibility = Visibility.Collapsed;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void Item_Click(object sender, RoutedEventArgs e)
|
private void Playlist_ItemChanged(string id)
|
||||||
{
|
{
|
||||||
if(((ToggleMenuFlyoutItem)sender).IsChecked)
|
ResetControl();
|
||||||
{
|
Initialize((id, null, incognito, playlistItem), true);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void NewPlaylist_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
await playlistDialog.ShowAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void Wl_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
if (wl.IsChecked)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
PlaylistItem playlist = new PlaylistItem
|
|
||||||
{
|
|
||||||
Snippet = new PlaylistItemSnippet
|
|
||||||
{
|
|
||||||
PlaylistId = "WL",
|
|
||||||
ResourceId = new ResourceId
|
|
||||||
{
|
|
||||||
VideoId = item.Id,
|
|
||||||
Kind = "youtube#video"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
PlaylistItemsResource.InsertRequest request = SecretsVault.Service.PlaylistItems.Insert(playlist, "snippet");
|
|
||||||
|
|
||||||
await request.ExecuteAsync();
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
wl.IsChecked = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
wl.IsChecked = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void ContentDialog_PrimaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args)
|
|
||||||
{
|
|
||||||
string privacy = "private";
|
|
||||||
switch(newListDisc.SelectedIndex)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
privacy = "public";
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
privacy = "private";
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
privacy = "unlisted";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
Playlist newItem = new Playlist
|
|
||||||
{
|
|
||||||
Snippet = new PlaylistSnippet
|
|
||||||
{
|
|
||||||
Title = newListName.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;
|
|
||||||
addList.Items.Add(menuItem);
|
|
||||||
|
|
||||||
Item_Click(menuItem, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Left_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
Player.Player.Position = history.LeftOn;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void Report_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
await new ReportVideo(item.Id).ShowAsync();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -169,7 +169,7 @@
|
|||||||
<value>Skip forward for 30 seconds</value>
|
<value>Skip forward for 30 seconds</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="generatedCaption" xml:space="preserve">
|
<data name="generatedCaption" xml:space="preserve">
|
||||||
<value>(Auto-generated)</value>
|
<value>Auto-generated</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="goLive.Text" xml:space="preserve">
|
<data name="goLive.Text" xml:space="preserve">
|
||||||
<value>Go to live broadcast</value>
|
<value>Go to live broadcast</value>
|
||||||
|
|||||||
@@ -169,7 +169,7 @@
|
|||||||
<value>Вперед на 30 секунд</value>
|
<value>Вперед на 30 секунд</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="generatedCaption" xml:space="preserve">
|
<data name="generatedCaption" xml:space="preserve">
|
||||||
<value>(Авто-перевод)</value>
|
<value>Авто-перевод</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="goLive.Text" xml:space="preserve">
|
<data name="goLive.Text" xml:space="preserve">
|
||||||
<value>Перейти к прямому эфиру</value>
|
<value>Перейти к прямому эфиру</value>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<ResourceDictionary
|
<ResourceDictionary
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:local="using:FoxTube"
|
xmlns:local="using:FoxTube.Controls.Player"
|
||||||
xmlns:controls="using:FoxTube.Controls"
|
xmlns:controls="using:FoxTube.Controls"
|
||||||
xmlns:adverts="using:FoxTube.Controls.Adverts">
|
xmlns:adverts="using:FoxTube.Controls.Adverts">
|
||||||
|
|
||||||
@@ -294,6 +294,7 @@
|
|||||||
<KeyboardAccelerator Key="Space"/>
|
<KeyboardAccelerator Key="Space"/>
|
||||||
</Button.KeyboardAccelerators>
|
</Button.KeyboardAccelerators>
|
||||||
</Button>
|
</Button>
|
||||||
|
<Button x:Name="PreviousButton" Content="" Visibility="Collapsed"/>
|
||||||
<Button x:Name="NextButton" Content=""/>
|
<Button x:Name="NextButton" Content=""/>
|
||||||
<Button x:Name="VolumeMenuButton" Content="">
|
<Button x:Name="VolumeMenuButton" Content="">
|
||||||
<Button.Flyout>
|
<Button.Flyout>
|
||||||
|
|||||||
Reference in New Issue
Block a user