New arch (not working)
This commit is contained in:
+23
-232
@@ -1,30 +1,16 @@
|
||||
using Google.Apis.YouTube.v3.Data;
|
||||
using Microsoft.AppCenter;
|
||||
using FoxTube.Classes;
|
||||
using Microsoft.AppCenter.Analytics;
|
||||
using System;
|
||||
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.Background;
|
||||
using Windows.Globalization;
|
||||
using Windows.Storage;
|
||||
using Windows.System.Power;
|
||||
using Windows.UI.Notifications;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
|
||||
namespace FoxTube
|
||||
{
|
||||
sealed partial class App : Application
|
||||
{
|
||||
public static string[] AvailableLanguages => new[] { "en-US", "ru-RU" };
|
||||
|
||||
Stopwatch sw = new Stopwatch();
|
||||
public App()
|
||||
{
|
||||
SettingsStorage.LoadData();
|
||||
@@ -40,113 +26,30 @@ namespace FoxTube
|
||||
}
|
||||
ApplicationLanguages.PrimaryLanguageOverride = SettingsStorage.Language;
|
||||
|
||||
CheckVersion();
|
||||
|
||||
InitializeComponent();
|
||||
Suspending += OnSuspending;
|
||||
UnhandledException += UnhandledError;
|
||||
|
||||
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()
|
||||
Suspending += (s, e) => Processes.SuspendApp();
|
||||
UnhandledException += (s, e) => Analytics.TrackEvent("The app crashed", new Dictionary<string, string>()
|
||||
{
|
||||
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());
|
||||
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 }
|
||||
{ "Exception", e.Exception.GetType().ToString() },
|
||||
{ "Details", e.Message },
|
||||
{ "StackTrace", e.Exception.StackTrace }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Processes.InitializeApp();
|
||||
}
|
||||
|
||||
protected override void OnLaunched(LaunchActivatedEventArgs e)
|
||||
{
|
||||
if (!(Window.Current.Content is Frame rootFrame))
|
||||
{
|
||||
rootFrame = new Frame();
|
||||
rootFrame.NavigationFailed += OnNavigationFailed;
|
||||
Window.Current.Content = rootFrame;
|
||||
}
|
||||
if (!(Window.Current.Content is Frame))
|
||||
Window.Current.Content = new Frame();
|
||||
|
||||
if (e.PrelaunchActivated == false)
|
||||
{
|
||||
if (rootFrame.Content == null)
|
||||
rootFrame.Navigate(typeof(MainPage), e.Arguments);
|
||||
if ((Window.Current.Content as Frame).Content == null)
|
||||
(Window.Current.Content as Frame).Navigate(typeof(MainPage), e.Arguments);
|
||||
|
||||
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)
|
||||
@@ -154,50 +57,10 @@ namespace FoxTube
|
||||
var deferral = args.TaskInstance.GetDeferral();
|
||||
base.OnBackgroundActivated(args);
|
||||
|
||||
if (args.TaskInstance.Task.Name == "FoxtubeToastBackground" && args.TaskInstance.TriggerDetails is ToastNotificationActionTriggerDetail details)
|
||||
{
|
||||
string[] arguments = details.Argument.Split('|');
|
||||
if (args.TaskInstance.Task.Name == "FoxtubeToastBackground" || !(args.TaskInstance.TriggerDetails is ToastNotificationActionTriggerDetail details))
|
||||
return;
|
||||
|
||||
switch (arguments[0])
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
Processes.ProcessToast(details.Argument);
|
||||
|
||||
deferral.Complete();
|
||||
}
|
||||
@@ -206,7 +69,8 @@ namespace FoxTube
|
||||
{
|
||||
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.NavigationFailed += OnNavigationFailed;
|
||||
@@ -217,88 +81,15 @@ namespace FoxTube
|
||||
if (rootFrame.Content == null)
|
||||
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)
|
||||
ProcessToast((e as ToastNotificationActivatedEventArgs).Argument);
|
||||
Processes.ProcessToast((e as ToastNotificationActivatedEventArgs).Argument);
|
||||
else
|
||||
SecretsVault.AuthorizationStateChanged += (s, arg) => 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 }
|
||||
});
|
||||
SecretsVault.AuthorizationStateChanged += (arg) => Processes.ProcessToast((e as ToastNotificationActivatedEventArgs).Argument);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,7 @@ namespace FoxTube.Classes
|
||||
{
|
||||
class AdaptiveCommandBar : CommandBar
|
||||
{
|
||||
public AdaptiveCommandBar()
|
||||
{
|
||||
public AdaptiveCommandBar() =>
|
||||
ClosedDisplayMode = SettingsStorage.AppBarClosedMode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,26 +3,26 @@ using System.Collections.Generic;
|
||||
using Windows.Storage;
|
||||
using Newtonsoft.Json;
|
||||
using YoutubeExplode.Models.MediaStreams;
|
||||
using Google.Apis.YouTube.v3.Data;
|
||||
using FoxTube.Controls;
|
||||
using FoxTube.Pages;
|
||||
using Microsoft.AppCenter.Analytics;
|
||||
using YoutubeExplode.Models;
|
||||
|
||||
namespace FoxTube
|
||||
{
|
||||
public static class DownloadAgent
|
||||
{
|
||||
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 StorageFolder Downloads { get; set; }
|
||||
|
||||
public static async void Initialize()
|
||||
{
|
||||
Downloads = await KnownFolders.VideosLibrary.CreateFolderAsync("FoxTube", CreationCollisionOption.OpenIfExists);
|
||||
Items.Clear();
|
||||
try
|
||||
{
|
||||
Downloads = await KnownFolders.VideosLibrary.CreateFolderAsync("FoxTube", CreationCollisionOption.OpenIfExists);
|
||||
List<DownloadItemContainer> containers = JsonConvert.DeserializeObject<List<DownloadItemContainer>>((string)settings.Values[$"downloads"]);
|
||||
containers.ForEach(i => Items.Add(new DownloadItem(i)));
|
||||
}
|
||||
@@ -38,10 +38,8 @@ namespace FoxTube
|
||||
}
|
||||
}
|
||||
|
||||
public static void Add(MediaStreamInfo info, Video meta, string qualty)
|
||||
{
|
||||
Items.Insert(0, new DownloadItem(info, meta, qualty));
|
||||
}
|
||||
public static void Add((MediaStreamInfo info, Video meta, string qualty) e) =>
|
||||
Items.Insert(0, new DownloadItem(e.info, e.meta, e.qualty));
|
||||
|
||||
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 DateTime TimeStamp { get; set; }
|
||||
public string TimeStampString
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Type == InboxItemType.PatchNote)
|
||||
return TimeStamp.ToShortDateString();
|
||||
else
|
||||
return TimeStamp.ToString();
|
||||
}
|
||||
}
|
||||
public string TimeStampString => Type == InboxItemType.PatchNote ? TimeStamp.ToShortDateString() : TimeStamp.ToString();
|
||||
|
||||
public string Subject { get; set; }
|
||||
public string Content { get; set; }
|
||||
@@ -26,38 +17,10 @@ namespace FoxTube.Classes
|
||||
|
||||
private ResourceLoader resources = ResourceLoader.GetForCurrentView("Inbox");
|
||||
|
||||
public string Icon
|
||||
{
|
||||
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 Icon => Type == InboxItemType.PatchNote ? "\xE728" : "\xE119";
|
||||
public string Subtitle => Type == InboxItemType.PatchNote ? resources.GetString("changelog") : resources.GetString("dev");
|
||||
|
||||
public string Title => Type == InboxItemType.PatchNote ? $"{resources.GetString("whatsnew")}{Id}" : Subject;
|
||||
|
||||
public InboxItem(string version, string content, DateTime timeStamp)
|
||||
{
|
||||
|
||||
@@ -16,7 +16,7 @@ using Windows.ApplicationModel.Resources;
|
||||
using Windows.Storage;
|
||||
using YoutubeExplode.Models.MediaStreams;
|
||||
|
||||
namespace FoxTube.Controls.Player
|
||||
namespace FoxTube.Classes
|
||||
{
|
||||
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");
|
||||
representation.SetAttribute("bandwidth", GetBandwidth(info.Label));
|
||||
@@ -108,7 +108,7 @@ namespace FoxTube.Controls.Player
|
||||
return representation;
|
||||
}
|
||||
|
||||
private static XmlElement GetAudioPresentation(XmlDocument doc, StreamInfo.AudioInfo info)
|
||||
static XmlElement GetAudioPresentation(XmlDocument doc, StreamInfo.AudioInfo info)
|
||||
{
|
||||
XmlElement audio = doc.CreateElement("Representation");
|
||||
audio.SetAttribute("bandwidth", "200000");
|
||||
@@ -133,7 +133,7 @@ namespace FoxTube.Controls.Player
|
||||
return audio;
|
||||
}
|
||||
|
||||
private static async Task<StreamInfo> GetInfoAsync(Video info, VideoStreamInfo requestedQuality)
|
||||
static async Task<StreamInfo> GetInfoAsync(Video info, VideoStreamInfo requestedQuality)
|
||||
{
|
||||
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);
|
||||
string[] paramsEncoded = query.TrimStart('?').Split("&");
|
||||
@@ -221,7 +221,7 @@ namespace FoxTube.Controls.Player
|
||||
return dic;
|
||||
}
|
||||
|
||||
private static string GetBandwidth(string quality)
|
||||
static string GetBandwidth(string quality)
|
||||
{
|
||||
string parsed = quality.Split('p')[0];
|
||||
switch (quality)
|
||||
@@ -301,41 +301,4 @@ namespace FoxTube.Controls.Player
|
||||
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 Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
@@ -9,7 +10,6 @@ using System.Net.Mail;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using Windows.ApplicationModel.Core;
|
||||
using Windows.ApplicationModel.DataTransfer;
|
||||
using Windows.ApplicationModel.Resources;
|
||||
using Windows.Storage.Streams;
|
||||
@@ -26,21 +26,47 @@ namespace FoxTube
|
||||
|
||||
public delegate void ObjectEventHandler(object sender = null, params object[] args);
|
||||
|
||||
public interface INavigationPage
|
||||
{
|
||||
object Parameter { get; set; }
|
||||
}
|
||||
|
||||
public static class 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 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)
|
||||
@@ -49,10 +75,8 @@ namespace FoxTube
|
||||
catch { return null; }
|
||||
}
|
||||
|
||||
public static string GuardFromNull(string str)
|
||||
{
|
||||
return str ?? string.Empty;
|
||||
}
|
||||
public static string GuardFromNull(string str) =>
|
||||
str ?? string.Empty;
|
||||
|
||||
public static void SendMail(string content)
|
||||
{
|
||||
@@ -68,22 +92,6 @@ namespace FoxTube
|
||||
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)
|
||||
{
|
||||
List<object> list = new List<object>();
|
||||
@@ -93,22 +101,15 @@ namespace FoxTube
|
||||
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);
|
||||
}
|
||||
|
||||
public static T Find<T>(this IEnumerable<T> array, Predicate<T> match)
|
||||
{
|
||||
return array.ToList().Find(match);
|
||||
}
|
||||
public static T Find<T>(this IEnumerable<T> array, Predicate<T> match) =>
|
||||
array.ToList().Find(match);
|
||||
|
||||
public static List<T> FindAll<T>(this IEnumerable<T> array, Predicate<T> match)
|
||||
{
|
||||
return array.ToList().FindAll(match);
|
||||
}
|
||||
public static List<T> FindAll<T>(this IEnumerable<T> array, Predicate<T> match) =>
|
||||
array.ToList().FindAll(match);
|
||||
|
||||
[Obsolete]
|
||||
public static string ReplaceInvalidChars(this string str, char newValue)
|
||||
{
|
||||
foreach (char i in Path.GetInvalidFileNameChars())
|
||||
@@ -116,12 +117,7 @@ namespace FoxTube
|
||||
return str;
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
public static string Last(this string[] arr)
|
||||
{
|
||||
return arr[arr.Length - 1];
|
||||
}
|
||||
|
||||
[Obsolete("Use *YoutubeExplode.Models.Video instead*")]
|
||||
public static TimeSpan GetDuration(this string str)
|
||||
{
|
||||
try
|
||||
@@ -243,6 +239,8 @@ namespace FoxTube
|
||||
}
|
||||
|
||||
public async static void ProcessLink(string url)
|
||||
{
|
||||
try
|
||||
{
|
||||
string type;
|
||||
|
||||
@@ -274,19 +272,21 @@ namespace FoxTube
|
||||
switch (type)
|
||||
{
|
||||
case "channel":
|
||||
MainPage.GoToChannel(output);
|
||||
Navigation.GoToChannel(output);
|
||||
break;
|
||||
case "video":
|
||||
MainPage.GoToVideo(output);
|
||||
Navigation.GoToVideo(output);
|
||||
break;
|
||||
case "playlist":
|
||||
MainPage.GoToPlaylist(output);
|
||||
Navigation.GoToPlaylist(output);
|
||||
break;
|
||||
case "user":
|
||||
MainPage.GoToChannel(await new YoutubeClient().GetChannelIdAsync(output));
|
||||
Navigation.GoToChannel(await new YoutubeClient().GetChannelIdAsync(output));
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
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()));
|
||||
}
|
||||
|
||||
public static async Task<List<string>> GetHistory()
|
||||
public static async Task<YoutubeExplode.Models.Playlist> GetHistory()
|
||||
{
|
||||
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}");
|
||||
|
||||
dynamic raw = JsonConvert.DeserializeObject(output);
|
||||
foreach (dynamic i in raw.video)
|
||||
list.Add(i.encrypted_id.ToString());
|
||||
|
||||
return list;
|
||||
return await new YoutubeClient(SecretsVault.HttpClient).GetPlaylistAsync("HL");
|
||||
}
|
||||
|
||||
public static async Task<List<string>> GetLater()
|
||||
public static async Task<YoutubeExplode.Models.Playlist> GetLater()
|
||||
{
|
||||
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}");
|
||||
|
||||
dynamic raw = JsonConvert.DeserializeObject(output);
|
||||
foreach (dynamic i in raw.video)
|
||||
list.Add(i.encrypted_id.ToString());
|
||||
|
||||
return list;
|
||||
return await new YoutubeClient(SecretsVault.HttpClient).GetPlaylistAsync("WL");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.YouTube.v3;
|
||||
using Google.Apis.YouTube.v3.Data;
|
||||
using Newtonsoft.Json;
|
||||
using Windows.Storage;
|
||||
using Windows.Services.Store;
|
||||
using System.Net.Http;
|
||||
using Google.Apis.Oauth2.v2.Data;
|
||||
@@ -15,6 +13,8 @@ using Google.Apis.Oauth2.v2;
|
||||
using static Google.Apis.Auth.OAuth2.UwpCodeReceiver;
|
||||
using Microsoft.AppCenter.Analytics;
|
||||
using System.Net;
|
||||
using FoxTube.Classes;
|
||||
using System.Linq;
|
||||
|
||||
namespace FoxTube
|
||||
{
|
||||
@@ -22,12 +22,12 @@ namespace FoxTube
|
||||
{
|
||||
#region Properties
|
||||
//Events
|
||||
public static event ObjectEventHandler AuthorizationStateChanged;
|
||||
public static event ObjectEventHandler SubscriptionsChanged;
|
||||
public static event ObjectEventHandler Purchased; //Rising when app finds out that it's not a PRO version
|
||||
public static event AuthorizationChangedEventHandler AuthorizationStateChanged;
|
||||
public static event SubscriptionsChangedEventHandler SubscriptionsChanged;
|
||||
public static event ObjectEventHandler Purchased; //Rising when app finds out that it's not a PRO version or after purchase
|
||||
|
||||
//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
|
||||
{
|
||||
ClientId = "349735264870-2ekqlm0a4mkg3mmrfcv90s3qp3o15dq0.apps.googleusercontent.com",
|
||||
@@ -38,7 +38,7 @@ namespace FoxTube
|
||||
ApiKey = "AIzaSyBgHrCnrlzlVmk0cJKL8RqP9Y8x6XSuk_0",
|
||||
ApplicationName = "FoxTube"
|
||||
});
|
||||
public static BaseClientService.Initializer Initializer => new BaseClientService.Initializer
|
||||
private static BaseClientService.Initializer Initializer => new BaseClientService.Initializer
|
||||
{
|
||||
HttpClientInitializer = Credential,
|
||||
ApplicationName = "FoxTube"
|
||||
@@ -46,7 +46,7 @@ namespace FoxTube
|
||||
public static YouTubeService Service => IsAuthorized ? new YouTubeService(Initializer) : NoAuthService;
|
||||
|
||||
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 AdUnitId => TestAds ? "test" : "1100037769";
|
||||
public static bool AdsDisabled { get; private set; } = true;
|
||||
@@ -60,15 +60,13 @@ namespace FoxTube
|
||||
public static Userinfoplus UserInfo { get; private set; }
|
||||
|
||||
public static List<Subscription> Subscriptions { get; } = new List<Subscription>();
|
||||
public static List<string> History { get; set; } = new List<string>();
|
||||
public static List<string> WatchLater { get; set; } = new List<string>();
|
||||
public static YoutubeExplode.Models.Playlist History { get; set; }
|
||||
public static YoutubeExplode.Models.Playlist WatchLater { get; set; }
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
public static void RefreshToken()
|
||||
{
|
||||
public static void RefreshToken() =>
|
||||
Credential?.RefreshTokenAsync(CancellationToken.None);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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>
|
||||
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(s.Id).ExecuteAsync(); }
|
||||
try { await Service.Subscriptions.Delete(subscription.Id).ExecuteAsync(); }
|
||||
catch { return true; }
|
||||
|
||||
SubscriptionsChanged?.Invoke(null, "remove", s);
|
||||
Subscriptions.Remove(s);
|
||||
SubscriptionsChanged?.Invoke("remove", subscription);
|
||||
Subscriptions.Remove(subscription);
|
||||
|
||||
SaveSubscriptions();
|
||||
return false;
|
||||
}
|
||||
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,
|
||||
Kind = "youtube#channel"
|
||||
@@ -104,13 +99,12 @@ namespace FoxTube
|
||||
}
|
||||
}, "snippet");
|
||||
|
||||
Subscription s = await request.ExecuteAsync();
|
||||
if (s == null)
|
||||
if (!(await request.ExecuteAsync() is Subscription sub))
|
||||
return false;
|
||||
Subscriptions.Add(s);
|
||||
SubscriptionsChanged?.Invoke(null, "add", s);
|
||||
|
||||
SaveSubscriptions();
|
||||
Subscriptions.Add(sub);
|
||||
SubscriptionsChanged?.Invoke("add", sub);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -140,23 +134,17 @@ namespace FoxTube
|
||||
Oauth2Service.Scope.UserinfoProfile,
|
||||
Oauth2Service.Scope.UserinfoEmail,
|
||||
YouTubeService.Scope.YoutubeForceSsl,
|
||||
YouTubeService.Scope.Youtube,
|
||||
YouTubeService.Scope.YoutubeUpload,
|
||||
YouTubeService.Scope.YoutubeReadonly,
|
||||
YouTubeService.Scope.Youtubepartner
|
||||
YouTubeService.Scope.YoutubeUpload
|
||||
},
|
||||
"user",
|
||||
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"))
|
||||
return;
|
||||
else
|
||||
{
|
||||
AuthorizationStateChanged?.Invoke(args: new bool?[] { null });
|
||||
AuthorizationStateChanged?.Invoke(null);
|
||||
Analytics.TrackEvent("Failed to authorize", new Dictionary<string, string>
|
||||
{
|
||||
{ "Exception", e.GetType().ToString() },
|
||||
@@ -164,7 +152,6 @@ namespace FoxTube
|
||||
{ "StackTrace", e.StackTrace }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (Credential == null || !retrieveSubs)
|
||||
return;
|
||||
@@ -188,7 +175,6 @@ namespace FoxTube
|
||||
subRequest.Order = SubscriptionsResource.ListRequest.OrderEnum.Relevance;
|
||||
SubscriptionListResponse subResponse;
|
||||
string nextToken = null;
|
||||
Subscriptions.Clear();
|
||||
|
||||
do
|
||||
{
|
||||
@@ -200,22 +186,17 @@ namespace FoxTube
|
||||
|
||||
} while (!string.IsNullOrWhiteSpace(nextToken));
|
||||
|
||||
var request = Service.Channels.List("snippet,contentDetails");
|
||||
ChannelsResource.ListRequest request = Service.Channels.List("snippet,contentDetails");
|
||||
request.Mine = true;
|
||||
UserChannel = (await request.ExecuteAsync()).Items[0];
|
||||
UserChannel = (await request.ExecuteAsync()).Items.FirstOrDefault();
|
||||
#endregion
|
||||
|
||||
//Saving user's subscriptions for background task
|
||||
SaveSubscriptions();
|
||||
|
||||
AuthorizationStateChanged?.Invoke(args: true);
|
||||
AuthorizationStateChanged?.Invoke(true);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
AuthorizationStateChanged?.Invoke(args: new bool?[] { null });
|
||||
Methods.SendMail($@"Exception: {e.GetType()}
|
||||
Message: {e.Message}
|
||||
Stack trace: {e.StackTrace}");
|
||||
AuthorizationStateChanged?.Invoke(null);
|
||||
Methods.SendMail(e.ToString());
|
||||
Analytics.TrackEvent("Failed to retrieve user's info", new Dictionary<string, string>
|
||||
{
|
||||
{ "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>
|
||||
/// Deauthenticates current user
|
||||
/// </summary>
|
||||
@@ -273,12 +217,13 @@ Stack trace: {e.StackTrace}");
|
||||
Credential = null;
|
||||
UserChannel = null;
|
||||
UserInfo = null;
|
||||
History.Clear();
|
||||
WatchLater.Clear();
|
||||
History = null;
|
||||
WatchLater = null;
|
||||
Subscriptions.Clear();
|
||||
ApplicationData.Current.RoamingSettings.Values["subscriptions"] = "";
|
||||
|
||||
AuthorizationStateChanged?.Invoke(args: false);
|
||||
HttpClient.DefaultRequestHeaders.Authorization = null;
|
||||
|
||||
AuthorizationStateChanged?.Invoke(false);
|
||||
SettingsStorage.HasAccount = false;
|
||||
}
|
||||
|
||||
@@ -291,10 +236,7 @@ Stack trace: {e.StackTrace}");
|
||||
if (SettingsStorage.HasAccount)
|
||||
Authorize(retrieveSubs);
|
||||
else
|
||||
{
|
||||
AuthorizationStateChanged.Invoke(args: false);
|
||||
ApplicationData.Current.RoamingSettings.Values["subscriptions"] = "";
|
||||
}
|
||||
AuthorizationStateChanged.Invoke(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace FoxTube
|
||||
|
||||
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;
|
||||
else if ((new[] { "ua", "ru", "by", "kz", "kg", "md", "lv", "ee" }).Contains(CultureInfo.InstalledUICulture.TwoLetterISOLanguageName))
|
||||
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"
|
||||
mc:Ignorable="d"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Top"
|
||||
VerticalAlignment="Stretch"
|
||||
d:DesignHeight="290"
|
||||
d:DesignWidth="384"
|
||||
Visibility="Collapsed"
|
||||
Opacity="0"
|
||||
Name="card">
|
||||
|
||||
@@ -17,19 +16,9 @@
|
||||
<Storyboard x:Name="show">
|
||||
<DoubleAnimation Storyboard.TargetName="card" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="{StaticResource CardOpacityDuration}"/>
|
||||
</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>
|
||||
|
||||
<Button Padding="0" Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}">
|
||||
<Grid Name="grid">
|
||||
<Grid Name="grid" Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition Height="20"/>
|
||||
@@ -61,5 +50,4 @@
|
||||
|
||||
<TextBlock Grid.Row="2" Name="title" Text="[Title]" TextWrapping="WrapWholeWords" Margin="5" MaxLines="2" TextTrimming="CharacterEllipsis"/>
|
||||
</Grid>
|
||||
</Button>
|
||||
</UserControl>
|
||||
|
||||
@@ -12,8 +12,8 @@ namespace FoxTube.Controls.Adverts
|
||||
/// </summary>
|
||||
public sealed partial class CardAdvert : UserControl
|
||||
{
|
||||
NativeAdsManagerV2 manager = new NativeAdsManagerV2(SecretsVault.AppId, SecretsVault.AdUnitId);
|
||||
public NativeAdV2 advert;
|
||||
readonly NativeAdsManagerV2 manager = new NativeAdsManagerV2(SecretsVault.AppId, SecretsVault.AdUnitId);
|
||||
NativeAdV2 advert;
|
||||
public CardAdvert()
|
||||
{
|
||||
InitializeComponent();
|
||||
@@ -22,22 +22,21 @@ namespace FoxTube.Controls.Adverts
|
||||
manager.RequestAd();
|
||||
}
|
||||
|
||||
private void ErrorOccurred(object sender, NativeAdErrorEventArgs e)
|
||||
void ErrorOccurred(object sender, NativeAdErrorEventArgs e)
|
||||
{
|
||||
(Parent as AdaptiveGridView)?.Items.Remove(this);
|
||||
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;
|
||||
Initialize();
|
||||
e.NativeAd.RegisterAdContainer(grid);
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
void Initialize()
|
||||
{
|
||||
Visibility = Visibility.Visible;
|
||||
title.Text = advert.Title;
|
||||
image.Source = new BitmapImage(advert.MainImages.First().Url.ToUri());
|
||||
|
||||
@@ -57,13 +56,9 @@ namespace FoxTube.Controls.Adverts
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(advert.Rating))
|
||||
desc.Text += " " + advert.Rating;
|
||||
}
|
||||
|
||||
void Image_ImageOpened(object sender, RoutedEventArgs e) =>
|
||||
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>
|
||||
public sealed partial class CommentAdvert : UserControl
|
||||
{
|
||||
NativeAdsManagerV2 manager = new NativeAdsManagerV2(SecretsVault.AppId, SecretsVault.AdUnitId);
|
||||
public NativeAdV2 advert;
|
||||
readonly NativeAdsManagerV2 manager = new NativeAdsManagerV2(SecretsVault.AppId, SecretsVault.AdUnitId);
|
||||
NativeAdV2 advert;
|
||||
public CommentAdvert()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
manager.AdReady += AdReady;
|
||||
manager.ErrorOccurred += ErrorOccurred;
|
||||
manager.RequestAd();
|
||||
}
|
||||
|
||||
private void ErrorOccurred(object sender, NativeAdErrorEventArgs e)
|
||||
{
|
||||
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;
|
||||
Initialize();
|
||||
@@ -36,7 +30,7 @@ namespace FoxTube.Controls.Adverts
|
||||
e.NativeAd.RegisterAdContainer(grid, new List<FrameworkElement> { cta });
|
||||
}
|
||||
|
||||
private void Initialize()
|
||||
void Initialize()
|
||||
{
|
||||
title.Text = advert.Title;
|
||||
description.Text = Methods.GuardFromNull(advert.Description);
|
||||
|
||||
@@ -8,10 +8,9 @@ namespace FoxTube.Controls.Adverts
|
||||
{
|
||||
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;
|
||||
|
||||
DispatcherTimer timer = new DispatcherTimer()
|
||||
readonly DispatcherTimer timer = new DispatcherTimer
|
||||
{
|
||||
Interval = TimeSpan.FromMilliseconds(10000)
|
||||
};
|
||||
@@ -20,7 +19,6 @@ namespace FoxTube.Controls.Adverts
|
||||
InitializeComponent();
|
||||
|
||||
manager.AdReady += AdReady;
|
||||
manager.ErrorOccurred += ErrorOccurred;
|
||||
|
||||
timer.Tick += (s, e) =>
|
||||
{
|
||||
@@ -29,12 +27,7 @@ namespace FoxTube.Controls.Adverts
|
||||
};
|
||||
}
|
||||
|
||||
private void ErrorOccurred(object sender, NativeAdErrorEventArgs e)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine("Error has occured while loading ad");
|
||||
}
|
||||
|
||||
private void AdReady(object sender, NativeAdReadyEventArgs arg)
|
||||
void AdReady(object sender, NativeAdReadyEventArgs arg)
|
||||
{
|
||||
advert = arg.NativeAd;
|
||||
|
||||
@@ -68,12 +61,10 @@ namespace FoxTube.Controls.Adverts
|
||||
show.Begin();
|
||||
}
|
||||
|
||||
public void PushAdvert()
|
||||
{
|
||||
public void PushAdvert() =>
|
||||
manager.RequestAd();
|
||||
}
|
||||
|
||||
private void Button_Click(object sender, RoutedEventArgs e)
|
||||
void Button_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
timer.Stop();
|
||||
hide.Begin();
|
||||
|
||||
@@ -6,25 +6,21 @@
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Top"
|
||||
VerticalAlignment="Stretch"
|
||||
d:DesignHeight="290"
|
||||
d:DesignWidth="384"
|
||||
MaxWidth="700"
|
||||
MaxHeight="600"
|
||||
Opacity="0"
|
||||
Name="card"
|
||||
SizeChanged="Card_SizeChanged">
|
||||
Name="card">
|
||||
|
||||
<UserControl.Resources>
|
||||
<Storyboard x:Name="show">
|
||||
<DoubleAnimation Storyboard.TargetName="card" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="{StaticResource CardOpacityDuration}"/>
|
||||
</Storyboard>
|
||||
<Storyboard x:Name="showThumb">
|
||||
<DoubleAnimation Storyboard.TargetName="cover" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="{StaticResource CardOpacityDuration}"/>
|
||||
</Storyboard>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Button Padding="0" Margin="1" Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}" Click="Button_Click">
|
||||
<Grid Name="grid">
|
||||
<Grid Name="grid" Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition Height="50"/>
|
||||
@@ -33,7 +29,7 @@
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<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">
|
||||
<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"/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Button>
|
||||
|
||||
<UserControl.ContextFlyout>
|
||||
<MenuFlyout>
|
||||
<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 Microsoft.Toolkit.Uwp.UI.Controls;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.ApplicationModel.DataTransfer;
|
||||
using Windows.ApplicationModel.Resources;
|
||||
using Windows.System;
|
||||
@@ -16,32 +18,33 @@ namespace FoxTube.Controls
|
||||
/// <summary>
|
||||
/// Channel item card
|
||||
/// </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;
|
||||
|
||||
public ChannelCard(string id, string live = null)
|
||||
{
|
||||
InitializeComponent();
|
||||
Initialize(id, live);
|
||||
channelId = id;
|
||||
this.live = live;
|
||||
}
|
||||
|
||||
public async void Initialize(string id, string live)
|
||||
public async Task Initialize()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (id == SecretsVault.AccountId)
|
||||
if (channelId == SecretsVault.AccountId)
|
||||
grid.RowDefinitions[3].Height = new GridLength(0);
|
||||
|
||||
ChannelsResource.ListRequest request = SecretsVault.Service.Channels.List("snippet,statistics,brandingSettings");
|
||||
request.Id = id;
|
||||
request.Id = channelId;
|
||||
ChannelListResponse response = await request.ExecuteAsync();
|
||||
|
||||
item = response.Items[0];
|
||||
channelId = id;
|
||||
|
||||
title.Text = item.Snippet.Title;
|
||||
description.Text = item.Snippet.Description;
|
||||
@@ -54,7 +57,7 @@ namespace FoxTube.Controls
|
||||
|
||||
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.Foreground = new SolidColorBrush(Colors.Gray);
|
||||
@@ -63,10 +66,9 @@ namespace FoxTube.Controls
|
||||
subscriptionPane.Visibility = Visibility.Visible;
|
||||
}
|
||||
|
||||
try { avatar.ProfilePicture = new BitmapImage(new Uri(item.Snippet.Thumbnails.Medium.Url)) { DecodePixelWidth = 74, DecodePixelHeight = 74 }; }
|
||||
catch { }
|
||||
try
|
||||
{
|
||||
avatar.ProfilePicture = new BitmapImage(new Uri(item.Snippet.Thumbnails.Medium.Url)) { DecodePixelWidth = 74, DecodePixelHeight = 74 };
|
||||
if (!item.BrandingSettings.Image.BannerImageUrl.Contains("default"))
|
||||
cover.Source = new BitmapImage(item.BrandingSettings.Image.BannerMobileImageUrl.ToUri());
|
||||
}
|
||||
@@ -80,25 +82,22 @@ namespace FoxTube.Controls
|
||||
{
|
||||
{ "Exception", e.GetType().ToString() },
|
||||
{ "Message", e.Message },
|
||||
{ "Video ID", id },
|
||||
{ "Video ID", channelId },
|
||||
{ "StackTrace", e.StackTrace }
|
||||
});
|
||||
}
|
||||
|
||||
show.Begin();
|
||||
}
|
||||
|
||||
public void Button_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Methods.MainPage.GoToChannel(channelId);
|
||||
}
|
||||
public void ItemClicked() =>
|
||||
Navigation.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();
|
||||
}
|
||||
|
||||
private async void subscribe_Click(object sender, RoutedEventArgs e)
|
||||
async void subscribe_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
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();
|
||||
data.SetText($"https://www.youtube.com/channel/{item.Id}");
|
||||
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());
|
||||
}
|
||||
|
||||
private void Cover_ImageOpened(object sender, RoutedEventArgs e)
|
||||
{
|
||||
showThumb.Begin();
|
||||
}
|
||||
|
||||
private void Card_SizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
Height = e.NewSize.Width * 0.75;
|
||||
}
|
||||
void Cover_ImageOpened(object sender, RoutedEventArgs e) =>
|
||||
show.Begin();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Input;
|
||||
@@ -10,6 +9,7 @@ using Windows.UI.Xaml.Media.Imaging;
|
||||
using Windows.UI.Popups;
|
||||
using Windows.ApplicationModel.Resources;
|
||||
using Microsoft.AppCenter.Analytics;
|
||||
using FoxTube.Classes;
|
||||
|
||||
namespace FoxTube.Controls
|
||||
{
|
||||
@@ -135,12 +135,10 @@ namespace FoxTube.Controls
|
||||
catch { }
|
||||
}
|
||||
|
||||
private void replyBtn_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
replyEditor.Visibility = replyEditor.Visibility == Visibility.Visible ? Visibility.Collapsed : Visibility.Visible;
|
||||
}
|
||||
void replyBtn_Click(object sender, RoutedEventArgs e) =>
|
||||
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;
|
||||
|
||||
@@ -169,15 +167,11 @@ namespace FoxTube.Controls
|
||||
processing.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
|
||||
private void avatar_Tapped(object sender, TappedRoutedEventArgs e)
|
||||
{
|
||||
Methods.MainPage.GoToChannel(item.Snippet.AuthorChannelId.ToString().Split('"')[3]);
|
||||
}
|
||||
void avatar_Tapped(object sender, TappedRoutedEventArgs e) =>
|
||||
Navigation.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;
|
||||
}
|
||||
|
||||
private async void send_Click(object sender, RoutedEventArgs args)
|
||||
{
|
||||
@@ -283,10 +277,8 @@ namespace FoxTube.Controls
|
||||
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;
|
||||
}
|
||||
|
||||
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.Navigation;
|
||||
|
||||
@@ -10,26 +12,27 @@ namespace FoxTube.Controls
|
||||
public LoadingPage LoadingPage => loading;
|
||||
public event NavigatedEventHandler Navigated;
|
||||
|
||||
public new object Content => content.Content;
|
||||
|
||||
public ContentFrame()
|
||||
{
|
||||
InitializeComponent();
|
||||
content.Navigated += (s, e) => Navigated?.Invoke(s, e);
|
||||
}
|
||||
|
||||
private void Content_Navigating(object sender, NavigatingCancelEventArgs e)
|
||||
{
|
||||
loading.Refresh();
|
||||
}
|
||||
public void Navigate(Type sourcePageType, object parameter) =>
|
||||
content.Navigate(sourcePageType, parameter);
|
||||
|
||||
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.BackStack.RemoveAt(content.BackStack.Count - 1);
|
||||
}
|
||||
|
||||
public void Refresh()
|
||||
{
|
||||
public void Refresh() =>
|
||||
Loading_RefreshPage(this, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
d:DesignHeight="100"
|
||||
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.ColumnDefinitions>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
|
||||
@@ -7,7 +7,6 @@ using Windows.System;
|
||||
using YoutubeExplode.Models.MediaStreams;
|
||||
using YoutubeExplode;
|
||||
using Windows.Storage;
|
||||
using Google.Apis.YouTube.v3.Data;
|
||||
using System.Threading;
|
||||
using Windows.UI.Popups;
|
||||
using Windows.UI.Notifications;
|
||||
@@ -17,6 +16,8 @@ using Windows.ApplicationModel.Resources;
|
||||
using Microsoft.AppCenter.Analytics;
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
using YoutubeExplode.Models;
|
||||
using FoxTube.Classes;
|
||||
|
||||
namespace FoxTube.Controls
|
||||
{
|
||||
@@ -52,14 +53,14 @@ namespace FoxTube.Controls
|
||||
|
||||
Container = new DownloadItemContainer()
|
||||
{
|
||||
Channel = meta.Snippet.ChannelTitle,
|
||||
Duration = Methods.GetDuration(meta.ContentDetails.Duration),
|
||||
Channel = meta.Author,
|
||||
Duration = meta.Duration,
|
||||
Extension = info.Container.GetFileExtension(),
|
||||
Id = meta.Id,
|
||||
IsDownloaded = false,
|
||||
Quality = q,
|
||||
Thumbnail = meta.Snippet.Thumbnails.Medium.Url.ToUri(),
|
||||
Title = meta.Snippet.Title
|
||||
Thumbnail = meta.Thumbnails.MediumResUrl.ToUri(),
|
||||
Title = meta.Title
|
||||
};
|
||||
|
||||
Download(info);
|
||||
@@ -102,16 +103,16 @@ namespace FoxTube.Controls
|
||||
timer.Tick += (s, e) => UpdateInfo();
|
||||
|
||||
#region Polling notification
|
||||
ToastContent toastContent = new ToastContent()
|
||||
ToastContent toastContent = new ToastContent
|
||||
{
|
||||
Visual = new ToastVisual()
|
||||
Visual = new ToastVisual
|
||||
{
|
||||
BindingGeneric = new ToastBindingGeneric()
|
||||
BindingGeneric = new ToastBindingGeneric
|
||||
{
|
||||
Children =
|
||||
{
|
||||
new AdaptiveText() { Text = resources.GetString("/Downloads/toastStartHeader") },
|
||||
new AdaptiveProgressBar()
|
||||
new AdaptiveText { Text = resources.GetString("/Downloads/toastStartHeader") },
|
||||
new AdaptiveProgressBar
|
||||
{
|
||||
Title = Container.Title,
|
||||
Status = resources.GetString("/Downloads/downloading/Text"),
|
||||
@@ -121,7 +122,7 @@ namespace FoxTube.Controls
|
||||
}
|
||||
},
|
||||
|
||||
Actions = new ToastActionsCustom()
|
||||
Actions = new ToastActionsCustom
|
||||
{
|
||||
Buttons =
|
||||
{
|
||||
@@ -197,7 +198,7 @@ namespace FoxTube.Controls
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateInfo()
|
||||
void UpdateInfo()
|
||||
{
|
||||
progressBar.Value = percentage;
|
||||
progressText.Text = Math.Round(percentage * 100, 1) + "%";
|
||||
@@ -206,7 +207,7 @@ namespace FoxTube.Controls
|
||||
ToastNotificationManager.CreateToastNotifier().Update(data, $"download|{Container.Id}");
|
||||
}
|
||||
|
||||
private void DownloadCompleted()
|
||||
void DownloadCompleted()
|
||||
{
|
||||
Windows.Data.Xml.Dom.XmlDocument template = new Windows.Data.Xml.Dom.XmlDocument();
|
||||
template.LoadXml($@"<toast activationType='foreground' launch='download'>
|
||||
@@ -229,15 +230,11 @@ namespace FoxTube.Controls
|
||||
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);
|
||||
}
|
||||
|
||||
private void gotoOriginal_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Methods.MainPage.GoToVideo(Container.Id);
|
||||
}
|
||||
void gotoOriginal_Click(object sender, RoutedEventArgs e) =>
|
||||
Navigation.GoToVideo(Container.Id);
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using FoxTube.Controls;
|
||||
using FoxTube.Classes;
|
||||
using FoxTube.Controls;
|
||||
using FoxTube.Controls.Adverts;
|
||||
using FoxTube.Controls.Player;
|
||||
using Google.Apis.YouTube.v3.Data;
|
||||
@@ -6,57 +7,29 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.ApplicationModel.Resources;
|
||||
using Windows.Foundation;
|
||||
using Windows.Graphics.Display;
|
||||
using Windows.Media;
|
||||
using Windows.Media.Core;
|
||||
using Windows.UI.Core;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Controls.Primitives;
|
||||
using Windows.UI.Xaml.Media;
|
||||
using YoutubeExplode;
|
||||
using YoutubeExplode.Models.ClosedCaptions;
|
||||
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>
|
||||
/// Custom controls for media player. MARKUP IS IN **Themes/Generic.xaml**!!!
|
||||
/// </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
|
||||
Button minimize;
|
||||
@@ -64,6 +37,7 @@ namespace FoxTube
|
||||
Button miniview;
|
||||
Button play;
|
||||
Button next;
|
||||
Button prev;
|
||||
Button volumeMenu;
|
||||
Button mute;
|
||||
Button live;
|
||||
@@ -97,17 +71,12 @@ namespace FoxTube
|
||||
Grid centerTrigger;
|
||||
#endregion
|
||||
|
||||
PlayerDisplayState State { get; set; } = PlayerDisplayState.Normal;
|
||||
|
||||
public MediaElement Player { get; set; }
|
||||
public PlayerAdvert Advert;
|
||||
public LiveCaptions Caption;
|
||||
|
||||
TimeSpan timecodeBackup;
|
||||
bool needUpdateTimecode = false;
|
||||
|
||||
public Video Meta { get; set; }
|
||||
|
||||
public IReadOnlyList<ClosedCaptionTrackInfo> ClosedCaptions { get; set; }
|
||||
public MediaStreamInfoSet MediaStreams { get; set; }
|
||||
|
||||
@@ -125,11 +94,22 @@ namespace FoxTube
|
||||
|
||||
isReady = true;
|
||||
|
||||
Player.MediaOpened += Player_MediaOpened;
|
||||
Player.MarkerReached += (s, e) => PushAdvert();
|
||||
Player.CurrentStateChanged += Player_CurrentStateChanged;
|
||||
Caption.Player = Player;
|
||||
|
||||
minimize.Click += Minimize_Click;
|
||||
close.Click += Close_Click;
|
||||
miniview.Click += Miniview_Click;
|
||||
|
||||
mute.Click += async (s, e) =>
|
||||
{
|
||||
await Task.Delay(10);
|
||||
Volume_ValueChanged(this, null);
|
||||
};
|
||||
next.Click += Next_Click;
|
||||
prev.Click += Prev_Click;
|
||||
volume.ValueChanged += Volume_ValueChanged;
|
||||
playbackSpeed.ValueChanged += PlaybackSpeed_ValueChanged;
|
||||
live.Click += Live_Click;
|
||||
@@ -139,8 +119,19 @@ namespace FoxTube
|
||||
quality.SelectionChanged += Quality_SelectionChanged;
|
||||
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);
|
||||
Point p = e.GetPosition(centerTrigger);
|
||||
|
||||
@@ -160,10 +151,20 @@ namespace FoxTube
|
||||
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()
|
||||
{
|
||||
@@ -172,6 +173,7 @@ namespace FoxTube
|
||||
miniview = GetTemplateChild("CompactOverlayButton") as Button;
|
||||
play = GetTemplateChild("PlayPauseButton") as Button;
|
||||
next = GetTemplateChild("NextButton") as Button;
|
||||
prev = GetTemplateChild("PreviousButton") as Button;
|
||||
volumeMenu = GetTemplateChild("VolumeMenuButton") as Button;
|
||||
mute = GetTemplateChild("AudioMuteButton") as Button;
|
||||
live = GetTemplateChild("PlayLiveButton") as Button;
|
||||
@@ -207,14 +209,14 @@ namespace FoxTube
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
if(!needUpdateTimecode)
|
||||
timecodeBackup = Player.Position;
|
||||
@@ -227,7 +229,7 @@ namespace FoxTube
|
||||
if (info is MuxedStreamInfo)
|
||||
Player.SetPlaybackSource(MediaSource.CreateFromUri((info as MuxedStreamInfo).Url.ToUri()));
|
||||
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)
|
||||
Player.SetPlaybackSource(MediaSource.CreateFromUri((info as StreamQuality).Url));
|
||||
}
|
||||
@@ -256,9 +258,15 @@ namespace FoxTube
|
||||
|
||||
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)
|
||||
{
|
||||
if (State == PlayerDisplayState.Compact)
|
||||
@@ -267,11 +275,6 @@ namespace FoxTube
|
||||
EnterMiniview();
|
||||
}
|
||||
|
||||
public void UpdateVolumeIcon()
|
||||
{
|
||||
Volume_ValueChanged(this, null);
|
||||
}
|
||||
|
||||
private void Volume_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
|
||||
{
|
||||
double v = volume.Value;
|
||||
@@ -289,6 +292,13 @@ namespace FoxTube
|
||||
|
||||
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)
|
||||
return;
|
||||
|
||||
@@ -298,7 +308,10 @@ namespace FoxTube
|
||||
|
||||
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)
|
||||
@@ -314,6 +327,8 @@ namespace FoxTube
|
||||
if (State == PlayerDisplayState.Minimized)
|
||||
return;
|
||||
|
||||
//Methods.MainPage.MinimizeVideo(true);
|
||||
|
||||
header.Children.Remove(minimize);
|
||||
center.Children.Add(minimize);
|
||||
rightHeader.Children.Remove(close);
|
||||
@@ -331,7 +346,7 @@ namespace FoxTube
|
||||
|
||||
minimize.Content = "\xE010";
|
||||
|
||||
MiniModeChanged.Invoke(this, true);
|
||||
MiniModeChanged?.Invoke(true);
|
||||
Caption.Minimize();
|
||||
|
||||
State = PlayerDisplayState.Minimized;
|
||||
@@ -342,6 +357,8 @@ namespace FoxTube
|
||||
if (State == PlayerDisplayState.Normal)
|
||||
return;
|
||||
|
||||
//Methods.MainPage.MaximizeVideo(true);
|
||||
|
||||
if(State == PlayerDisplayState.Compact)
|
||||
{
|
||||
center.Children.Remove(miniview);
|
||||
@@ -370,7 +387,7 @@ namespace FoxTube
|
||||
centerStack.Children.Remove(bwd);
|
||||
rightFooter.Children.Insert(0, bwd);
|
||||
|
||||
MiniModeChanged.Invoke(this, false);
|
||||
MiniModeChanged?.Invoke(false);
|
||||
}
|
||||
|
||||
drag.Visibility = Visibility.Collapsed;
|
||||
@@ -413,120 +430,27 @@ namespace FoxTube
|
||||
State = PlayerDisplayState.Compact;
|
||||
}
|
||||
|
||||
public async void Load(Video meta)
|
||||
{
|
||||
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()
|
||||
void PushAdvert()
|
||||
{
|
||||
if(State == PlayerDisplayState.Normal)
|
||||
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:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:foxtube="using:FoxTube"
|
||||
xmlns:foxtube="using:FoxTube.Controls.Player"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="1080"
|
||||
d:DesignWidth="1920"
|
||||
|
||||
@@ -7,6 +7,7 @@ using Windows.UI.Xaml.Media.Imaging;
|
||||
using Windows.Media;
|
||||
using Windows.Storage.Streams;
|
||||
using Windows.UI.Xaml.Media;
|
||||
using FoxTube.Controls.Player;
|
||||
|
||||
namespace FoxTube
|
||||
{
|
||||
@@ -45,7 +46,7 @@ namespace FoxTube
|
||||
if (item.Snippet.LiveBroadcastContent == "none")
|
||||
{
|
||||
InitializeContols();
|
||||
Controls.Load(item);
|
||||
//Controls.Load(item);
|
||||
|
||||
if (Methods.GetDuration(item.ContentDetails.Duration).TotalMinutes > 5)
|
||||
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")
|
||||
{
|
||||
InitializeContols();
|
||||
Controls.Load(item);
|
||||
//Controls.Load(item);
|
||||
}
|
||||
else
|
||||
videoSource.AreTransportControlsEnabled = false;
|
||||
@@ -73,9 +74,9 @@ namespace FoxTube
|
||||
videoSource.AutoPlay = SettingsStorage.Autoplay;
|
||||
|
||||
Controls.CloseRequested += Controls_CloseRequested;
|
||||
Controls.NextRequested += (s, e) => NextClicked?.Invoke();
|
||||
Controls.NextRequested += () => NextClicked?.Invoke();
|
||||
Controls.MiniModeChanged += Controls_MiniModeChanged;
|
||||
Controls.Player = videoSource;
|
||||
//Controls.Player = videoSource;
|
||||
|
||||
#region System Media Transport Controls
|
||||
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;
|
||||
|
||||
@@ -125,7 +126,7 @@ namespace FoxTube
|
||||
Controls.Minimize();
|
||||
}
|
||||
|
||||
public void Controls_CloseRequested(object sender, RoutedEventArgs e)
|
||||
public void Controls_CloseRequested()
|
||||
{
|
||||
videoSource.Pause();
|
||||
systemControls.IsEnabled = false;
|
||||
@@ -137,7 +138,7 @@ namespace FoxTube
|
||||
HistorySet.Update(history);
|
||||
}
|
||||
|
||||
Methods.MainPage.CloseVideo();
|
||||
//Methods.MainPage.CloseVideo();
|
||||
}
|
||||
|
||||
public void Pause()
|
||||
@@ -161,12 +162,12 @@ namespace FoxTube
|
||||
{
|
||||
if(videoSource.Volume != 0)
|
||||
SettingsStorage.Volume = videoSource.Volume;
|
||||
Controls.UpdateVolumeIcon();
|
||||
//Controls.UpdateVolumeIcon();
|
||||
}
|
||||
|
||||
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"
|
||||
mc:Ignorable="d"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Top"
|
||||
VerticalAlignment="Stretch"
|
||||
d:DesignHeight="290"
|
||||
d:DesignWidth="384"
|
||||
MaxWidth="700"
|
||||
MaxHeight="600"
|
||||
Opacity="0"
|
||||
Name="card"
|
||||
SizeChanged="Card_SizeChanged">
|
||||
Name="card">
|
||||
|
||||
<UserControl.Resources>
|
||||
<Storyboard x:Name="show">
|
||||
<DoubleAnimation Storyboard.TargetName="card" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="{StaticResource CardOpacityDuration}"/>
|
||||
</Storyboard>
|
||||
<Storyboard x:Name="showThumb">
|
||||
<DoubleAnimation Storyboard.TargetName="thumbnail" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="{StaticResource CardOpacityDuration}"/>
|
||||
</Storyboard>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Button Padding="0" Margin="1" Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}" Click="Button_Click">
|
||||
<Grid>
|
||||
<Grid Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition Height="20"/>
|
||||
@@ -32,7 +28,7 @@
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<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.Background>
|
||||
@@ -58,7 +54,7 @@
|
||||
|
||||
<TextBlock Grid.Row="2" Name="title" Text="[Title]" TextWrapping="WrapWholeWords" TextTrimming="CharacterEllipsis" Margin="5" MaxLines="2"/>
|
||||
</Grid>
|
||||
</Button>
|
||||
|
||||
<UserControl.ContextFlyout>
|
||||
<MenuFlyout>
|
||||
<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 Microsoft.AppCenter.Analytics;
|
||||
using Microsoft.Toolkit.Uwp.UI.Controls;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.ApplicationModel.DataTransfer;
|
||||
using Windows.System;
|
||||
using Windows.UI.Xaml;
|
||||
@@ -16,24 +18,21 @@ namespace FoxTube.Controls
|
||||
/// <summary>
|
||||
/// Playlist card control
|
||||
/// </summary>
|
||||
public sealed partial class PlaylistCard : UserControl
|
||||
public sealed partial class PlaylistCard : UserControl, ICard
|
||||
{
|
||||
Playlist item;
|
||||
public string playlistId;
|
||||
|
||||
public bool NeedInitialize { get; set; } = true;
|
||||
readonly string playlistId;
|
||||
|
||||
public PlaylistCard(string id)
|
||||
{
|
||||
InitializeComponent();
|
||||
Initialize(id);
|
||||
playlistId = id;
|
||||
}
|
||||
|
||||
public async void Initialize(string id)
|
||||
public async Task Initialize()
|
||||
{
|
||||
try
|
||||
{
|
||||
playlistId = id;
|
||||
PlaylistsResource.ListRequest request = SecretsVault.Service.Playlists.List("snippet,contentDetails");
|
||||
request.Id = playlistId;
|
||||
request.Hl = SettingsStorage.RelevanceLanguage;
|
||||
@@ -44,17 +43,12 @@ namespace FoxTube.Controls
|
||||
counter.Text = item.ContentDetails.ItemCount.ToString();
|
||||
date.Text = Methods.GetAgo(item.Snippet.PublishedAt.Value);
|
||||
|
||||
ChannelsResource.ListRequest r = SecretsVault.Service.Channels.List("snippet");
|
||||
r.Id = item.Snippet.ChannelId;
|
||||
|
||||
try
|
||||
{
|
||||
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 { }
|
||||
|
||||
show.Begin();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -70,36 +64,26 @@ namespace FoxTube.Controls
|
||||
}
|
||||
}
|
||||
|
||||
public void Button_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Methods.MainPage.GoToPlaylist(item.Id);
|
||||
}
|
||||
public void ItemClicked() =>
|
||||
Navigation.GoToPlaylist(item.Id);
|
||||
|
||||
private void OpenChannel_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Methods.MainPage.GoToChannel(item.Snippet.ChannelId);
|
||||
}
|
||||
public void Button_Click(object sender, RoutedEventArgs e) =>
|
||||
ItemClicked();
|
||||
|
||||
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();
|
||||
data.SetText($"https://www.youtube.com/playlist?list={playlistId}");
|
||||
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());
|
||||
}
|
||||
|
||||
private void Thumbnail_ImageOpened(object sender, RoutedEventArgs e)
|
||||
{
|
||||
showThumb.Begin();
|
||||
}
|
||||
|
||||
private void Card_SizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
Height = e.NewSize.Width * 0.75;
|
||||
}
|
||||
void Thumbnail_ImageOpened(object sender, RoutedEventArgs e) =>
|
||||
show.Begin();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,10 +6,8 @@ namespace FoxTube.Controls
|
||||
public sealed partial class ShowMore : UserControl
|
||||
{
|
||||
public event Event Clicked;
|
||||
public ShowMore()
|
||||
{
|
||||
public ShowMore() =>
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void btn_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
@@ -18,17 +16,6 @@ namespace FoxTube.Controls
|
||||
Clicked.Invoke();
|
||||
}
|
||||
|
||||
public void Invoke()
|
||||
{
|
||||
btn_Click(this, null);
|
||||
}
|
||||
|
||||
public void Show()
|
||||
{
|
||||
btn.Visibility = Visibility.Collapsed;
|
||||
bar.Visibility = Visibility.Visible;
|
||||
}
|
||||
|
||||
public void Complete()
|
||||
{
|
||||
bar.Visibility = Visibility.Collapsed;
|
||||
|
||||
@@ -6,25 +6,21 @@
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Top"
|
||||
VerticalAlignment="Stretch"
|
||||
d:DesignHeight="290"
|
||||
d:DesignWidth="384"
|
||||
MaxWidth="700"
|
||||
MaxHeight="600"
|
||||
Opacity="0"
|
||||
Name="card"
|
||||
SizeChanged="Card_SizeChanged">
|
||||
Name="card">
|
||||
|
||||
<UserControl.Resources>
|
||||
<Storyboard x:Name="show">
|
||||
<DoubleAnimation Storyboard.TargetName="card" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="{StaticResource CardOpacityDuration}"/>
|
||||
</Storyboard>
|
||||
<Storyboard x:Name="showThumb">
|
||||
<DoubleAnimation Storyboard.TargetName="thumbnail" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="{StaticResource CardOpacityDuration}"/>
|
||||
</Storyboard>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Button Padding="0" Margin="1" Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}" Click="Button_Click">
|
||||
<Grid>
|
||||
<Grid Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition Height="20"/>
|
||||
@@ -32,20 +28,20 @@
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<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">
|
||||
<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"/>
|
||||
</StackPanel>
|
||||
<ProgressBar VerticalAlignment="Bottom" Margin="54,0,0,0" Foreground="Red" Name="leftOn"/>
|
||||
</Border>
|
||||
<ProgressBar VerticalAlignment="Bottom" Margin="54,0,0,0" Name="leftOn"/>
|
||||
</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"/>
|
||||
</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 x:Uid="/Cards/live" Name="liveContent" Text="LIVE" VerticalAlignment="Center" Foreground="White" FontSize="12" FontWeight="Bold"/>
|
||||
</StackPanel>
|
||||
@@ -64,7 +60,6 @@
|
||||
|
||||
<TextBlock Grid.Row="2" Name="title" Text="[Title]" TextWrapping="WrapWholeWords" Margin="5" MaxLines="2" TextTrimming="CharacterEllipsis"/>
|
||||
</Grid>
|
||||
</Button>
|
||||
<UserControl.ContextFlyout>
|
||||
<MenuFlyout>
|
||||
<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"/>
|
||||
<MenuFlyoutSeparator/>
|
||||
<MenuFlyoutSubItem x:Uid="/Cards/downloads" Icon="Download" Text="Download" Name="download"/>
|
||||
<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>
|
||||
<MenuFlyoutSubItem x:Uid="/Cards/addTo" Icon="Add" Text="Add to" Name="addTo"/>
|
||||
<MenuFlyoutItem x:Uid="/Cards/delete" Text="Remove from playlist" Icon="Delete" Visibility="Collapsed" Name="delete" Click="Delete_Click"/>
|
||||
</MenuFlyout>
|
||||
</UserControl.ContextFlyout>
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Google.Apis.YouTube.v3;
|
||||
using Google.Apis.YouTube.v3.Data;
|
||||
using Windows.UI.Xaml.Media.Imaging;
|
||||
using Windows.System;
|
||||
using Windows.ApplicationModel.DataTransfer;
|
||||
@@ -10,112 +9,108 @@ using Windows.ApplicationModel.Resources;
|
||||
using Microsoft.AppCenter.Analytics;
|
||||
using System.Collections.Generic;
|
||||
using YoutubeExplode;
|
||||
using YoutubeExplode.Models;
|
||||
using Windows.UI.Popups;
|
||||
using YoutubeExplode.Models.MediaStreams;
|
||||
using Windows.Foundation;
|
||||
using FoxTube.Pages;
|
||||
using Windows.Networking.Connectivity;
|
||||
using Microsoft.Toolkit.Uwp.UI.Controls;
|
||||
using FoxTube.Classes;
|
||||
using FoxTube.Controls.Common;
|
||||
using System.Threading.Tasks;
|
||||
using System.Linq;
|
||||
|
||||
namespace FoxTube.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Video item card
|
||||
/// </summary>
|
||||
public sealed partial class VideoCard : UserControl
|
||||
public sealed partial class VideoCard : UserControl, ICard
|
||||
{
|
||||
ResourceLoader resources = ResourceLoader.GetForCurrentView("Cards");
|
||||
|
||||
public string playlistId;
|
||||
readonly string playlistId;
|
||||
readonly string id;
|
||||
Video item;
|
||||
HistoryItem history;
|
||||
|
||||
Google.Apis.YouTube.v3.Data.Video liveItem;
|
||||
|
||||
public VideoCard(string id, string playlist = null)
|
||||
{
|
||||
InitializeComponent();
|
||||
Initialize(id, playlist);
|
||||
}
|
||||
|
||||
|
||||
public VideoCard(Video meta, string playlist = null)
|
||||
{
|
||||
InitializeComponent();
|
||||
item = meta;
|
||||
this.id = id;
|
||||
playlistId = playlist;
|
||||
LoadMeta();
|
||||
}
|
||||
|
||||
public async void Initialize(string id, string playlist = null)
|
||||
public async Task Initialize()
|
||||
{
|
||||
try
|
||||
{
|
||||
playlistId = playlist;
|
||||
delete.Visibility = string.IsNullOrWhiteSpace(playlistId) ? Visibility.Collapsed : Visibility.Visible;
|
||||
item = await new YoutubeClient(SecretsVault.HttpClient).GetVideoAsync(id);
|
||||
|
||||
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.Hl = SettingsStorage.RelevanceLanguage;
|
||||
item = (await request.ExecuteAsync()).Items[0];
|
||||
liveItem = (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;
|
||||
show.Begin();
|
||||
return;
|
||||
}
|
||||
|
||||
if (item.Snippet.LiveBroadcastContent == "live")
|
||||
if (liveItem.LiveStreamingDetails.ActualStartTime.HasValue)
|
||||
{
|
||||
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)}";
|
||||
views.Text = $"{liveItem.LiveStreamingDetails.ConcurrentViewers:0,0} {resources.GetString("/Cards/viewers")}";
|
||||
if (liveItem.LiveStreamingDetails.ScheduledStartTime.HasValue && liveItem.LiveStreamingDetails.ScheduledEndTime.HasValue)
|
||||
info.Text = $"{liveItem.LiveStreamingDetails.ScheduledEndTime - liveItem.LiveStreamingDetails.ActualStartTime} | {Methods.GetAgo(liveItem.LiveStreamingDetails.ActualStartTime.Value)}";
|
||||
else
|
||||
info.Text = Methods.GetAgo(item.LiveStreamingDetails.ActualStartTime.Value);
|
||||
liveTag.Visibility = Visibility.Visible;
|
||||
download.Visibility = Visibility.Collapsed;
|
||||
info.Text = Methods.GetAgo(liveItem.LiveStreamingDetails.ActualStartTime.Value);
|
||||
}
|
||||
else if (item.Snippet.LiveBroadcastContent == "upcoming")
|
||||
else
|
||||
{
|
||||
views.Text = "";
|
||||
if (item.LiveStreamingDetails.ScheduledStartTime.HasValue && item.LiveStreamingDetails.ScheduledEndTime.HasValue)
|
||||
info.Text = $"{item.LiveStreamingDetails.ScheduledEndTime - item.LiveStreamingDetails.ScheduledStartTime} | {item.LiveStreamingDetails.ScheduledStartTime}";
|
||||
if (liveItem.LiveStreamingDetails.ScheduledStartTime.HasValue && liveItem.LiveStreamingDetails.ScheduledEndTime.HasValue)
|
||||
info.Text = $"{liveItem.LiveStreamingDetails.ScheduledEndTime - liveItem.LiveStreamingDetails.ScheduledStartTime} | {liveItem.LiveStreamingDetails.ScheduledStartTime}";
|
||||
else
|
||||
info.Text = $"{Methods.GetAgo(item.Snippet.PublishedAt.Value)}";
|
||||
liveTag.Visibility = Visibility.Visible;
|
||||
info.Text = Methods.GetAgo(item.UploadDate.DateTime);
|
||||
|
||||
if (item.LiveStreamingDetails.ScheduledStartTime.HasValue)
|
||||
liveContent.Text = resources.GetString("/Cards/goesLive") + (item.LiveStreamingDetails.ScheduledStartTime.Value > DateTime.Now ? " " : " -") + (item.LiveStreamingDetails.ScheduledStartTime.Value - DateTime.Now).ToString(@"hh\:mm\:ss");
|
||||
if (liveItem.LiveStreamingDetails.ScheduledStartTime.HasValue)
|
||||
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");
|
||||
}
|
||||
liveTag.Visibility = Visibility.Visible;
|
||||
download.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
else
|
||||
{
|
||||
views.Text = $"{item.Statistics.ViewCount:0,0} {resources.GetString("/Cards/views")}";
|
||||
info.Text = $"{item.ContentDetails.Duration.GetDuration()} | {Methods.GetAgo(item.Snippet.PublishedAt.Value)}";
|
||||
LoadDownloads();
|
||||
info.Text = $"{item.Duration} | {item.UploadDate}";
|
||||
|
||||
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
|
||||
{
|
||||
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 };
|
||||
thumbnail.Source = new BitmapImage(item.Thumbnails.MediumResUrl.ToUri());
|
||||
avatar.ProfilePicture = new BitmapImage((await new YoutubeClient(SecretsVault.HttpClient).GetVideoAuthorChannelAsync(id)).LogoUrl.ToUri()) { DecodePixelHeight = 46, DecodePixelWidth = 46 };
|
||||
}
|
||||
catch { }
|
||||
|
||||
if (SecretsVault.History.Contains(item.Id))
|
||||
if (SecretsVault.History.Videos.Any(i => i.Id == id))
|
||||
watched.Visibility = Visibility.Visible;
|
||||
if (HistorySet.Items.Exists(i => i.Id == item.Id))
|
||||
{
|
||||
history = HistorySet.Items.Find(i => i.Id == item.Id);
|
||||
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)
|
||||
{
|
||||
@@ -133,95 +128,30 @@ namespace FoxTube.Controls
|
||||
}
|
||||
}
|
||||
|
||||
async void LoadDownloads()
|
||||
async void ValidatePlaylist()
|
||||
{
|
||||
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;
|
||||
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();
|
||||
if (string.IsNullOrWhiteSpace(playlistId) || !SecretsVault.IsAuthorized)
|
||||
return;
|
||||
}
|
||||
|
||||
if (item.Snippet.LiveBroadcastContent == "live")
|
||||
{
|
||||
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");
|
||||
}
|
||||
if (playlistId == "WL" || playlistId == SecretsVault.UserChannel.ContentDetails.RelatedPlaylists.Likes)
|
||||
delete.Visibility = Visibility.Visible;
|
||||
else
|
||||
{
|
||||
views.Text = $"{item.Statistics.ViewCount:0,0} {resources.GetString("/Cards/views")}";
|
||||
info.Text = $"{item.ContentDetails.Duration.GetDuration()} | {Methods.GetAgo(item.Snippet.PublishedAt.Value)}";
|
||||
PlaylistsResource.ListRequest playlistRequest = SecretsVault.Service.Playlists.List("snippet");
|
||||
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());
|
||||
avatar.ProfilePicture = new BitmapImage((await new YoutubeClient().GetChannelAsync(item.Snippet.ChannelId)).LogoUrl.ToUri()) { DecodePixelHeight = 50, DecodePixelWidth = 50 };
|
||||
public void ItemClicked() =>
|
||||
ItemClicked(false);
|
||||
|
||||
if (SecretsVault.History.Contains(item.Id))
|
||||
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)
|
||||
async void ItemClicked(bool incognito = false)
|
||||
{
|
||||
if (item.ContentDetails.ContentRating != null)
|
||||
if (liveItem.ContentDetails.ContentRating != null)
|
||||
{
|
||||
if (SecretsVault.IsAuthorized)
|
||||
{
|
||||
@@ -268,11 +198,11 @@ namespace FoxTube.Controls
|
||||
{
|
||||
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",
|
||||
VideoId = item.Id
|
||||
@@ -290,251 +220,37 @@ namespace FoxTube.Controls
|
||||
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,
|
||||
item.Snippet.Thumbnails.Medium.Url,
|
||||
item.Snippet.Title,
|
||||
$"https://www.youtube.com/watch?v={item.Id}",
|
||||
item.Thumbnails.MediumResUrl,
|
||||
item.Title,
|
||||
item.GetShortUrl(),
|
||||
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.ShowShareUI();
|
||||
}
|
||||
|
||||
private void ViewChannel_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Methods.MainPage.GoToChannel(item.Snippet.ChannelId);
|
||||
}
|
||||
async void ViewChannel_Click(object sender, RoutedEventArgs e) =>
|
||||
Navigation.GoToChannel((await new YoutubeClient(SecretsVault.HttpClient).GetVideoAuthorChannelAsync(id)).Id);
|
||||
|
||||
private void GetLink_Click(object sender, RoutedEventArgs e)
|
||||
void GetLink_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
DataPackage data = new DataPackage();
|
||||
data.SetText($"https://www.youtube.com/watch?v={item.Id}");
|
||||
data.SetText(item.GetShortUrl());
|
||||
Clipboard.SetContent(data);
|
||||
}
|
||||
|
||||
private async void InBrowser_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
await Launcher.LaunchUriAsync($"https://www.youtube.com/watch?v={item.Id}".ToUri());
|
||||
}
|
||||
async void InBrowser_Click(object sender, RoutedEventArgs e) =>
|
||||
await Launcher.LaunchUriAsync(item.GetShortUrl().ToUri());
|
||||
|
||||
private void Thumbnail_ImageOpened(object sender, RoutedEventArgs e)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
void Thumbnail_ImageOpened(object sender, RoutedEventArgs e) =>
|
||||
show.Begin();
|
||||
|
||||
private async void Delete_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
@@ -550,7 +266,7 @@ namespace FoxTube.Controls
|
||||
else
|
||||
{
|
||||
HistorySet.Delete(history);
|
||||
(Methods.MainPage.PageContent.Frame.Content as History).Delete(this);
|
||||
(Navigation.Frame.Frame.Content as History).Delete(this);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -559,23 +275,15 @@ namespace FoxTube.Controls
|
||||
PlaylistItemsResource.ListRequest request = SecretsVault.Service.PlaylistItems.List("snippet");
|
||||
request.PlaylistId = playlistId;
|
||||
request.VideoId = item.Id;
|
||||
PlaylistItemListResponse response = await request.ExecuteAsync();
|
||||
|
||||
PlaylistItem playlistItem = response.Items.Find(i => i.Snippet.PlaylistId == playlistId);
|
||||
|
||||
await SecretsVault.Service.PlaylistItems.Delete(playlistItem.Id).ExecuteAsync();
|
||||
|
||||
(Methods.MainPage.PageContent.Frame.Content as PlaylistPage).DeleteItem(this);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await SecretsVault.Service.PlaylistItems.Delete((await request.ExecuteAsync()).Items[0].Id).ExecuteAsync();
|
||||
|
||||
(Navigation.Frame.Frame.Content as PlaylistPage).DeleteItem(this);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
private void Card_SizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
Height = e.NewSize.Width * 0.75;
|
||||
}
|
||||
private void Button_Click(object sender, RoutedEventArgs e) =>
|
||||
ItemClicked(((FrameworkElement)sender).Name == "incognito" ? true : false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<UserControl
|
||||
x:Class="FoxTube.Controls.Chat"
|
||||
x:Class="FoxTube.Controls.VideoPage.Chat"
|
||||
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"
|
||||
xmlns:controls="using:FoxTube.Controls.VideoPage"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="600"
|
||||
d:DesignWidth="400">
|
||||
@@ -10,10 +10,11 @@ using System.Collections.Generic;
|
||||
using Windows.UI.Popups;
|
||||
using Windows.ApplicationModel.Resources;
|
||||
using Microsoft.Advertising.WinRT.UI;
|
||||
using Windows.UI.Xaml.Media.Imaging;
|
||||
using System.Linq;
|
||||
using FoxTube.Classes;
|
||||
using FoxTube.Controls.Adverts;
|
||||
|
||||
namespace FoxTube.Controls
|
||||
namespace FoxTube.Controls.VideoPage
|
||||
{
|
||||
public class ChatMessage
|
||||
{
|
||||
@@ -63,16 +64,12 @@ namespace FoxTube.Controls
|
||||
|
||||
private LiveChatMessage message;
|
||||
|
||||
public ChatMessage(LiveChatMessage item)
|
||||
{
|
||||
public ChatMessage(LiveChatMessage item) =>
|
||||
message = item;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed partial class Chat : UserControl
|
||||
{
|
||||
NativeAdsManagerV2 manager = new NativeAdsManagerV2(SecretsVault.AppId, SecretsVault.AdUnitId);
|
||||
public NativeAdV2 advert;
|
||||
string chatId;
|
||||
DateTime lastInsert;
|
||||
|
||||
@@ -81,7 +78,7 @@ namespace FoxTube.Controls
|
||||
|
||||
DispatcherTimer timer = new DispatcherTimer
|
||||
{
|
||||
Interval = TimeSpan.FromSeconds(1)
|
||||
Interval = TimeSpan.FromSeconds(3)
|
||||
};
|
||||
|
||||
DispatcherTimer adTimer = new DispatcherTimer
|
||||
@@ -104,130 +101,8 @@ namespace FoxTube.Controls
|
||||
if (SecretsVault.AdsDisabled)
|
||||
return;
|
||||
|
||||
adTimer.Tick += (s, e) => manager.RequestAd();
|
||||
adTimer.Tick += (s, e) => list.Items.Add(new ChatAdvert());
|
||||
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)
|
||||
@@ -241,10 +116,8 @@ namespace FoxTube.Controls
|
||||
timer.Start();
|
||||
}
|
||||
|
||||
private void HyperlinkButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Methods.MainPage.GoToChannel(((HyperlinkButton)sender).Tag as string);
|
||||
}
|
||||
private void HyperlinkButton_Click(object sender, RoutedEventArgs e) =>
|
||||
Navigation.GoToChannel(((HyperlinkButton)sender).Tag as string);
|
||||
|
||||
private async void send_Click(object sender, RoutedEventArgs args)
|
||||
{
|
||||
@@ -1,5 +1,5 @@
|
||||
<Page
|
||||
x:Class="FoxTube.Pages.CommentsPage"
|
||||
<UserControl
|
||||
x:Class="FoxTube.Controls.VideoPage.Comments"
|
||||
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"
|
||||
@@ -50,4 +50,4 @@
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</Page>
|
||||
</UserControl>
|
||||
@@ -9,12 +9,12 @@ using Windows.ApplicationModel.Resources;
|
||||
using Microsoft.AppCenter.Analytics;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FoxTube.Pages
|
||||
namespace FoxTube.Controls.VideoPage
|
||||
{
|
||||
/// <summary>
|
||||
/// Comments placeholder
|
||||
/// </summary>
|
||||
public sealed partial class CommentsPage : Page
|
||||
public sealed partial class Comments : UserControl
|
||||
{
|
||||
ResourceLoader resources = ResourceLoader.GetForCurrentView("CommentsPage");
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace FoxTube.Pages
|
||||
CommentThreadsResource.ListRequest.OrderEnum order = CommentThreadsResource.ListRequest.OrderEnum.Relevance;
|
||||
CommentThreadsResource.ListRequest request;
|
||||
|
||||
public CommentsPage()
|
||||
public Comments()
|
||||
{
|
||||
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">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<LangVersion>8.0</LangVersion>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
|
||||
<ProjectGuid>{2597B816-7316-4D20-BA6C-D78001E89C1A}</ProjectGuid>
|
||||
@@ -83,6 +84,7 @@
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
<LangVersion>default</LangVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<OutputPath>bin\x64\Release\</OutputPath>
|
||||
@@ -104,15 +106,27 @@
|
||||
<DependentUpon>App.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Classes\AdaptiveCommandBar.cs" />
|
||||
<Compile Include="Classes\Extensions.cs" />
|
||||
<Compile Include="Classes\HistorySet.cs" />
|
||||
<Compile Include="Classes\InboxItem.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\SettingsStorage.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">
|
||||
<DependentUpon>CardAdvert.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\Adverts\ChatAdvert.xaml.cs">
|
||||
<DependentUpon>ChatAdvert.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\Adverts\CommentAdvert.xaml.cs">
|
||||
<DependentUpon>CommentAdvert.xaml</DependentUpon>
|
||||
</Compile>
|
||||
@@ -122,7 +136,8 @@
|
||||
<Compile Include="Controls\ChannelCard.xaml.cs">
|
||||
<DependentUpon>ChannelCard.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\Chat.xaml.cs">
|
||||
<Compile Include="Controls\Common\DownloadSelector.cs" />
|
||||
<Compile Include="Controls\VideoPage\Chat.xaml.cs">
|
||||
<DependentUpon>Chat.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\CommentCard.xaml.cs">
|
||||
@@ -132,34 +147,44 @@
|
||||
<Compile Include="Controls\ContentFrame.xaml.cs">
|
||||
<DependentUpon>ContentFrame.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\Common\CreateAndAddPlaylist.xaml.cs">
|
||||
<DependentUpon>CreateAndAddPlaylist.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\DownloadItem.xaml.cs">
|
||||
<DependentUpon>DownloadItem.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\LiveCaptions.xaml.cs">
|
||||
<Compile Include="Controls\Player\LiveCaptions.xaml.cs">
|
||||
<DependentUpon>LiveCaptions.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\Player\PlayerControls.cs" />
|
||||
<Compile Include="Controls\Player\PlayerMain.cs" />
|
||||
<Compile Include="Controls\PlaylistCard.xaml.cs">
|
||||
<DependentUpon>PlaylistCard.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\ReportVideo.xaml.cs">
|
||||
<Compile Include="Controls\VideoPage\ReportVideo.xaml.cs">
|
||||
<DependentUpon>ReportVideo.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\ShowMore.xaml.cs">
|
||||
<DependentUpon>ShowMore.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Pages\Browser.xaml.cs">
|
||||
<DependentUpon>Browser.xaml</DependentUpon>
|
||||
<Compile Include="Controls\VideoPage\RelatedVideos.xaml.cs">
|
||||
<DependentUpon>RelatedVideos.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\VideoPage\VideoPlaylist.xaml.cs">
|
||||
<DependentUpon>VideoPlaylist.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Pages\ChannelPage.xaml.cs">
|
||||
<DependentUpon>ChannelPage.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Pages\CommentsPage.xaml.cs">
|
||||
<DependentUpon>CommentsPage.xaml</DependentUpon>
|
||||
<Compile Include="Controls\VideoPage\Comments.xaml.cs">
|
||||
<DependentUpon>Comments.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Pages\Downloads.xaml.cs">
|
||||
<DependentUpon>Downloads.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Pages\MainFrame.xaml.cs">
|
||||
<DependentUpon>MainFrame.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Pages\SettingsPages\About.xaml.cs">
|
||||
<DependentUpon>About.xaml</DependentUpon>
|
||||
</Compile>
|
||||
@@ -293,10 +318,18 @@
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</ApplicationDefinition>
|
||||
<Page Include="Controls\Common\AccountManager.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Controls\Adverts\CardAdvert.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Controls\Adverts\ChatAdvert.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Controls\Adverts\CommentAdvert.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
@@ -309,7 +342,7 @@
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Controls\Chat.xaml">
|
||||
<Page Include="Controls\VideoPage\Chat.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
@@ -321,11 +354,15 @@
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Controls\Common\CreateAndAddPlaylist.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Controls\DownloadItem.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Controls\LiveCaptions.xaml">
|
||||
<Page Include="Controls\Player\LiveCaptions.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
@@ -333,7 +370,7 @@
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Controls\ReportVideo.xaml">
|
||||
<Page Include="Controls\VideoPage\ReportVideo.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
@@ -341,7 +378,11 @@
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</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>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
@@ -349,7 +390,7 @@
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Pages\CommentsPage.xaml">
|
||||
<Page Include="Controls\VideoPage\Comments.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
@@ -357,6 +398,10 @@
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Pages\MainFrame.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Pages\SettingsPages\About.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<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 Microsoft.AppCenter.Analytics;
|
||||
using System.Collections.Generic;
|
||||
using FoxTube.Classes;
|
||||
|
||||
namespace FoxTube.Pages
|
||||
{
|
||||
@@ -105,21 +106,21 @@ namespace FoxTube.Pages
|
||||
|
||||
ScrollViewer_ViewChanged(this, null);
|
||||
|
||||
Methods.MainPage.PageContent.LoadingPage.Close();
|
||||
Navigation.Frame.Frame.LoadingPage.Close();
|
||||
}
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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>()
|
||||
{
|
||||
{ "Exception", e.GetType().ToString() },
|
||||
@@ -267,7 +268,7 @@ namespace FoxTube.Pages
|
||||
|
||||
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)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using FoxTube.Controls;
|
||||
using FoxTube.Classes;
|
||||
using FoxTube.Controls;
|
||||
using System;
|
||||
using Windows.System;
|
||||
using Windows.UI.Xaml;
|
||||
@@ -24,7 +25,7 @@ namespace FoxTube.Pages
|
||||
|
||||
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)
|
||||
@@ -34,10 +35,8 @@ namespace FoxTube.Pages
|
||||
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);
|
||||
}
|
||||
|
||||
public void Remove(DownloadItem item)
|
||||
{
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
</Grid.RowDefinitions>
|
||||
<Pivot SelectionChanged="Pivot_SelectionChanged">
|
||||
<PivotItem x:Uid="/Playlist/appHistory" Header="Application">
|
||||
<Grid>
|
||||
<ScrollViewer>
|
||||
<StackPanel>
|
||||
<Grid Margin="0,10" BorderBrush="Red" BorderThickness="5" CornerRadius="10" Padding="10">
|
||||
@@ -39,9 +38,6 @@
|
||||
<controls:ShowMore x:Name="more" Clicked="ShowMore_Clicked"/>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
<foxtube:LoadingPage x:Name="loading" Visibility="Collapsed" RefreshPage="Refresh_Click"/>
|
||||
</Grid>
|
||||
</PivotItem>
|
||||
<PivotItem x:Uid="/Playlist/webHistory" Header="Website">
|
||||
<Grid>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using FoxTube.Controls;
|
||||
using FoxTube.Classes;
|
||||
using FoxTube.Controls;
|
||||
using Microsoft.AppCenter.Analytics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -20,10 +21,8 @@ namespace FoxTube.Pages
|
||||
int page = 1;
|
||||
int webPage = 0;
|
||||
|
||||
public History()
|
||||
{
|
||||
public History() =>
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
@@ -31,15 +30,14 @@ namespace FoxTube.Pages
|
||||
Parameter = e.Parameter;
|
||||
|
||||
Initialize();
|
||||
Methods.MainPage.PageContent.LoadingPage.Close();
|
||||
}
|
||||
|
||||
public async void Initialize()
|
||||
{
|
||||
Methods.MainPage.VideoContent.LoadingPage.Close();
|
||||
Navigation.Frame.Frame.LoadingPage.Close();
|
||||
try
|
||||
{
|
||||
loading.Refresh();
|
||||
Navigation.Frame.Frame.LoadingPage.Refresh();
|
||||
|
||||
await Dispatcher.RunIdleAsync((command) =>
|
||||
{
|
||||
@@ -53,11 +51,11 @@ namespace FoxTube.Pages
|
||||
clear.Visibility = Visibility.Collapsed;
|
||||
});
|
||||
|
||||
loading.Close();
|
||||
Navigation.Frame.Frame.LoadingPage.Close();
|
||||
}
|
||||
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>()
|
||||
{
|
||||
{ "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());
|
||||
}
|
||||
|
||||
private void Refresh_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Methods.MainPage.PageContent.Refresh();
|
||||
}
|
||||
private void Refresh_Click(object sender, RoutedEventArgs e) =>
|
||||
Navigation.Frame.Refresh();
|
||||
|
||||
private async void ShowMore_Clicked()
|
||||
{
|
||||
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
|
||||
private async void ShowMore_Clicked() => await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
|
||||
{
|
||||
for (int k = 25 * page++; k < 25 * page && k < HistorySet.Items.Count; k++)
|
||||
list.Add(new VideoCard(HistorySet.Items[k].Id, "HL"));
|
||||
@@ -89,7 +81,6 @@ namespace FoxTube.Pages
|
||||
else
|
||||
more.Complete();
|
||||
});
|
||||
}
|
||||
|
||||
private async void Clear_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
@@ -117,8 +108,6 @@ namespace FoxTube.Pages
|
||||
}
|
||||
|
||||
async void LoadWeb()
|
||||
{
|
||||
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -126,10 +115,10 @@ namespace FoxTube.Pages
|
||||
|
||||
SecretsVault.History = await Methods.GetHistory();
|
||||
|
||||
for (int k = 0; k < 25 && k < SecretsVault.History.Count; k++)
|
||||
websiteList.Add(new VideoCard(SecretsVault.History[k], "HL"));
|
||||
for (int k = 0; k < 25 && k < SecretsVault.History.Videos.Count; k++)
|
||||
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;
|
||||
|
||||
websiteLoading.Close();
|
||||
@@ -144,26 +133,20 @@ namespace FoxTube.Pages
|
||||
{ "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.Count; k++)
|
||||
websiteList.Add(new VideoCard(SecretsVault.History[k], "HL"));
|
||||
for (int k = 25 * webPage++; k < 25 * webPage && k < SecretsVault.History.Videos.Count; k++)
|
||||
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;
|
||||
else
|
||||
websiteMore.Complete();
|
||||
});
|
||||
}
|
||||
|
||||
public void Delete (VideoCard item)
|
||||
{
|
||||
public void Delete (VideoCard item) =>
|
||||
list.DeleteItem(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ using FoxTube.Controls;
|
||||
using System.Net.Http;
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.AppCenter.Analytics;
|
||||
using FoxTube.Classes;
|
||||
|
||||
namespace FoxTube
|
||||
{
|
||||
@@ -42,7 +43,7 @@ namespace FoxTube
|
||||
|
||||
private void pivot_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
Methods.MainPage.PageContent.LoadingPage.Close();
|
||||
Navigation.Frame.Frame.LoadingPage.Close();
|
||||
|
||||
if (pivot.SelectedItem == recommended && !recLoaded)
|
||||
LoadRecommendations();
|
||||
@@ -96,7 +97,7 @@ namespace FoxTube
|
||||
{
|
||||
trendsLoading.Refresh();
|
||||
|
||||
trendsRequest = SecretsVault.Service.Videos.List("snippet,contentDetails,statistics,liveStreamingDetails");
|
||||
trendsRequest = SecretsVault.Service.Videos.List("id");
|
||||
trendsRequest.MaxResults = 25;
|
||||
|
||||
trendsRequest.Chart = VideosResource.ListRequest.ChartEnum.MostPopular;
|
||||
@@ -108,7 +109,7 @@ namespace FoxTube
|
||||
trendingMore.Visibility = string.IsNullOrWhiteSpace(response.NextPageToken) ? Visibility.Collapsed : Visibility.Visible;
|
||||
|
||||
foreach (Video i in response.Items)
|
||||
trendGrid.Add(new VideoCard(i));
|
||||
trendGrid.Add(new VideoCard(i.Id));
|
||||
|
||||
trendsLoading.Close();
|
||||
trendLoaded = true;
|
||||
@@ -170,8 +171,7 @@ namespace FoxTube
|
||||
#region More requests
|
||||
private void Recommended_More()
|
||||
{
|
||||
int l = 25 + recGrid.Count;
|
||||
for (int k = recGrid.Count; k < l && k < homeList.Count; k++)
|
||||
for (int k = recGrid.Count; k < 25 + recGrid.Count && k < homeList.Count; k++)
|
||||
recGrid.Add(new VideoCard(homeList[k]));
|
||||
|
||||
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;
|
||||
|
||||
foreach (Video i in response.Items)
|
||||
trendGrid.Add(new VideoCard(i));
|
||||
trendGrid.Add(new VideoCard(i.Id));
|
||||
|
||||
trendingMore.Complete();
|
||||
}
|
||||
private void Subscriptions_More()
|
||||
{
|
||||
int l = 25 + subsGrid.Count;
|
||||
for (int k = subsGrid.Count; k < l && k < subsList.Count; k++)
|
||||
for (int k = subsGrid.Count; k < 25 + subsGrid.Count && k < subsList.Count; k++)
|
||||
subsGrid.Add(new VideoCard(subsList[k]));
|
||||
|
||||
subscriptionsMore.Visibility = subsGrid.Count >= subsList.Count ? Visibility.Collapsed : Visibility.Visible;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using Windows.ApplicationModel.Resources;
|
||||
using Windows.System;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
@@ -12,15 +13,13 @@ namespace FoxTube
|
||||
/// </summary>
|
||||
public sealed partial class LoadingPage : Page
|
||||
{
|
||||
ResourceLoader resources = ResourceLoader.GetForCurrentView("LoadingPage");
|
||||
readonly ResourceLoader resources = ResourceLoader.GetForCurrentView("LoadingPage");
|
||||
|
||||
public event RoutedEventHandler RefreshPage;
|
||||
public LoadingState State { get; private set; } = LoadingState.Loadnig;
|
||||
|
||||
public LoadingPage()
|
||||
{
|
||||
public LoadingPage() =>
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public void Error(string exceptionId = "Unknown", string details = "N/A", bool isWifiTrouble = false)
|
||||
{
|
||||
@@ -47,39 +46,6 @@ namespace FoxTube
|
||||
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()
|
||||
{
|
||||
Visibility = Visibility.Visible;
|
||||
@@ -97,5 +63,32 @@ namespace FoxTube
|
||||
|
||||
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"
|
||||
mc:Ignorable="d"
|
||||
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">
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
@@ -35,43 +39,23 @@
|
||||
Style="{StaticResource CaptionTextBlockStyle}" />
|
||||
</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>
|
||||
<Grid>
|
||||
<TextBlock Name="Title" Style="{StaticResource TitleTextBlockStyle}"/>
|
||||
<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/signIn" Name="account" Click="SignIn_Click" Visibility="Collapsed" FontFamily="Segoe MDL2 Assets" Content="" Background="Transparent" Height="41" Width="60" FontSize="15"/>
|
||||
<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>
|
||||
<common:AccountManager x:Name="manager"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</ui:NavigationView.Header>
|
||||
|
||||
<ui:NavigationView.MenuItemTemplate>
|
||||
<DataTemplate>
|
||||
<StackPanel Orientation="Horizontal" Padding="5" Margin="-5,0,0,0" Tag="{Binding Snippet.ResourceId.ChannelId}">
|
||||
<DataTemplate x:DataType="data:Subscription">
|
||||
<StackPanel Orientation="Horizontal" Padding="5" Margin="-5,0,0,0">
|
||||
<PersonPicture Height="20" Margin="-5,0,15,0">
|
||||
<PersonPicture.ProfilePicture>
|
||||
<BitmapImage UriSource="{Binding Snippet.Thumbnails.Medium.Url}" DecodePixelHeight="20" DecodePixelWidth="20"/>
|
||||
@@ -99,21 +83,17 @@
|
||||
</ui:NavigationView.MenuItems>
|
||||
|
||||
<ui:NavigationView.PaneFooter>
|
||||
<ui:NavigationViewItem Content="Remove ads" Visibility="Collapsed" Tapped="RemoveAds_Tapped" Name="removeAds">
|
||||
<ui:NavigationViewItem.Icon>
|
||||
<FontIcon Glyph=""/>
|
||||
</ui:NavigationViewItem.Icon>
|
||||
</ui:NavigationViewItem>
|
||||
<ui:NavigationViewList>
|
||||
<ui:NavigationViewItemSeparator/>
|
||||
<ui:NavigationViewItem Content="Remove ads" Visibility="Collapsed" Tapped="RemoveAds_Tapped" Name="removeAds" Icon="Shop"/>
|
||||
</ui:NavigationViewList>
|
||||
</ui:NavigationView.PaneFooter>
|
||||
|
||||
<ui:NavigationView.AutoSuggestBox>
|
||||
<AutoSuggestBox x:Name="search" QueryIcon="Find" QuerySubmitted="Search_QuerySubmitted" TextChanged="Search_TextChanged" x:Uid="/Main/searchPlaceholder" PlaceholderText="Search"/>
|
||||
</ui:NavigationView.AutoSuggestBox>
|
||||
|
||||
<Grid>
|
||||
<controls:ContentFrame x:Name="content" Navigated="Content_Navigated"/>
|
||||
<controls:ContentFrame x:Name="videoPlaceholder"/>
|
||||
</Grid>
|
||||
<pages:MainFrame x:Name="content" Navigated="Content_Navigated"/>
|
||||
|
||||
</ui:NavigationView>
|
||||
</Grid>
|
||||
|
||||
+131
-449
@@ -1,27 +1,19 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using Windows.UI;
|
||||
using Windows.UI.ViewManagement;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Input;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
using Windows.UI.Xaml.Media.Imaging;
|
||||
using Google.Apis.YouTube.v3.Data;
|
||||
using Windows.ApplicationModel.Core;
|
||||
using Windows.System;
|
||||
using FoxTube.Pages;
|
||||
using Windows.UI.Popups;
|
||||
using Windows.ApplicationModel.Resources;
|
||||
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.Linq;
|
||||
using FoxTube.Classes;
|
||||
|
||||
namespace FoxTube
|
||||
{
|
||||
@@ -30,12 +22,10 @@ namespace FoxTube
|
||||
/// </summary>
|
||||
public sealed partial class MainPage : Page
|
||||
{
|
||||
bool wasInvoked = false;
|
||||
readonly ResourceLoader resources = ResourceLoader.GetForCurrentView("Main");
|
||||
Dictionary<Type, string> headers;
|
||||
readonly Dictionary<Type, string> headers;
|
||||
|
||||
public ContentFrame PageContent => content;
|
||||
public ContentFrame VideoContent => videoPlaceholder;
|
||||
public new MainFrame Content => content;
|
||||
|
||||
public MainPage()
|
||||
{
|
||||
@@ -70,129 +60,21 @@ namespace FoxTube
|
||||
}
|
||||
|
||||
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.CancelCommandIndex = 1;
|
||||
dialog.DefaultCommandIndex = 0;
|
||||
await dialog.ShowAsync();
|
||||
};
|
||||
SecretsVault.Initialize();
|
||||
|
||||
if (SecretsVault.IsAuthorized)
|
||||
AuthorizationStateChanged(true);
|
||||
|
||||
if (!SecretsVault.AdsDisabled)
|
||||
SecretsVault.CheckAddons();
|
||||
|
||||
if(StoreServicesFeedbackLauncher.IsSupported())
|
||||
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)
|
||||
@@ -212,49 +94,38 @@ namespace FoxTube
|
||||
titleBar.ButtonPressedBackgroundColor = Colors.DarkRed;
|
||||
titleBar.ButtonInactiveBackgroundColor = Colors.Transparent;
|
||||
titleBar.ButtonInactiveForegroundColor = Colors.Gray;
|
||||
|
||||
if(RequestedTheme == ElementTheme.Dark || (RequestedTheme == ElementTheme.Default && Application.Current.RequestedTheme == ApplicationTheme.Dark))
|
||||
titleBar.ButtonForegroundColor = Colors.White;
|
||||
else
|
||||
titleBar.ButtonForegroundColor = Colors.Black;
|
||||
titleBar.ButtonForegroundColor = Application.Current.RequestedTheme == ApplicationTheme.Dark ? Colors.Black : Colors.White;
|
||||
}
|
||||
|
||||
private void SecretsVault_SubscriptionsChanged(object sender, params object[] args)
|
||||
void SecretsVault_SubscriptionsChanged(string action, Subscription subscription)
|
||||
{
|
||||
switch((string)args[0])
|
||||
switch(action)
|
||||
{
|
||||
case "add":
|
||||
subsHeader.Visibility = Visibility.Visible;
|
||||
if (nav.MenuItems.Count < 19)
|
||||
nav.MenuItems.Add(args[1] as Subscription);
|
||||
nav.MenuItems.Add(subscription);
|
||||
break;
|
||||
|
||||
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)
|
||||
nav.MenuItems.Add(SecretsVault.Subscriptions[9]);
|
||||
else if (SecretsVault.Subscriptions.Count == 0)
|
||||
subsHeader.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private async void AuthorizationStateChanged(object sender, params object[] e)
|
||||
async void AuthorizationStateChanged(bool? isAuthozied)
|
||||
{
|
||||
wasInvoked = false;
|
||||
|
||||
switch (e[0] as bool?)
|
||||
switch (isAuthozied)
|
||||
{
|
||||
case true:
|
||||
account.Visibility = Visibility.Collapsed;
|
||||
|
||||
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;
|
||||
manager.Logged();
|
||||
|
||||
toChannel.Visibility = Visibility.Visible;
|
||||
toSubscriptions.Visibility = Visibility.Visible;
|
||||
@@ -270,21 +141,10 @@ namespace FoxTube
|
||||
nav.MenuItems.Add(SecretsVault.Subscriptions[k]);
|
||||
}
|
||||
HistorySet.Load();
|
||||
|
||||
if (content.Frame.Content != null)
|
||||
content.Refresh();
|
||||
else
|
||||
content.Frame.Navigate(typeof(Home));
|
||||
break;
|
||||
|
||||
case false:
|
||||
content.Frame.Navigate(typeof(Home));
|
||||
|
||||
for (int k = nav.MenuItems.Count - 1; k > 8; k--)
|
||||
nav.MenuItems.RemoveAt(k);
|
||||
|
||||
account.Visibility = Visibility.Visible;
|
||||
avatar.Visibility = Visibility.Collapsed;
|
||||
manager.Quit();
|
||||
|
||||
toChannel.Visibility = Visibility.Collapsed;
|
||||
toSubscriptions.Visibility = Visibility.Collapsed;
|
||||
@@ -296,8 +156,9 @@ namespace FoxTube
|
||||
|
||||
subsHeader.Visibility = Visibility.Collapsed;
|
||||
|
||||
content.Frame.BackStack.Clear();
|
||||
content.Frame.ForwardStack.Clear();
|
||||
for (int k = nav.MenuItems.Count - 1; k > 8; k--)
|
||||
nav.MenuItems.RemoveAt(k);
|
||||
HistorySet.Items.Clear();
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -305,14 +166,8 @@ namespace FoxTube
|
||||
|
||||
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("/Main/tryAgain"), (command) =>
|
||||
{
|
||||
SecretsVault.Authorize();
|
||||
}));
|
||||
dialog.Commands.Add(new UICommand(resources.GetString("/Main/quit"), (command) =>
|
||||
{
|
||||
Methods.CloseApp();
|
||||
}));
|
||||
dialog.Commands.Add(new UICommand(resources.GetString("/Main/tryAgain"), (command) => SecretsVault.Authorize()));
|
||||
dialog.Commands.Add(new UICommand(resources.GetString("/Main/quit"), (command) => CoreApplication.Exit()));
|
||||
|
||||
dialog.CancelCommandIndex = 1;
|
||||
dialog.DefaultCommandIndex = 0;
|
||||
@@ -321,114 +176,18 @@ namespace FoxTube
|
||||
break;
|
||||
}
|
||||
|
||||
if (videoPlaceholder.Frame.Content != null)
|
||||
{
|
||||
MaximizeVideo();
|
||||
videoPlaceholder.Refresh();
|
||||
content.AuthorizationChanged(isAuthozied);
|
||||
}
|
||||
|
||||
DownloadAgent.Initialize();
|
||||
}
|
||||
|
||||
private async void Feedback_Click(object sender, RoutedEventArgs e)
|
||||
public void UpdateView()
|
||||
{
|
||||
await StoreServicesFeedbackLauncher.GetDefault().LaunchAsync();
|
||||
}
|
||||
|
||||
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 });
|
||||
|
||||
if(content.Video.Content != null && !content.VideoMinimized)
|
||||
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
|
||||
(videoPlaceholder.Frame.Content as VideoPage).Player.Minimize();
|
||||
Title.Text = headers[content.Frame.Frame.SourcePageType];
|
||||
nav.IsBackEnabled = content.CanGoBack;
|
||||
|
||||
Title.Text = headers[content.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))
|
||||
if (new[] { typeof(Home), typeof(Settings), typeof(Subscriptions) }.Contains(content.Frame.Frame.SourcePageType))
|
||||
{
|
||||
nav.ExpandedModeThresholdWidth = 1008;
|
||||
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;
|
||||
videoPlaceholder.Height = double.NaN;
|
||||
videoPlaceholder.VerticalAlignment = VerticalAlignment.Stretch;
|
||||
videoPlaceholder.HorizontalAlignment = HorizontalAlignment.Stretch;
|
||||
videoPlaceholder.Margin = new Thickness(0);
|
||||
if (!SecretsVault.IsAuthorized)
|
||||
return null;
|
||||
|
||||
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;
|
||||
|
||||
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
|
||||
{
|
||||
XmlDocument doc = new XmlDocument();
|
||||
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++)
|
||||
suggestions.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;
|
||||
search.Items.Add(doc["toplevel"].ChildNodes[i]["suggestion"].GetAttribute("data"));
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
});
|
||||
|
||||
public void Content_Navigated(object sender, NavigationEventArgs e)
|
||||
{
|
||||
Title.Text = headers[content.Frame.SourcePageType];
|
||||
#region Simple UI interaction events
|
||||
async void Feedback_Click(object sender, RoutedEventArgs e) =>
|
||||
await StoreServicesFeedbackLauncher.GetDefault().LaunchAsync();
|
||||
|
||||
if (!wasInvoked)
|
||||
{
|
||||
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)
|
||||
{
|
||||
void RemoveAds_Tapped(object sender, TappedRoutedEventArgs e) =>
|
||||
SecretsVault.GetAdblock();
|
||||
}
|
||||
|
||||
private void Nav_SelectionChanged(Microsoft.UI.Xaml.Controls.NavigationView sender, Microsoft.UI.Xaml.Controls.NavigationViewSelectionChangedEventArgs 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)
|
||||
{
|
||||
void Nav_PaneClosing(Microsoft.UI.Xaml.Controls.NavigationView sender, Microsoft.UI.Xaml.Controls.NavigationViewPaneClosingEventArgs args) =>
|
||||
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;
|
||||
|
||||
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/>
|
||||
</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"/>
|
||||
<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="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.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
@@ -79,13 +79,6 @@
|
||||
|
||||
<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/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/share" Icon="Share" Label="Share" Name="share" Click="share_Click"/>
|
||||
</classes:AdaptiveCommandBar>
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
using FoxTube.Controls;
|
||||
using Google.Apis.YouTube.v3;
|
||||
using Google.Apis.YouTube.v3.Data;
|
||||
using FoxTube.Classes;
|
||||
using FoxTube.Controls;
|
||||
using Microsoft.AppCenter.Analytics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Windows.ApplicationModel.DataTransfer;
|
||||
using Windows.ApplicationModel.Resources;
|
||||
using Windows.Foundation;
|
||||
@@ -13,6 +11,8 @@ using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Media.Imaging;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
using YoutubeExplode.Models;
|
||||
using YoutubeExplode;
|
||||
|
||||
namespace FoxTube.Pages
|
||||
{
|
||||
@@ -22,196 +22,120 @@ namespace FoxTube.Pages
|
||||
public sealed partial class PlaylistPage : Page, INavigationPage
|
||||
{
|
||||
public object Parameter { get; set; } = null;
|
||||
public string playlistId;
|
||||
|
||||
string authorId;
|
||||
Playlist item;
|
||||
|
||||
PlaylistItemsResource.ListRequest request;
|
||||
string token;
|
||||
int page = 1;
|
||||
|
||||
public PlaylistPage()
|
||||
{
|
||||
public PlaylistPage() =>
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
base.OnNavigatedTo(e);
|
||||
Parameter = e.Parameter;
|
||||
|
||||
if (e.Parameter as string == "WL")
|
||||
LoadWL();
|
||||
else
|
||||
Initialize(e.Parameter as string);
|
||||
}
|
||||
|
||||
public async void Initialize(string id)
|
||||
async void Initialize(string id)
|
||||
{
|
||||
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.Hl = SettingsStorage.RelevanceLanguage;
|
||||
|
||||
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);
|
||||
authorId = (await infoRequest.ExecuteAsync()).Items[0].Snippet.ChannelId;
|
||||
|
||||
try
|
||||
{
|
||||
thumbnail.Source = new BitmapImage(item.Snippet.Thumbnails.Medium.Url.ToUri());
|
||||
avatar.ProfilePicture = new BitmapImage((await new YoutubeExplode.YoutubeClient().GetChannelAsync(item.Snippet.ChannelId)).LogoUrl.ToUri()) { DecodePixelWidth = 50, DecodePixelHeight = 50 };
|
||||
thumbnail.Source = new BitmapImage((item.Videos.Count > 0 ? item.Videos[0].Thumbnails.MediumResUrl : "/Assets/videoThumbSample.png").ToUri());
|
||||
avatar.ProfilePicture = new BitmapImage((await new YoutubeClient(SecretsVault.HttpClient).GetChannelAsync(authorId)).LogoUrl.ToUri()) { DecodePixelHeight = 50, DecodePixelWidth = 50 };
|
||||
}
|
||||
catch { }
|
||||
|
||||
request = SecretsVault.Service.PlaylistItems.List("contentDetails");
|
||||
request.PlaylistId = id;
|
||||
request.MaxResults = 25;
|
||||
for (int k = 0; k < 25 && k < item.Videos.Count; k++)
|
||||
list.Add(new VideoCard(item.Videos[k].Id, "WL"));
|
||||
|
||||
PlaylistItemListResponse response = await request.ExecuteAsync();
|
||||
token = response.NextPageToken;
|
||||
if (string.IsNullOrWhiteSpace(token))
|
||||
if (list.Count >= item.Videos.Count)
|
||||
more.Visibility = Visibility.Collapsed;
|
||||
|
||||
foreach (PlaylistItem i in response.Items)
|
||||
list.Add(new VideoCard(i.ContentDetails.VideoId, playlistId));
|
||||
|
||||
Methods.MainPage.PageContent.LoadingPage.Close();
|
||||
Navigation.Frame.Frame.LoadingPage.Close();
|
||||
}
|
||||
catch (System.Net.Http.HttpRequestException)
|
||||
{
|
||||
Methods.MainPage.PageContent.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();
|
||||
Navigation.Frame.Frame.LoadingPage.Error("System.Net.Http.HttpRequestException", "Unable to connect to Google servers.", true);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
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;
|
||||
}
|
||||
Methods.MainPage.PageContent.LoadingPage.Error(e.GetType().ToString(), e.Message);
|
||||
Analytics.TrackEvent("WL playlist loading error", new Dictionary<string, string>()
|
||||
Navigation.Frame.Frame.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", item.Id },
|
||||
{ "StackTrace", e.StackTrace }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void toChannel_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Methods.MainPage.GoToChannel(item.Snippet.ChannelId);
|
||||
}
|
||||
void toChannel_Click(object sender, RoutedEventArgs e) =>
|
||||
Navigation.GoToChannel(authorId);
|
||||
|
||||
private async void inBrowser_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
await Launcher.LaunchUriAsync(new Uri($"https://www.youtube.com/playlist?list={item.Id}"));
|
||||
}
|
||||
async void inBrowser_Click(object sender, RoutedEventArgs e) =>
|
||||
await Launcher.LaunchUriAsync(item.GetUrl().ToUri());
|
||||
|
||||
private void refresh_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Methods.MainPage.PageContent.Refresh();
|
||||
}
|
||||
void refresh_Click(object sender, RoutedEventArgs e) =>
|
||||
Navigation.Frame.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.ShowShareUI();
|
||||
}
|
||||
|
||||
private void Share(DataTransferManager sender, DataRequestedEventArgs args)
|
||||
void Share(DataTransferManager sender, DataRequestedEventArgs args)
|
||||
{
|
||||
Methods.Share(args,
|
||||
item.Snippet.Thumbnails.Medium.Url,
|
||||
item.Snippet.Title,
|
||||
$"https://www.youtube.com/playlist?list={item.Id}",
|
||||
(thumbnail.Source as BitmapImage).UriSource.AbsoluteUri,
|
||||
item.Title,
|
||||
item.GetUrl(),
|
||||
ResourceLoader.GetForCurrentView("Cards").GetString("/Cards/playlistShare"));
|
||||
}
|
||||
|
||||
private async void ShowMore_Clicked()
|
||||
void ShowMore_Clicked()
|
||||
{
|
||||
if(playlistId == "WL")
|
||||
{
|
||||
MoreWL();
|
||||
return;
|
||||
}
|
||||
for (int k = 25 * page++; k < 25 * page && k < item.Videos.Count; k++)
|
||||
list.Add(new VideoCard(item.Videos[k].Id, "WL"));
|
||||
|
||||
request.PageToken = token;
|
||||
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)
|
||||
if (list.Count >= item.Videos.Count)
|
||||
more.Visibility = Visibility.Collapsed;
|
||||
else
|
||||
more.Complete();
|
||||
}
|
||||
|
||||
public void DeleteItem(FrameworkElement card)
|
||||
{
|
||||
public void DeleteItem(FrameworkElement card) =>
|
||||
list.DeleteItem(card);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
x:Class="FoxTube.Search"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:FoxTube"
|
||||
xmlns:pages="using:FoxTube.Pages"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
|
||||
@@ -10,6 +10,7 @@ using Windows.System;
|
||||
using Windows.ApplicationModel.Resources;
|
||||
using Microsoft.AppCenter.Analytics;
|
||||
using System.Collections.Generic;
|
||||
using FoxTube.Classes;
|
||||
|
||||
namespace FoxTube
|
||||
{
|
||||
@@ -26,41 +27,9 @@ namespace FoxTube
|
||||
SearchResource.ListRequest request;
|
||||
string nextToken;
|
||||
|
||||
public Search()
|
||||
{
|
||||
public Search() =>
|
||||
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)
|
||||
{
|
||||
@@ -128,7 +97,7 @@ namespace FoxTube
|
||||
features.SelectedItems.Add(features.Items[4]);
|
||||
|
||||
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))
|
||||
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)
|
||||
{
|
||||
@@ -172,28 +172,25 @@ namespace FoxTube
|
||||
}
|
||||
}
|
||||
|
||||
private void AppBarButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
void AppBarButton_Click(object sender, RoutedEventArgs e) =>
|
||||
frame.Refresh();
|
||||
}
|
||||
|
||||
private async void More_Clicked()
|
||||
async void More_Clicked()
|
||||
{
|
||||
request.PageToken = nextToken;
|
||||
SearchListResponse response = await request.ExecuteAsync();
|
||||
nextToken = response.NextPageToken;
|
||||
|
||||
foreach (SearchResult item in response.Items)
|
||||
AddItem(item);
|
||||
|
||||
if (response.NextPageToken != null)
|
||||
{
|
||||
nextToken = response.NextPageToken;
|
||||
if (!string.IsNullOrWhiteSpace(nextToken))
|
||||
more.Complete();
|
||||
}
|
||||
else
|
||||
more.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
|
||||
private void Type_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
void Type_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -213,12 +210,7 @@ namespace FoxTube
|
||||
catch (NullReferenceException) { }
|
||||
}
|
||||
|
||||
private async void InBrowser_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)
|
||||
void Apply_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Parameters.Filter.HD = features.SelectedItems.Contains(features.Items[0]);
|
||||
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.Duration = (SearchParameters.Filters.Enumerations.Duration)duration.SelectedIndex;
|
||||
|
||||
frame.LoadingPage.Refresh();
|
||||
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
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">
|
||||
<PivotItem Name="generalTab" Header="General" x:Uid="/Settings/general">
|
||||
<ScrollViewer>
|
||||
@@ -30,5 +30,4 @@
|
||||
</ScrollViewer>
|
||||
</PivotItem>
|
||||
</Pivot>
|
||||
</Grid>
|
||||
</Page>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
using FoxTube.Pages.SettingsPages;
|
||||
using FoxTube.Classes;
|
||||
|
||||
namespace FoxTube
|
||||
{
|
||||
@@ -13,10 +14,8 @@ namespace FoxTube
|
||||
|
||||
bool inboxLoaded = false;
|
||||
string inboxId = null;
|
||||
public Settings()
|
||||
{
|
||||
public Settings() =>
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
@@ -38,10 +37,10 @@ namespace FoxTube
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -24,9 +24,7 @@ namespace FoxTube.Pages.SettingsPages
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ namespace FoxTube.Pages.SettingsPages
|
||||
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)
|
||||
return;
|
||||
@@ -88,47 +88,31 @@ namespace FoxTube.Pages.SettingsPages
|
||||
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;
|
||||
}
|
||||
|
||||
private void mobileWarning_Toggled(object sender, RoutedEventArgs e)
|
||||
{
|
||||
void mobileWarning_Toggled(object sender, RoutedEventArgs e) =>
|
||||
SettingsStorage.CheckConnection = mobileWarning.IsOn;
|
||||
}
|
||||
|
||||
private void autoplay_Toggled(object sender, RoutedEventArgs e)
|
||||
{
|
||||
void autoplay_Toggled(object sender, RoutedEventArgs e) =>
|
||||
SettingsStorage.Autoplay = autoplay.IsOn;
|
||||
}
|
||||
|
||||
private void notification_IsEnabledChanged(object sender, RoutedEventArgs e)
|
||||
{
|
||||
void notification_IsEnabledChanged(object sender, RoutedEventArgs e) =>
|
||||
SettingsStorage.VideoNotifications = newVideo.IsOn;
|
||||
}
|
||||
|
||||
private void devNews_Toggled(object sender, RoutedEventArgs e)
|
||||
{
|
||||
void devNews_Toggled(object sender, RoutedEventArgs e) =>
|
||||
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();
|
||||
}
|
||||
|
||||
private void region_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
void region_SelectionChanged(object sender, SelectionChangedEventArgs e) =>
|
||||
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;
|
||||
}
|
||||
|
||||
private void RadioButton_Checked(object sender, RoutedEventArgs e)
|
||||
void RadioButton_Checked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender == light)
|
||||
{
|
||||
@@ -151,19 +135,13 @@ namespace FoxTube.Pages.SettingsPages
|
||||
Methods.MainPage.SetTitleBar();
|
||||
}
|
||||
|
||||
private void Button_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
void Button_Click(object sender, RoutedEventArgs e) =>
|
||||
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;
|
||||
}
|
||||
|
||||
private void ClipboardProcessing_Toggled(object sender, RoutedEventArgs e)
|
||||
{
|
||||
void ClipboardProcessing_Toggled(object sender, RoutedEventArgs e) =>
|
||||
SettingsStorage.ProcessClipboard = clipboardProcessing.IsOn;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ namespace FoxTube.Pages.SettingsPages
|
||||
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)
|
||||
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))
|
||||
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();
|
||||
}
|
||||
|
||||
private void VisualStateGroup_CurrentStateChanged(object sender, VisualStateChangedEventArgs e)
|
||||
void VisualStateGroup_CurrentStateChanged(object sender, VisualStateChangedEventArgs e)
|
||||
{
|
||||
if (e.NewState == null)
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ namespace FoxTube.Pages.SettingsPages
|
||||
{
|
||||
public sealed partial class Translate : Page
|
||||
{
|
||||
//TODO: Localize page
|
||||
ResourceLoader resources = ResourceLoader.GetForCurrentView("Translate");
|
||||
StorageFile submission;
|
||||
public Translate()
|
||||
@@ -31,7 +30,7 @@ namespace FoxTube.Pages.SettingsPages
|
||||
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();
|
||||
picker.CommitButtonText = resources.GetString("/Translate/exportPicker");
|
||||
@@ -49,7 +48,7 @@ namespace FoxTube.Pages.SettingsPages
|
||||
await Launcher.LaunchFileAsync(file);
|
||||
}
|
||||
|
||||
private void LangList_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
void LangList_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
greenResult.Visibility = Visibility.Collapsed;
|
||||
certification.Visibility = Visibility.Collapsed;
|
||||
@@ -59,7 +58,7 @@ namespace FoxTube.Pages.SettingsPages
|
||||
export.IsEnabled = true;
|
||||
}
|
||||
|
||||
private async void upload_Click(object sender, RoutedEventArgs e)
|
||||
async void upload_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
FileOpenPicker picker = new FileOpenPicker()
|
||||
{
|
||||
@@ -156,12 +155,10 @@ namespace FoxTube.Pages.SettingsPages
|
||||
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);
|
||||
}
|
||||
|
||||
private async void Submit_Click(object sender, RoutedEventArgs e)
|
||||
async void Submit_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
uploadingProgress.Visibility = Visibility.Visible;
|
||||
submit.IsEnabled = false;
|
||||
|
||||
@@ -8,12 +8,10 @@
|
||||
mc:Ignorable="d"
|
||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
|
||||
<ScrollViewer>
|
||||
<controls:AdaptiveGridView ItemsSource="{x:Bind list}" DesiredWidth="250">
|
||||
<controls:AdaptiveGridView ItemsSource="{x:Bind list}" DesiredWidth="250" ItemClick="AdaptiveGridView_ItemClick">
|
||||
<controls:AdaptiveGridView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Button HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" Padding="5" Tag="{Binding Path=Snippet.ResourceId.ChannelId}" Click="Button_Click">
|
||||
<Grid>
|
||||
<Grid HorizontalAlignment="Stretch" Padding="5" Background="{StaticResource ButtonBackgroundThemeBrush}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="55"/>
|
||||
<ColumnDefinition/>
|
||||
@@ -25,9 +23,7 @@
|
||||
</PersonPicture>
|
||||
<TextBlock Grid.Column="1" TextWrapping="Wrap" VerticalAlignment="Center" TextTrimming="CharacterEllipsis" Text="{Binding Path=Snippet.Title}"/>
|
||||
</Grid>
|
||||
</Button>
|
||||
</DataTemplate>
|
||||
</controls:AdaptiveGridView.ItemTemplate>
|
||||
</controls:AdaptiveGridView>
|
||||
</ScrollViewer>
|
||||
</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 Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
namespace FoxTube.Pages
|
||||
@@ -16,12 +16,10 @@ namespace FoxTube.Pages
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
Methods.MainPage.PageContent.LoadingPage.Close();
|
||||
Navigation.Frame.Frame.LoadingPage.Close();
|
||||
}
|
||||
|
||||
private void Button_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Methods.MainPage.GoToChannel(((Button)sender).Tag.ToString());
|
||||
}
|
||||
void AdaptiveGridView_ItemClick(object sender, ItemClickEventArgs e) =>
|
||||
Navigation.GoToChannel(((Subscription)e.ClickedItem).Snippet.ResourceId.ChannelId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
mc:Ignorable="d">
|
||||
|
||||
<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>
|
||||
<TransitionCollection>
|
||||
<EntranceThemeTransition IsStaggeringEnabled="True"/>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using FoxTube.Controls;
|
||||
using FoxTube.Classes;
|
||||
using FoxTube.Controls.Adverts;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
@@ -12,17 +14,27 @@ namespace FoxTube.Pages
|
||||
{
|
||||
public int Count => list.Items.Count;
|
||||
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();
|
||||
|
||||
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);
|
||||
if ((list.Items.Count - 5) % 25 == 0)
|
||||
list.Items.Add(item);
|
||||
if ((ItemsCount - 5) % 25 == 0)
|
||||
list.Items.Add(new CardAdvert());
|
||||
empty.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
@@ -33,9 +45,20 @@ namespace FoxTube.Pages
|
||||
empty.Visibility = Visibility.Visible;
|
||||
}
|
||||
|
||||
public void DeleteItem(FrameworkElement item)
|
||||
{
|
||||
public void DeleteItem(FrameworkElement 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"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:FoxTube"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:pages="using:FoxTube.Pages"
|
||||
xmlns:classes="using:FoxTube.Classes"
|
||||
xmlns:videopage="using:FoxTube.Controls.VideoPage"
|
||||
xmlns:controls="using:FoxTube.Controls"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid Name="grid" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" SizeChanged="grid_SizeChanged">
|
||||
@@ -25,6 +25,7 @@
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="400"/>
|
||||
@@ -34,7 +35,7 @@
|
||||
<RowDefinition/>
|
||||
<RowDefinition Height="auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<ScrollViewer Name="mainScroll" VerticalScrollBarVisibility="Hidden">
|
||||
<ScrollViewer Name="mainScroll" VerticalScrollBarVisibility="Hidden" ViewChanged="MainScroll_ViewChanged">
|
||||
<StackPanel Name="mainContent">
|
||||
<Border BorderBrush="Red" BorderThickness="5" CornerRadius="10" Margin="10" Name="upcoming" Visibility="Collapsed">
|
||||
<Grid Margin="10">
|
||||
@@ -61,10 +62,8 @@
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
<local:VideoPlayer x:Name="player" NextClicked="Player_NextClicked" MiniMode="Player_Minimize"/>
|
||||
<PivotItem Header="Description" Name="descriptionPanel">
|
||||
<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 Text="Published at: " Name="meta"/>
|
||||
<Grid>
|
||||
@@ -72,13 +71,13 @@
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</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">
|
||||
<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="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>
|
||||
</Button>
|
||||
@@ -89,7 +88,7 @@
|
||||
<TextBlock Foreground="Gray" Text="[dislikes]" Name="dislikes"/>
|
||||
<TextBlock HorizontalAlignment="Right" Foreground="Gray" Text="[likes]" Name="likes"/>
|
||||
</Grid>
|
||||
<Grid BorderBrush="{StaticResource SystemControlBackgroundListMediumRevealBorderBrush}">
|
||||
<Grid>
|
||||
<FontIcon Foreground="Gray"
|
||||
HorizontalAlignment="Left"
|
||||
FontSize="40"
|
||||
@@ -113,16 +112,12 @@
|
||||
<classes:AdaptiveCommandBar Grid.Row="1" VerticalAlignment="Bottom" x:Name="commandbar">
|
||||
<AppBarButton x:Uid="/VideoPage/download" Icon="Download" Label="Download video" Name="download">
|
||||
<AppBarButton.Flyout>
|
||||
<MenuFlyout x:Name="downloadSelector"/>
|
||||
<Flyout x:Name="downloadSelector"/>
|
||||
</AppBarButton.Flyout>
|
||||
</AppBarButton>
|
||||
<AppBarButton x:Uid="/VideoPage/addTo" Name="addTo" Label="Add to" Icon="Add" Visibility="Visible">
|
||||
<AppBarButton.Flyout>
|
||||
<MenuFlyout x:Name="addList">
|
||||
<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>
|
||||
<Flyout x:Name="addToSelector"/>
|
||||
</AppBarButton.Flyout>
|
||||
</AppBarButton>
|
||||
<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">
|
||||
<Pivot Name="pivot" SelectedIndex="0" IsHeaderItemsCarouselEnabled="False">
|
||||
<PivotItem x:Uid="/VideoPage/related" Header="Suggestions">
|
||||
<ScrollViewer>
|
||||
<pages:VideoGrid x:Name="relatedVideos"/>
|
||||
</ScrollViewer>
|
||||
<videopage:RelatedVideos x:Name="suggestions"/>
|
||||
</PivotItem>
|
||||
<PivotItem x:Uid="/VideoPage/comments" Header="Comments" Name="commentsPlaceholder">
|
||||
<pages:CommentsPage x:Name="comments"/>
|
||||
<PivotItem x:Uid="/VideoPage/comments" Header="Comments" Name="commentsTab">
|
||||
<videopage:Comments x:Name="comments"/>
|
||||
</PivotItem>
|
||||
<PivotItem x:Uid="/VideoPage/playlist" Header="Playlist" Name="playlist">
|
||||
<ScrollViewer Name="playlistScroll">
|
||||
<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 x:Uid="/VideoPage/playlist" Header="Playlist" Name="playlistTab">
|
||||
<videopage:VideoPlaylist x:Name="playlist" ItemChanged="Playlist_ItemChanged"/>
|
||||
</PivotItem>
|
||||
</Pivot>
|
||||
</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>
|
||||
</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.Data;
|
||||
using Microsoft.AppCenter.Analytics;
|
||||
@@ -25,21 +27,6 @@ namespace FoxTube.Pages
|
||||
{
|
||||
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>
|
||||
/// Video page
|
||||
/// </summary>
|
||||
@@ -49,27 +36,25 @@ namespace FoxTube.Pages
|
||||
|
||||
public object Parameter { get; set; } = null;
|
||||
|
||||
public string playlistId = null;
|
||||
public Video item;
|
||||
public HistoryItem history;
|
||||
public bool incognito = false;
|
||||
|
||||
bool isExtended = false;
|
||||
string playlistItem = null;
|
||||
Video item;
|
||||
Channel channelItem;
|
||||
bool incognito = false;
|
||||
|
||||
Rating userRating = Rating.None;
|
||||
|
||||
DispatcherTimer liveTimer;
|
||||
DispatcherTimer countdownTimer;
|
||||
|
||||
public VideoPlayer Player => player;
|
||||
|
||||
public VideoPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
if (Window.Current.Bounds.Width <= 1000)
|
||||
{
|
||||
Debug.WriteLine("Correcting layout...");
|
||||
//Methods.Player.SizeChanged += Player_SizeChanged;
|
||||
|
||||
if (Window.Current.Bounds.Width > 1000)
|
||||
return;
|
||||
|
||||
mainContent.Children.Remove(descriptionPanel);
|
||||
pivot.Items.Insert(0, descriptionPanel);
|
||||
|
||||
@@ -78,65 +63,87 @@ namespace FoxTube.Pages
|
||||
|
||||
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)
|
||||
{
|
||||
base.OnNavigatedTo(e);
|
||||
Parameter = e.Parameter;
|
||||
|
||||
Initialize(e.Parameter as object[]);
|
||||
Initialize(((object, Channel, bool, string))e.Parameter);
|
||||
}
|
||||
|
||||
protected override void OnNavigatedFrom(NavigationEventArgs e)
|
||||
{
|
||||
base.OnNavigatedFrom(e);
|
||||
Player.Player.Stop();
|
||||
}
|
||||
|
||||
public async void Initialize(object[] ids)
|
||||
async void Initialize((object video, Channel channel, bool incognito, string playlist) parameter, bool playlistItemSwitch = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
incognito = (bool)ids[2];
|
||||
incognito = parameter.incognito;
|
||||
channelItem = parameter.channel;
|
||||
|
||||
if (ids[1] != null)
|
||||
LoadPlaylist(ids[1] as string);
|
||||
if (parameter.video is Video)
|
||||
item = parameter.video as Video;
|
||||
else
|
||||
pivot.Items.Remove(playlist);
|
||||
|
||||
{
|
||||
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;
|
||||
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")
|
||||
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
|
||||
LoadStream();
|
||||
|
||||
if (item.Snippet.LiveBroadcastContent == "upcoming")
|
||||
SetSchedule();
|
||||
|
||||
LoadInfo();
|
||||
LoadAddTo();
|
||||
suggestions.Initialize(item.Id);
|
||||
|
||||
Methods.MainPage.VideoContent.LoadingPage.Close();
|
||||
//Methods.MainPage.VideoContent.LoadingPage.Close();
|
||||
}
|
||||
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)
|
||||
{
|
||||
/*Methods.Player.Player.Visibility = Visibility.Collapsed;
|
||||
if (item == null)
|
||||
{
|
||||
Methods.MainPage.PageContent.LoadingPage.Error("VideoNotFound", "Such video doesn't exist");
|
||||
@@ -150,7 +157,7 @@ namespace FoxTube.Pages
|
||||
{ "Message", e.Message },
|
||||
{ "Video ID", item.Id },
|
||||
{ "StackTrace", e.StackTrace }
|
||||
});
|
||||
});*/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,95 +190,35 @@ namespace FoxTube.Pages
|
||||
}
|
||||
}
|
||||
|
||||
async void LoadPlaylist(string id)
|
||||
{
|
||||
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()
|
||||
async void LoadDescription()
|
||||
{
|
||||
//Setting meta
|
||||
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.Inlines.Add(new Run
|
||||
{
|
||||
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");
|
||||
request.Id = item.Snippet.CategoryId;
|
||||
request.Hl = SettingsStorage.RelevanceLanguage;
|
||||
VideoCategoryListResponse response = await request.ExecuteAsync();
|
||||
if(response.Items.Count != 0)
|
||||
{
|
||||
|
||||
meta.Inlines.Add(new Run
|
||||
{
|
||||
Text = $" {resources.GetString("/VideoPage/inCat")} "
|
||||
@@ -281,26 +228,9 @@ namespace FoxTube.Pages
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
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
|
||||
if (SecretsVault.IsAuthorized)
|
||||
@@ -323,8 +253,11 @@ namespace FoxTube.Pages
|
||||
subscribe.Foreground = new SolidColorBrush(Colors.Gray);
|
||||
subscribe.Content = resources.GetString("/Cards/unsubscribe");
|
||||
}
|
||||
if (item.Snippet.ChannelId == SecretsVault.AccountId)
|
||||
else if (item.Snippet.ChannelId == SecretsVault.AccountId)
|
||||
subscribe.Visibility = Visibility.Collapsed;
|
||||
|
||||
/*try { addToSelector.Initialize(item); }
|
||||
catch { addTo.Visibility = Visibility.Collapsed; }*/
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -332,34 +265,22 @@ namespace FoxTube.Pages
|
||||
addTo.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()
|
||||
{
|
||||
liveTimer = new DispatcherTimer() { Interval = TimeSpan.FromSeconds(10) };
|
||||
liveTimer = new DispatcherTimer() { Interval = TimeSpan.FromMinutes(1) };
|
||||
liveTimer.Tick += LiveStatsUpdate;
|
||||
liveTimer.Start();
|
||||
LiveStatsUpdate();
|
||||
views.Text = $"{item.LiveStreamingDetails.ConcurrentViewers} {resources.GetString("/Cards/viewers")}";
|
||||
|
||||
if(string.IsNullOrWhiteSpace(item.LiveStreamingDetails.ActiveLiveChatId))
|
||||
pivot.Items.Remove(commentsPlaceholder);
|
||||
if (string.IsNullOrWhiteSpace(item.LiveStreamingDetails.ActiveLiveChatId))
|
||||
comments.Initialize(item);
|
||||
else
|
||||
{
|
||||
commentsPlaceholder.Header = resources.GetString("/VideoPage/chat");
|
||||
commentsPlaceholder.Content = new Chat(item.LiveStreamingDetails.ActiveLiveChatId);
|
||||
pivot.SelectedItem = commentsPlaceholder;
|
||||
commentsTab.Header = resources.GetString("/VideoPage/chat");
|
||||
commentsTab.Content = new Chat(item.LiveStreamingDetails.ActiveLiveChatId);
|
||||
pivot.SelectedItem = commentsTab;
|
||||
}
|
||||
download.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
@@ -372,117 +293,14 @@ namespace FoxTube.Pages
|
||||
views.Text = $"{(await request.ExecuteAsync()).Items[0].LiveStreamingDetails.ConcurrentViewers} {resources.GetString("/Cards/viewers")}";
|
||||
}
|
||||
|
||||
void LoadStats()
|
||||
{
|
||||
views.Text = $"{item.Statistics.ViewCount:0,0} {resources.GetString("/Cards/views")}";
|
||||
private void gotoChannel_Click(object sender, RoutedEventArgs e) =>
|
||||
Navigation.GoToChannel(channelItem.Id);
|
||||
|
||||
comments.Initialize(item);
|
||||
LoadDownloads();
|
||||
}
|
||||
private void openBrowser_Click(object sender, RoutedEventArgs e) => Methods.GuardFromNull("");
|
||||
//Methods.Player.OpenBrowser();
|
||||
|
||||
async void LoadDownloads()
|
||||
{
|
||||
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);
|
||||
}
|
||||
void refresh_Click(object sender, RoutedEventArgs e) => Methods.GuardFromNull("");
|
||||
//Methods.MainPage.VideoContent.Refresh();
|
||||
|
||||
private void grid_SizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
@@ -516,7 +334,7 @@ namespace FoxTube.Pages
|
||||
|
||||
private void Share(DataTransferManager sender, DataRequestedEventArgs args)
|
||||
{
|
||||
player.Pause();
|
||||
//Methods.Player.Pause();
|
||||
|
||||
Methods.Share(args,
|
||||
item.Snippet.Thumbnails.Medium.Url,
|
||||
@@ -531,6 +349,9 @@ namespace FoxTube.Pages
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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))
|
||||
(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)
|
||||
private void ResetControl()
|
||||
{
|
||||
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;
|
||||
addList.Items.Add(menuItem);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
addTo.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
mainScroll.ChangeView(0, 0, null);
|
||||
upcoming.Visibility = Visibility.Collapsed;
|
||||
schedule.Visibility = Visibility.Collapsed;
|
||||
start.Visibility = Visibility.Collapsed;
|
||||
end.Visibility = Visibility.Collapsed;
|
||||
|
||||
countdownPanel.Visibility = Visibility.Collapsed;
|
||||
|
||||
download.Visibility = Visibility.Visible;
|
||||
addTo.Visibility = Visibility.Visible;
|
||||
|
||||
comments = new Comments();
|
||||
}
|
||||
|
||||
private async void Item_Click(object sender, RoutedEventArgs e)
|
||||
private void Playlist_ItemChanged(string id)
|
||||
{
|
||||
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 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();
|
||||
|
||||
ResetControl();
|
||||
Initialize((id, null, incognito, playlistItem), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,7 +169,7 @@
|
||||
<value>Skip forward for 30 seconds</value>
|
||||
</data>
|
||||
<data name="generatedCaption" xml:space="preserve">
|
||||
<value>(Auto-generated)</value>
|
||||
<value>Auto-generated</value>
|
||||
</data>
|
||||
<data name="goLive.Text" xml:space="preserve">
|
||||
<value>Go to live broadcast</value>
|
||||
|
||||
@@ -169,7 +169,7 @@
|
||||
<value>Вперед на 30 секунд</value>
|
||||
</data>
|
||||
<data name="generatedCaption" xml:space="preserve">
|
||||
<value>(Авто-перевод)</value>
|
||||
<value>Авто-перевод</value>
|
||||
</data>
|
||||
<data name="goLive.Text" xml:space="preserve">
|
||||
<value>Перейти к прямому эфиру</value>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
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:adverts="using:FoxTube.Controls.Adverts">
|
||||
|
||||
@@ -294,6 +294,7 @@
|
||||
<KeyboardAccelerator Key="Space"/>
|
||||
</Button.KeyboardAccelerators>
|
||||
</Button>
|
||||
<Button x:Name="PreviousButton" Content="" Visibility="Collapsed"/>
|
||||
<Button x:Name="NextButton" Content=""/>
|
||||
<Button x:Name="VolumeMenuButton" Content="">
|
||||
<Button.Flyout>
|
||||
|
||||
Reference in New Issue
Block a user