diff --git a/FoxTube.Background/BackgroundProcessor.cs b/FoxTube.Background/BackgroundProcessor.cs index fa39192..97ca597 100644 --- a/FoxTube.Background/BackgroundProcessor.cs +++ b/FoxTube.Background/BackgroundProcessor.cs @@ -1,13 +1,10 @@ -using Google.Apis.Auth.OAuth2; -using Google.Apis.Services; +using Google.Apis.Services; using Google.Apis.YouTube.v3; using Google.Apis.YouTube.v3.Data; +using Newtonsoft.Json; using System; using System.Collections.Generic; -using System.IO; using System.Linq; -using System.Text; -using System.Threading; using System.Threading.Tasks; using System.Xml; using Windows.ApplicationModel.Background; @@ -16,141 +13,98 @@ using Windows.UI.Notifications; namespace FoxTube.Background { - public delegate void NotificationHandler(object sender, Notification item); - public sealed class BackgroundProcessor : IBackgroundTask { - public static event NotificationHandler NotificationRecieved; - - List Notifications = new List(); private DateTime lastCheck = DateTime.Now; - private ApplicationDataContainer settings = ApplicationData.Current.LocalSettings; - - private ClientSecrets Secrets => new ClientSecrets() - { - ClientId = "349735264870-2ekqlm0a4mkg3mmrfcv90s3qp3o15dq0.apps.googleusercontent.com", - ClientSecret = "BkVZOAaCU2Zclf0Zlicg6y2_" - }; private YouTubeService Service => new YouTubeService(new BaseClientService.Initializer() { ApiKey = "AIzaSyBgHrCnrlzlVmk0cJKL8RqP9Y8x6XSuk_0", ApplicationName = "FoxTube" }); - - XmlDocument doc = new XmlDocument(); BackgroundTaskDeferral def; - public void Run(IBackgroundTaskInstance taskInstance) + public async void Run(IBackgroundTaskInstance taskInstance) { - def = taskInstance.GetDeferral(); - if (settings.Values["lastCheck"] == null) - settings.Values.Add("lastCheck", XmlConvert.ToString(DateTime.Now, "YYYY-MM-DDThh:mm:ss")); - else lastCheck = XmlConvert.ToDateTime(settings.Values["lastCheck"] as string, XmlDateTimeSerializationMode.Unspecified); - try { - doc.LoadXml(settings.Values["notificationsHistory"] as string); + def = taskInstance.GetDeferral(); + + if (settings.Values["lastCheck"] == null) + { + settings.Values.Add("lastCheck", DateTime.Now.ToString()); + def.Complete(); + return; + } + else + lastCheck = DateTime.Parse(settings.Values["lastCheck"] as string); + + bool[] notificationsSettings = JsonConvert.DeserializeObject(await FileIO.ReadTextAsync(await ApplicationData.Current.RoamingFolder.GetFileAsync("notifications.json"))); + if (notificationsSettings[0]) + CheckAnnouncements(); + if (notificationsSettings[1]) + await CheckAccount(); } - catch + catch { } + finally { - return; + settings.Values["lastCheck"] = DateTime.Now.ToString(); + def.Complete(); } - - CheckAnnouncements(); - CheckAccount(); - - SendNSave(); - - def.Complete(); } - async void CheckAccount() + async Task CheckAccount() { - UserCredential credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(Secrets, new[] { Google.Apis.Oauth2.v2.Oauth2Service.Scope.UserinfoProfile, YouTubeService.Scope.YoutubeForceSsl }, "user", CancellationToken.None); - if (credential == null) - return; - - SubscriptionsResource.ListRequest subRequest = new YouTubeService(new BaseClientService.Initializer() + try { - HttpClientInitializer = credential, - ApplicationName = "FoxTube" - }).Subscriptions.List("snippet"); - subRequest.Mine = true; - subRequest.MaxResults = 50; - SubscriptionListResponse subResponse = await subRequest.ExecuteAsync(); - Dictionary subs = new Dictionary(); + Dictionary subscriptions = JsonConvert.DeserializeObject>(await FileIO.ReadTextAsync(await ApplicationData.Current.RoamingFolder.GetFileAsync("background.json"))); - foreach (Subscription s in subResponse.Items) - subs.Add(s.Snippet.ResourceId.ChannelId, s.Snippet.Thumbnails.Standard.Url); + List results = new List(); - string nextToken = subResponse.NextPageToken; - while (nextToken != null) - { - subRequest.PageToken = nextToken; - subResponse = await subRequest.ExecuteAsync(); - nextToken = subResponse.NextPageToken; + foreach (var s in subscriptions) + { + SearchResource.ListRequest request = Service.Search.List("snippet"); + request.PublishedAfter = lastCheck; + request.ChannelId = s.Key; + request.Type = "video"; + request.MaxResults = 5; + SearchListResponse response = await request.ExecuteAsync(); - foreach (Subscription s in subResponse.Items) - subs.Add(s.Snippet.ResourceId.ChannelId, s.Snippet.Thumbnails.Standard.Url); - } - - foreach(var s in subs) - { - SearchResource.ListRequest request = Service.Search.List("snippet"); - request.PublishedAfter = lastCheck; - request.ChannelId = s.Key; - request.Type = "video"; - SearchListResponse response = await request.ExecuteAsync(); - - foreach (var i in response.Items) - Notifications.Add(new Notification("video", i.Id.VideoId, - i.Snippet.ChannelTitle, - i.Snippet.Title, - i.Snippet.PublishedAt.Value, - i.Snippet.Thumbnails.Standard.Url, - s.Value)); + foreach (SearchResult i in response.Items) + { + results.Add(i); + + ToastNotificationManager.CreateToastNotifier().Show( + Notification.GetVideoToast(i.Id.VideoId, i.Snippet.ChannelId, i.Snippet.Title, i.Snippet.ChannelTitle, i.Snippet.Thumbnails.Medium.Url, s.Value)); + } + } + + results.OrderBy(i => i.Snippet.PublishedAt); + + TileUpdater updater = TileUpdateManager.CreateTileUpdaterForApplication(); + updater.EnableNotificationQueue(true); + updater.Clear(); + for (int i = 0; i < 5; i++) + updater.Update(Tiles.GetTileLayout(results[i].Snippet.Title, results[i].Snippet.ChannelTitle, results[i].Snippet.Thumbnails.Medium.Url, subscriptions[results[i].Snippet.ChannelId])); } + catch { } } void CheckAnnouncements() { - XmlDocument doc = new XmlDocument(); - doc.Load(XmlReader.Create("http://foxgame.hol.es/foxtube-messages.xml")); - if ((XmlConvert.ToDateTimeOffset((doc["posts"].FirstChild as XmlElement).GetAttribute("time"), "YYYY-MM-DDThh:mm:ss") - lastCheck.ToUniversalTime()).TotalSeconds > 0) - Notifications.Add(new Notification("internal", (doc["posts"].FirstChild as XmlElement).GetAttribute("id"), - doc["posts"].FirstChild["header"].InnerText, - doc["posts"].FirstChild["notificationHeader"].InnerText, - XmlConvert.ToDateTimeOffset((doc["posts"].FirstChild as XmlElement).GetAttribute("time"), "YYYY-MM-DDThh:mm:ss"), - (doc["posts"].FirstChild as XmlElement).GetAttribute("image"), (doc["posts"].FirstChild as XmlElement).GetAttribute("avatar"))); - } - - void SendNotification(Notification notification) - { - ToastNotificationManager.CreateToastNotifier().Show(notification.GetToast()); - } - - void SendNSave() - { - foreach (Notification n in Notifications) + try { - NotificationRecieved.Invoke(this, n); - doc["history"].InnerXml += n.GetXml(); + XmlDocument doc = new XmlDocument(); + doc.Load(XmlReader.Create("http://foxgame-studio.000webhostapp.com/foxtube-messages.xml")); + if ((DateTime.Parse((doc["posts"].FirstChild as XmlElement).GetAttribute("time")) - lastCheck).TotalSeconds > 0) + ToastNotificationManager.CreateToastNotifier().Show( + Notification.GetInternalToast(doc["posts"].FirstChild["id"].InnerText, + doc["posts"].FirstChild["header"].InnerText, + doc["posts"].FirstChild["content"].InnerText, + doc["posts"].FirstChild["thumbnail"].InnerText, + doc["posts"].FirstChild["avatar"].InnerText)); } - settings.Values.Add("notificationsHistory", doc.InnerXml); - - foreach (Notification n in Notifications) - switch (n.Type) - { - case NotificationType.Video: - if ((bool)settings.Values["newVideoNotification"]) - SendNotification(n); - break; - - case NotificationType.Internal: - SendNotification(n); - break; - } + catch { } } } } diff --git a/FoxTube.Background/FoxTube.Background.csproj b/FoxTube.Background/FoxTube.Background.csproj index d6f90da..41111b2 100644 --- a/FoxTube.Background/FoxTube.Background.csproj +++ b/FoxTube.Background/FoxTube.Background.csproj @@ -11,8 +11,8 @@ FoxTube.Background en-US UAP - 10.0.17134.0 - 10.0.15063.0 + 10.0.17763.0 + 10.0.16299.0 14 512 {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} @@ -108,7 +108,7 @@ - + diff --git a/FoxTube.Background/Notification.cs b/FoxTube.Background/Notification.cs deleted file mode 100644 index a872194..0000000 --- a/FoxTube.Background/Notification.cs +++ /dev/null @@ -1,235 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Windows.Data.Xml.Dom; -using Windows.UI; -using Windows.UI.Notifications; -using Windows.UI.Xaml; -using Windows.UI.Xaml.Controls; -using Windows.UI.Xaml.Media; -using Windows.UI.Xaml.Media.Imaging; - -namespace FoxTube.Background -{ - public enum NotificationType - { - Video, Comment, Post, Internal, Changelog - } - - public sealed class Notification - { - public string Channel { get; set; } - public string Content { get; set; } - public DateTimeOffset TimeStamp { get; set; } - public NotificationType Type { get; set; } - public string Avatar { get; set; } - public string Thumbnail { get; set; } - public string Id { get; set; } - - public Notification(string type, string id, - string channelName, string content, DateTimeOffset date, - string thumbnailUrl, string avatarUrl) - { - Channel = channelName; - Content = content; - TimeStamp = date; - Id = id; - Type = TypeConversion(type); - Avatar = avatarUrl ?? "ms-appx:///Assets/Icons/Profile.png"; - Thumbnail = thumbnailUrl; - } - - public Notification(string xmlSource) - { - System.Xml.XmlDocument d = new System.Xml.XmlDocument(); - d.InnerXml = xmlSource; - System.Xml.XmlElement xml = d["item"]; - - Channel = xml["channelName"].InnerText; - Content = xml["content"].InnerText; - TimeStamp = DateTimeOffset.Parse(xml.GetAttribute("time")); - Id = xml.GetAttribute("id"); - Type = TypeConversion(xml.GetAttribute("type")); - Avatar = xml["images"].GetAttribute("avatar"); - Thumbnail = xml["images"].GetAttribute("thumbnail"); - } - - public string GetXml() - { - return $@" - - {Channel} - {Content} - "; - } - - public Button GetNotification() - { - StackPanel stackPanel = new StackPanel() { Margin = new Thickness(10, 0, 0, 0) }; - - //Channel - switch (Type) - { - case NotificationType.Internal: - stackPanel.Children.Add(new TextBlock() - { - FontSize = 14, - FontStyle = Windows.UI.Text.FontStyle.Italic, - Foreground = new SolidColorBrush(Colors.Gray), - Text = "Developer's message" - }); - break; - - case NotificationType.Changelog: - stackPanel.Children.Add(new TextBlock() - { - FontSize = 14, - FontStyle = Windows.UI.Text.FontStyle.Italic, - Foreground = new SolidColorBrush(Colors.Gray), - Text = "Changelog" - }); - break; - - case NotificationType.Video: - stackPanel.Children.Add(new TextBlock() - { - FontSize = 14, - FontStyle = Windows.UI.Text.FontStyle.Italic, - Foreground = new SolidColorBrush(Colors.Gray), - Text = $"{Channel} uploaded new video" - }); - break; - } - - //Content - stackPanel.Children.Add(new TextBlock() - { - TextWrapping = TextWrapping.WrapWholeWords, - Text = Content, - }); - //Time - stackPanel.Children.Add(new TextBlock() - { - FontSize = 13, - Foreground = new SolidColorBrush(Colors.Gray), - Text = TimeStamp.ToString() - }); - PersonPicture avatar = new PersonPicture() - { - Height = 50, - VerticalAlignment = VerticalAlignment.Top, - ProfilePicture = string.IsNullOrWhiteSpace(Avatar) ? null : new BitmapImage(new Uri(Avatar)) - }; - - Grid grid = new Grid(); - grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(50) }); - grid.ColumnDefinitions.Add(new ColumnDefinition()); - - grid.Children.Add(avatar); - Grid.SetColumn(stackPanel, 1); - grid.Children.Add(stackPanel); - - Button item = new Button() - { - HorizontalAlignment = HorizontalAlignment.Stretch, - HorizontalContentAlignment = HorizontalAlignment.Left, - Background = new SolidColorBrush(Colors.Transparent), - Content = grid - }; - - return item; - } - - public ToastNotification GetToast() - { - XmlDocument template = new XmlDocument(); - switch (Type) - { - case NotificationType.Video: - template.LoadXml($@" - - - - {Content} - {Channel} uploaded a new video - - - - - - - - - "); - break; - - case NotificationType.Changelog: - template.LoadXml($@" - - - - - {Content} - {Channel} - - - "); - break; - - case NotificationType.Internal: - template.LoadXml($@" - - - - - {Content} - {Channel} - - - "); - break; - } - - return new ToastNotification(template); - } - - private string TypeConversion(NotificationType type) - { - switch(type) - { - case NotificationType.Comment: - return "comment"; - case NotificationType.Post: - return "post"; - case NotificationType.Video: - return "video"; - case NotificationType.Changelog: - return "changelog"; - default: - return "internal"; - } - } - - private NotificationType TypeConversion(string type) - { - switch (type) - { - case "comment": - return NotificationType.Comment; - case "post": - return NotificationType.Post; - case "video": - return NotificationType.Video; - case "changelog": - return NotificationType.Changelog; - default: - return NotificationType.Internal; - } - } - } -} diff --git a/FoxTube.Background/ResourceCreators.cs b/FoxTube.Background/ResourceCreators.cs new file mode 100644 index 0000000..0fd4c6f --- /dev/null +++ b/FoxTube.Background/ResourceCreators.cs @@ -0,0 +1,115 @@ +using Windows.Data.Xml.Dom; +using Windows.UI.Notifications; + +namespace FoxTube.Background +{ + public static class Notification + { + public static ToastNotification GetChangelogToast(string version) + { + XmlDocument template = new XmlDocument(); + + template.LoadXml($@" + + + + + Changelog + See what's new in version {version} + + + "); + + return new ToastNotification(template); + } + + public static ToastNotification GetVideoToast(string id, string channelId, string title, string channel, string thumbnail, string avatar) + { + XmlDocument template = new XmlDocument(); + + template.LoadXml($@" + + + + + {title} + {channel} uploaded a new video + + + + + + + + "); + + return new ToastNotification(template); + } + + public static ToastNotification GetInternalToast(string id, string header, string content, string thumbnail, string avatar) + { + XmlDocument template = new XmlDocument(); + + template.LoadXml($@" + + + + + {header} + {content} + + + "); + + return new ToastNotification(template); + } + } + + public static class Tiles + { + public static TileNotification GetTileLayout(string title, string channel, string thumbnail, string avatar) + { + XmlDocument doc = new XmlDocument(); + + doc.LoadXml($@" + + + + + + {channel} + {title} + + + + + + + + + + {channel} + {title} + + + + + + + + + + + + {channel} + {title} + + + + + "); + + return new TileNotification(doc); + } + } +} diff --git a/FoxTube/App.xaml.cs b/FoxTube/App.xaml.cs index 8188902..e4ee801 100644 --- a/FoxTube/App.xaml.cs +++ b/FoxTube/App.xaml.cs @@ -1,25 +1,17 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; +using Google.Apis.YouTube.v3.Data; +using System; +using System.Diagnostics; using System.Linq; -using System.Runtime.InteropServices.WindowsRuntime; using Windows.ApplicationModel; using Windows.ApplicationModel.Activation; -using Windows.ApplicationModel.Core; -using Windows.Foundation; -using Windows.Foundation.Collections; +using Windows.ApplicationModel.Background; using Windows.Globalization; using Windows.Storage; -using Windows.UI; -using Windows.UI.Core; -using Windows.UI.ViewManagement; +using Windows.System; +using Windows.System.Power; +using Windows.UI.Notifications; 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; namespace FoxTube @@ -33,36 +25,23 @@ namespace FoxTube /// Initializes the singleton application object. This is the first line of authored code /// executed, and as such is the logical equivalent of main() or WinMain(). /// - ApplicationDataContainer settings = ApplicationData.Current.LocalSettings; public App() { - try + SettingsStorage.LoadData(); + + switch (SettingsStorage.Theme) { - switch((int)settings.Values["themeMode"]) - { - case 0: - RequestedTheme = ApplicationTheme.Light; - break; - case 1: - RequestedTheme = ApplicationTheme.Dark; - break; - } - } catch { } - try - { - if (settings.Values["language"] == null) - { - List cultures = new List() { "ua", "ru", "by", "kz", "kg", "md", "lv", "ee" }; - if (cultures.Contains(CultureInfo.InstalledUICulture.ThreeLetterISOLanguageName)) - settings.Values.Add("language", "ru-RU"); - else - settings.Values.Add("language", "en-US"); - } - ApplicationLanguages.PrimaryLanguageOverride = (string)settings.Values["language"]; + case 0: + RequestedTheme = ApplicationTheme.Light; + break; + case 1: + RequestedTheme = ApplicationTheme.Dark; + break; } - catch { } - this.InitializeComponent(); - this.Suspending += OnSuspending; + + ApplicationLanguages.PrimaryLanguageOverride = SettingsStorage.Language; + InitializeComponent(); + Suspending += OnSuspending; } /// @@ -72,8 +51,6 @@ namespace FoxTube /// Details about the launch request and process. protected override void OnLaunched(LaunchActivatedEventArgs e) { - SecretsVault.CheckAuthorization(); - Frame rootFrame = Window.Current.Content as Frame; // Do not repeat app initialization when the Window already has content, @@ -85,11 +62,6 @@ namespace FoxTube rootFrame.NavigationFailed += OnNavigationFailed; - if (e.PreviousExecutionState == ApplicationExecutionState.Terminated) - { - //TODO: Load state from previously suspended application - } - // Place the frame in the current Window Window.Current.Content = rootFrame; } @@ -106,8 +78,150 @@ namespace FoxTube // Ensure the current window is active Window.Current.Activate(); } + + ActivateToastBackgoundTask(); + ActivateBackgoundTask(); + } - CoreApplication.GetCurrentView().TitleBar.ExtendViewIntoTitleBar = true; + /// + /// Initializes background task for processing toast notifications' clicks + /// + public async void ActivateToastBackgoundTask() + { + const string taskName = "FoxtubeToastBackground"; + 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) + return; + + BackgroundTaskBuilder builder = new BackgroundTaskBuilder() { Name = taskName }; + builder.SetTrigger(new ToastNotificationActionTrigger()); + + BackgroundTaskRegistration registration = builder.Register(); + } + + /// + /// Initializes background task for checking user's subscriptions and poping toast notifications when new video is uploaded + /// + 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 async override void OnBackgroundActivated(BackgroundActivatedEventArgs args) + { + 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('|'); + + switch (arguments[0]) + { + case "later": + try + { + if (!SecretsVault.IsAuthorized) + SecretsVault.CheckAuthorization(false); + if (!SecretsVault.IsAuthorized) + throw new Exception("Not authenticated"); + + 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(); + } + catch (Exception e) + { + Debug.WriteLine(e.Message); + } + break; + case "download": + await Launcher.LaunchFileAsync(await StorageFile.GetFileFromPathAsync(arguments[1])); + break; + } + } + + deferral.Complete(); + } + + protected override void OnActivated(IActivatedEventArgs e) + { + base.OnActivated(e); + + Frame rootFrame = Window.Current.Content as Frame; + + if (rootFrame == null) + { + rootFrame = new Frame(); + rootFrame.NavigationFailed += OnNavigationFailed; + + Window.Current.Content = rootFrame; + } + + if (rootFrame.Content == null) + { + rootFrame.Navigate(typeof(MainPage)); + } + + Window.Current.Activate(); + + if (e is ToastNotificationActivatedEventArgs) + { + string[] args = (e as ToastNotificationActivatedEventArgs).Argument.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.Remove(args[1]); + break; + } + } } /// @@ -130,7 +244,8 @@ namespace FoxTube private void OnSuspending(object sender, SuspendingEventArgs e) { var deferral = e.SuspendingOperation.GetDeferral(); - //TODO: Save application state and stop any background activity + SettingsStorage.ExportSettings(); + DownloadAgent.QuitPrompt(); deferral.Complete(); } } diff --git a/FoxTube/Assets/StoreLogo.scale-100.png b/FoxTube/Assets/StoreLogo.scale-100.png index 9d3b85f..3ab11f5 100644 Binary files a/FoxTube/Assets/StoreLogo.scale-100.png and b/FoxTube/Assets/StoreLogo.scale-100.png differ diff --git a/FoxTube/Assets/StoreLogo.scale-125.png b/FoxTube/Assets/StoreLogo.scale-125.png index c3c5610..cb504c8 100644 Binary files a/FoxTube/Assets/StoreLogo.scale-125.png and b/FoxTube/Assets/StoreLogo.scale-125.png differ diff --git a/FoxTube/Assets/StoreLogo.scale-150.png b/FoxTube/Assets/StoreLogo.scale-150.png index a541ede..8b8b63b 100644 Binary files a/FoxTube/Assets/StoreLogo.scale-150.png and b/FoxTube/Assets/StoreLogo.scale-150.png differ diff --git a/FoxTube/Assets/StoreLogo.scale-200.png b/FoxTube/Assets/StoreLogo.scale-200.png index 2fe564e..4e8cf47 100644 Binary files a/FoxTube/Assets/StoreLogo.scale-200.png and b/FoxTube/Assets/StoreLogo.scale-200.png differ diff --git a/FoxTube/Assets/StoreLogo.scale-400.png b/FoxTube/Assets/StoreLogo.scale-400.png index 428e767..67f49b5 100644 Binary files a/FoxTube/Assets/StoreLogo.scale-400.png and b/FoxTube/Assets/StoreLogo.scale-400.png differ diff --git a/FoxTube/Classes/DownloadAgent.cs b/FoxTube/Classes/DownloadAgent.cs index af7a334..cd60ce3 100644 --- a/FoxTube/Classes/DownloadAgent.cs +++ b/FoxTube/Classes/DownloadAgent.cs @@ -1,71 +1,75 @@ using System; using System.Collections.Generic; -using System.IO; using Windows.Storage; using FoxTube.Classes; using Newtonsoft.Json; -using Windows.UI.Popups; +using YoutubeExplode.Models.MediaStreams; +using Google.Apis.YouTube.v3.Data; +using System.Diagnostics; +using FoxTube.Controls; -namespace FoxTube.Controls +namespace FoxTube { - public class DownloadAgent + public static class DownloadAgent { - public List items = new List(); - StorageFolder roaming = ApplicationData.Current.RoamingFolder; - - public DownloadAgent() - { - Initialize(); - Windows.UI.Core.Preview.SystemNavigationManagerPreview.GetForCurrentView().CloseRequested += (s, a) => QuitPrompt(); - } + public static List items = new List(); + private static ApplicationDataContainer settings = ApplicationData.Current.LocalSettings; + public static StorageFolder Downloads { get; set; } - public async void Initialize() + public static async void Initialize() { + Downloads = await KnownFolders.VideosLibrary.CreateFolderAsync("FoxTube", CreationCollisionOption.OpenIfExists); try { - List containers = JsonConvert.DeserializeObject>(await FileIO.ReadTextAsync(await roaming.GetFileAsync("data.json"))); - - foreach (DownloadItemContainer i in containers) - try { items.Add(new DownloadItem(i)); } - catch (FileNotFoundException) { } + List containers = JsonConvert.DeserializeObject>((string)settings.Values["downloads"]); + containers.ForEach(i => items.Add(new DownloadItem(i))); } catch { } } - public void Add(string url) + public static void Add(MediaStreamInfo info, Video meta, string qualty) { - items.Add(new DownloadItem(url)); + items.Insert(0, new DownloadItem(info, meta, qualty)); } - private void Item_DownloadCanceled(object sender, params object[] e) + public static void CancelItem(string id) { - items.Remove(sender as DownloadItem); + DownloadItem item = items.Find(x => x.Container.Id == id); + if (item == null || !item.InProgress) + return; + + item.CancelPrompt(); } - public async void QuitPrompt() + public static void Remove(string id) { - if(items.Find(x => x.InProgress) != null) + DownloadItem item = items.Find(x => x.Container.Id == id); + if (item == null) + return; + + if (item.InProgress) + item.Cancel(); + else + items.Remove(item); + } + + public static void QuitPrompt() + { + foreach (DownloadItem i in items.FindAll(i => i.InProgress)) + i.Cancel(); + + List containers = new List(); + items.ForEach(i => containers.Add(i.Container)); + + string data = JsonConvert.SerializeObject(containers); + + try { - MessageDialog dialog = new MessageDialog("You have some unfinished downloads. Quitting now will erase all downloaded data. Are you sure to continue?", "Some downloads are still pending"); - - dialog.Commands.Add(new UICommand("Yes", async (command) => - { - foreach (DownloadItem i in items.FindAll(x => x.InProgress)) - i.Cancel(); - items.RemoveAll(x => x.InProgress); - - List containers = new List(); - foreach (DownloadItem i in items) - containers.Add(i.Container); - - await FileIO.WriteTextAsync( - await roaming.CreateFileAsync("data.json", CreationCollisionOption.ReplaceExisting), - JsonConvert.SerializeObject(containers)); - })); - dialog.Commands.Add(new UICommand("No")); - - dialog.DefaultCommandIndex = 1; - await dialog.ShowAsync(); + settings.Values["downloads"] = data; + } + catch + { + settings.Values.Add("downloads", data); } } } diff --git a/FoxTube/Classes/DownloadItemContainer.cs b/FoxTube/Classes/DownloadItemContainer.cs index f7e6fe2..b857c75 100644 --- a/FoxTube/Classes/DownloadItemContainer.cs +++ b/FoxTube/Classes/DownloadItemContainer.cs @@ -1,5 +1,5 @@ using System; -using YoutubeExplode.Models.MediaStreams; +using Windows.Storage; namespace FoxTube.Classes { @@ -8,9 +8,10 @@ namespace FoxTube.Classes public string Title { get; set; } public string Channel { get; set; } public string Id { get; set; } - public Uri Path { get; set; } + public string Name { get; set; } + public string Extension { get; set; } public Uri Thumbnail { get; set; } - public VideoQuality Quality { get; set; } + public string Quality { get; set; } public TimeSpan Duration { get; set; } } } diff --git a/FoxTube/Classes/InboxItem.cs b/FoxTube/Classes/InboxItem.cs index 842d370..7eaaa48 100644 --- a/FoxTube/Classes/InboxItem.cs +++ b/FoxTube/Classes/InboxItem.cs @@ -9,8 +9,7 @@ namespace FoxTube.Classes { public InboxItemType Type { get; set; } = InboxItemType.Default; public DateTime TimeStamp { get; set; } - - public string PatchVersion { get; set; } + public string Subject { get; set; } public string Content { get; set; } public string Id { get; set; } @@ -41,20 +40,19 @@ namespace FoxTube.Classes get { if (Type == InboxItemType.PatchNote) - return $"What's new in v{PatchVersion}"; + return $"What's new in v{Id}"; else return Subject; } } - public InboxItem(string version, string content, string timeStamp, string id) + public InboxItem(string version, string content, string timeStamp) { Type = InboxItemType.PatchNote; - PatchVersion = version; Content = content; TimeStamp = DateTime.Parse(timeStamp); - Id = id; + Id = version; } public InboxItem(string title, string content, DateTime timeStamp, string id) diff --git a/FoxTube/Classes/Methods.cs b/FoxTube/Classes/Methods.cs index f7fa11e..fef6a3f 100644 --- a/FoxTube/Classes/Methods.cs +++ b/FoxTube/Classes/Methods.cs @@ -1,9 +1,15 @@ using Google.Apis.YouTube.v3; using System; +using System.Collections.Generic; using System.Diagnostics; +using System.IO; +using System.Linq; using System.Text.RegularExpressions; using System.Web; using Windows.ApplicationModel.Core; +using Windows.ApplicationModel.DataTransfer; +using Windows.Storage; +using Windows.Storage.Streams; using Windows.System; using Windows.UI; using Windows.UI.Xaml; @@ -31,6 +37,33 @@ namespace FoxTube return new Uri(url); } + public static void ForEach(this IEnumerable array, Action action) + { + array.ToList().ForEach(action); + } + + public static T Find(this IEnumerable array, Predicate match) + { + return array.ToList().Find(match); + } + + public static List FindAll(this IEnumerable array, Predicate match) + { + return array.ToList().FindAll(match); + } + + public static string ReplaceInvalidChars(this string str, char newValue) + { + foreach (char i in Path.GetInvalidFileNameChars()) + str = str.Replace(i, newValue); + return str; + } + + public static string Last(this string[] arr) + { + return arr[arr.Length - 1]; + } + public static string GetAgo(DateTime dateTime) { TimeSpan span = DateTime.Now - dateTime; @@ -204,5 +237,29 @@ namespace FoxTube await Launcher.LaunchUriAsync(new Uri(url)); } } + + public static async void Share(DataRequestedEventArgs args, string thumbnail, string title, string url, string type) + { + DataRequest request = args.Request; + request.Data.Properties.Title = title; + request.Data.Properties.Description = $"Sharing a {type}"; + + request.Data.SetText(title + "\n" + "#YouTube #FoxTube #SharedWithFoxTube"); + request.Data.SetWebLink(url.ToUri()); + + DataRequestDeferral deferral = request.GetDeferral(); + try + { + StorageFile thumbnailFile = await StorageFile.CreateStreamedFileFromUriAsync("tempThumb.jpg", thumbnail.ToUri(), null); + request.Data.Properties.Thumbnail = RandomAccessStreamReference.CreateFromFile(thumbnailFile); + StorageFile imageFile = thumbnailFile; + + request.Data.SetBitmap(RandomAccessStreamReference.CreateFromFile(imageFile)); + } + finally + { + deferral.Complete(); + } + } } } diff --git a/FoxTube/Classes/ObjectEventArgs.cs b/FoxTube/Classes/SearchPaameters.cs similarity index 92% rename from FoxTube/Classes/ObjectEventArgs.cs rename to FoxTube/Classes/SearchPaameters.cs index 23cd9d0..8b6e86c 100644 --- a/FoxTube/Classes/ObjectEventArgs.cs +++ b/FoxTube/Classes/SearchPaameters.cs @@ -1,27 +1,12 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using static Google.Apis.YouTube.v3.SearchResource.ListRequest; namespace FoxTube { public delegate void Event(); - public delegate void ObjectEventHandler(object sender, params object[] args); - - /*public class SearchParameters - { - public string ChannelId { get; set; } - public string Term { get; set; } - - public SearchParameters(string channelId, string term) - { - ChannelId = channelId; - Term = term; - } - }*/ + public delegate void ObjectEventHandler(object sender = null, params object[] args); public class SearchParameters { diff --git a/FoxTube/Classes/SecretsVault.cs b/FoxTube/Classes/SecretsVault.cs index 2d305b5..707599e 100644 --- a/FoxTube/Classes/SecretsVault.cs +++ b/FoxTube/Classes/SecretsVault.cs @@ -1,75 +1,72 @@ using System; using System.Collections.Generic; -using System.Diagnostics; -using System.Net; using System.Threading; using System.Threading.Tasks; using Google.Apis.Auth.OAuth2; -using Google.Apis.Auth.OAuth2.Flows; using Google.Apis.Services; using Google.Apis.YouTube.v3; using Google.Apis.YouTube.v3.Data; +using Newtonsoft.Json; using Windows.Storage; -using Windows.UI.Popups; namespace FoxTube { public static class SecretsVault { - public static event EventHandler AuthorizationStateChanged; + #region Properties + //Events + public static event ObjectEventHandler AuthorizationStateChanged; public static event ObjectEventHandler SubscriptionsChanged; + public static event Event NotPurchased; //Rising when app finds out that it's not a PRO version - private static ApplicationDataContainer settings = ApplicationData.Current.LocalSettings; - public static NetworkCredential EmailCredential => new NetworkCredential("youwillneverknowthisadress@gmail.com", "thisisthepassword12345"); - public static ClientSecrets Secrets => new ClientSecrets() + //Private properties + private static ClientSecrets Secrets => new ClientSecrets() { ClientId = "349735264870-2ekqlm0a4mkg3mmrfcv90s3qp3o15dq0.apps.googleusercontent.com", ClientSecret = "BkVZOAaCU2Zclf0Zlicg6y2_" }; - private static UserCredential Credential; + private static YouTubeService NoAuthService => new YouTubeService(new BaseClientService.Initializer() + { + ApiKey = "AIzaSyBgHrCnrlzlVmk0cJKL8RqP9Y8x6XSuk_0", + ApplicationName = "FoxTube" + }); public static BaseClientService.Initializer Initializer => new BaseClientService.Initializer() { HttpClientInitializer = Credential, ApplicationName = "FoxTube" }; + public static YouTubeService Service => IsAuthorized ? new YouTubeService(Initializer) : NoAuthService; + public static bool AdsDisabled { get; private set; } = true; - public static string AccountId { get; private set; } - public static bool IsAuthorized { get; private set; } = false; + //User info + public static bool IsAuthorized => Credential != null; + private static UserCredential Credential { get; set; } + public static string AccountId => UserChannel?.Id; public static Channel UserChannel { get; private set; } - public static List WatchLater { get; private set; } = new List(); - public static List UserHistory { get; private set; } = new List(); - public static List Subscriptions { get; private set; } = new List(); - public static YouTubeService NoAuthService => new YouTubeService(new BaseClientService.Initializer() - { - ApiKey = "AIzaSyBgHrCnrlzlVmk0cJKL8RqP9Y8x6XSuk_0", - ApplicationName = "FoxTube" - }); - public static YouTubeService Service - { - get - { - if (IsAuthorized) - return new YouTubeService(Initializer); - else - return NoAuthService; - } - } + public static List Subscriptions { get; } = new List(); + #endregion + #region Methods + /// + /// Subscribes or unsibscribes authorized user from the channel + /// + /// The ID of channel which has to be added/removed + /// Returns 'true' if channel is in subscriptions now; 'false' if it's not public static async Task ChangeSubscriptionState(string id) { if (!IsAuthorized) return false; - if(Subscriptions.Find(x => x.Snippet.ResourceId.ChannelId == id) != null) + if(Subscriptions.Exists(x => x.Snippet.ResourceId.ChannelId == id)) { Subscription s = Subscriptions.Find(x => x.Snippet.ResourceId.ChannelId == id); try { await Service.Subscriptions.Delete(s.Id).ExecuteAsync(); } catch { return true; } - SubscriptionsChanged.Invoke(null, "remove", Subscriptions.IndexOf(s)); + SubscriptionsChanged?.Invoke(null, "remove", Subscriptions.IndexOf(s)); Subscriptions.Remove(s); return false; } @@ -91,194 +88,122 @@ namespace FoxTube if (s == null) return false; Subscriptions.Add(s); - SubscriptionsChanged.Invoke(null, "add", s); + SubscriptionsChanged?.Invoke(null, "add", s); return true; } } - public static async Task Subscribe(string id) - { - if (!IsAuthorized) - return false; - - var request = Service.Subscriptions.Insert(new Subscription() - { - Snippet = new SubscriptionSnippet() - { - ResourceId = new ResourceId() - { - ChannelId = id, - Kind = "youtube#channel" - } - } - }, "snippet"); - - Subscription s = await request.ExecuteAsync(); - if (s == null) - return false; - Subscriptions.Add(s); - SubscriptionsChanged.Invoke(null, "add", s); - return true; - } - - public static async Task Unsubscibe(string id) - { - if (!IsAuthorized) - return false; - - Subscription s = null; - foreach(Subscription i in Subscriptions) - if (i.Snippet.ResourceId.ChannelId == id) - { - s = i; - break; - } - if (s == null) - return false; - - try - { - await Service.Subscriptions.Delete(s.Id).ExecuteAsync(); - } - catch - { - return false; - } - - SubscriptionsChanged.Invoke(null, "remove", Subscriptions.IndexOf(s)); - Subscriptions.Remove(s); - return true; - } - - public static async void Authorize() + /// + /// Prompts to add an Youtube account and retrieves its info when successful + /// + /// Loads user's subscriptions if true + public static async void Authorize(bool retrieveSubs = true) { try { + #region Retrieving user's credential Credential = await GoogleWebAuthorizationBroker.AuthorizeAsync( Secrets, new[] { - Google.Apis.Oauth2.v2.Oauth2Service.Scope.UserinfoProfile, - YouTubeService.Scope.YoutubeForceSsl + Google.Apis.Oauth2.v2.Oauth2Service.Scope.UserinfoProfile, + YouTubeService.Scope.YoutubeForceSsl }, "user", CancellationToken.None); + + if (Credential == null || !retrieveSubs) + goto InvokeEvent; - if (Credential != null) + SettingsStorage.HasAccount = true; + #endregion + + #region Retrieving user's data + var request = Service.Channels.List("snippet,contentDetails"); + request.Mine = true; + UserChannel = (await request.ExecuteAsync()).Items[0]; + + SubscriptionsResource.ListRequest subRequest = Service.Subscriptions.List("snippet"); + subRequest.Mine = true; + subRequest.MaxResults = 50; + subRequest.Order = SubscriptionsResource.ListRequest.OrderEnum.Relevance; + SubscriptionListResponse subResponse; + string nextToken = null; + Subscriptions.Clear(); + + do { - if (settings.Values["authorized"] == null) - settings.Values.Add("authorized", true); - else settings.Values["authorized"] = true; - IsAuthorized = true; - - var request = Service.Channels.List("snippet,contentDetails"); - request.Mine = true; - UserChannel = (await request.ExecuteAsync()).Items[0]; - AccountId = UserChannel.Id; - - PlaylistItemsResource.ListRequest playlistRequest = Service.PlaylistItems.List("snippet"); - playlistRequest.PlaylistId = UserChannel.ContentDetails.RelatedPlaylists.WatchHistory; - playlistRequest.MaxResults = 50; - PlaylistItemListResponse playlistResponse = await playlistRequest.ExecuteAsync(); - UserHistory.Clear(); - foreach (PlaylistItem i in playlistResponse.Items) - UserHistory.Add(i); - - playlistRequest = Service.PlaylistItems.List("snippet"); - playlistRequest.PlaylistId = UserChannel.ContentDetails.RelatedPlaylists.WatchLater; - playlistRequest.MaxResults = 50; - playlistResponse = await playlistRequest.ExecuteAsync(); - WatchLater.Clear(); - - foreach (PlaylistItem i in playlistResponse.Items) - WatchLater.Add(i); - - string nextToken = playlistResponse.NextPageToken; - while (nextToken != null) - { - playlistRequest.PageToken = nextToken; - playlistResponse = await playlistRequest.ExecuteAsync(); - foreach (PlaylistItem i in playlistResponse.Items) - WatchLater.Add(i); - - nextToken = playlistResponse.NextPageToken; - } - - SubscriptionsResource.ListRequest subRequest = Service.Subscriptions.List("snippet"); - subRequest.Mine = true; - subRequest.MaxResults = 50; - subRequest.Order = SubscriptionsResource.ListRequest.OrderEnum.Relevance; - SubscriptionListResponse subResponse = await subRequest.ExecuteAsync(); - Subscriptions.Clear(); - + subRequest.PageToken = nextToken; + subResponse = await subRequest.ExecuteAsync(); foreach (Subscription s in subResponse.Items) Subscriptions.Add(s); - nextToken = subResponse.NextPageToken; - while (nextToken != null) - { - subRequest.PageToken = nextToken; - subResponse = await subRequest.ExecuteAsync(); - foreach (Subscription s in subResponse.Items) - Subscriptions.Add(s); - } - } + + } while (!string.IsNullOrWhiteSpace(nextToken)); + #endregion + + //Saving user's subscriptions for background task + SaveSubscriptions(); + + InvokeEvent: + AuthorizationStateChanged?.Invoke(args: IsAuthorized); } catch { - MessageDialog dialog = new MessageDialog("We were unabled to retrieve your account information due to weak internet connection or Google servers' problems. PLease, try again later", "Failed to connect"); - - dialog.Commands.Add(new UICommand("Try again", (command) => - { - Authorize(); - })); - dialog.Commands.Add(new UICommand("Quit", (command) => - { - Methods.CloseApp(); - })); - dialog.Commands.Add(new UICommand("Close")); - - await dialog.ShowAsync(); - - IsAuthorized = false; + AuthorizationStateChanged?.Invoke(args: new bool?[] { null }); } - - AuthorizationStateChanged.Invoke(null, null); } + /// + /// Saves user's subscriptions keypairs (channel ID: avatar URL) into "background.json" file for concurrent background processing + /// + public static async void SaveSubscriptions() + { + Dictionary subs = new Dictionary(); + Subscriptions.ForEach(x => subs.Add(x.Snippet.ResourceId.ChannelId, x.Snippet.Thumbnails.Medium.Url)); + await FileIO.WriteTextAsync( + await ApplicationData.Current.RoamingFolder.CreateFileAsync("background.json", CreationCollisionOption.ReplaceExisting), + JsonConvert.SerializeObject(subs)); + } + + /// + /// Deauthenticates current user + /// public static async void Deauthenticate() { if(await Credential.RevokeTokenAsync(CancellationToken.None)) { Credential = null; - IsAuthorized = false; - AuthorizationStateChanged.Invoke(null, null); - settings.Values["authorized"] = false; + AuthorizationStateChanged?.Invoke(args: false); + SettingsStorage.HasAccount = false; } } - public static void CheckAuthorization() + /// + /// Checks if any user has already been logged in. If has, calls *Authorize()* to retrieve his info + /// + /// Loads user's subscriptions if true + public static void CheckAuthorization(bool retrieveSubs = true) { - if (settings.Values["authorized"] == null || !(bool)settings.Values["authorized"]) - IsAuthorized = false; - else - Authorize(); + if (SettingsStorage.HasAccount) + Authorize(retrieveSubs); + else AuthorizationStateChanged.Invoke(args: false); } - public static bool AdsDisabled { get; private set; } = true; - + /// + /// Connects to MS Store and checks if user has bought ad-free + /// public static void CheckAddons() { - //TO-DO: Check addons list + //TODO: Check addons list bool purchased = true; if(!purchased) { AdsDisabled = false; - NotPurchased.Invoke(); + NotPurchased?.Invoke(); } } - - public static event Event NotPurchased; + #endregion } } diff --git a/FoxTube/Classes/SettingsStorage.cs b/FoxTube/Classes/SettingsStorage.cs new file mode 100644 index 0000000..6ce1403 --- /dev/null +++ b/FoxTube/Classes/SettingsStorage.cs @@ -0,0 +1,194 @@ +using Newtonsoft.Json; +using System; +using System.Globalization; +using System.Linq; +using Windows.ApplicationModel; +using Windows.Storage; + +namespace FoxTube +{ + public static class SettingsStorage + { + public static string VideoQuality + { + get { return (string)settings[0]; } + set + { + settings[0] = value; + SaveData(); + } + } + public static string RememberedQuality + { + get { return (string)settings[1]; } + set + { + settings[1] = value; + SaveData(); + } + } + + public static bool VideoNotifications + { + get { return (bool)settings[2]; } + set + { + settings[2] = value; + SaveData(); + } + } + public static bool DevNotifications + { + get { return (bool)settings[3]; } + set + { + settings[3] = value; + SaveData(); + } + } + + public static bool CheckConnection + { + get { return (bool)settings[4]; } + set + { + settings[4] = value; + SaveData(); + } + } + public static bool Autoplay + { + get { return (bool)settings[5]; } + set + { + settings[5] = value; + SaveData(); + } + } + public static int Volume + { + get { return Convert.ToInt32(settings[6]); } + set + { + settings[6] = value; + SaveData(); + } + } + + public static string Language + { + get { return (string)settings[7]; } + set + { + settings[7] = value; + SaveData(); + } + } + public static string Region + { + get { return (string)settings[8]; } + set + { + settings[8] = value; + SaveData(); + } + } + public static int SafeSearch + { + get { return Convert.ToInt32(settings[9]); } + set + { + settings[9] = value; + SaveData(); + } + } + + public static int Theme + { + get { return Convert.ToInt32(settings[10]); } + set + { + settings[10] = value; + SaveData(); + } + } + public static bool HasAccount + { + get { return (bool)settings[11]; } + set + { + settings[11] = value; + SaveData(); + } + } + + public static string Version + { + get + { + if (storage.Values["ver"] == null) + { + PackageVersion ver = Package.Current.Id.Version; + storage.Values["version"] = $"{ver.Major}.{ver.Minor}"; + return $"{ver.Major}.{ver.Minor}"; + } + else return (string)storage.Values["version"]; + } + set + { + storage.Values["version"] = value; + } + } + + //Settings storage + private static readonly ApplicationDataContainer storage = ApplicationData.Current.LocalSettings; + + //Predefined preferences + private static object[] settings = new object[] + { + "remember", + "1080p", + + true, + true, + + true, + true, + 100, + + (new[] { "ua", "ru", "by", "kz", "kg", "md", "lv", "ee" }).Contains(CultureInfo.InstalledUICulture.TwoLetterISOLanguageName) ? "ru-RU" : "en-US", + CultureInfo.CurrentCulture.Name, + 0, + + 2, + false + }; + + public static void LoadData() + { + try + { + settings = JsonConvert.DeserializeObject(storage.Values["settings"] as string); + } + catch (ArgumentNullException) { } + } + + public static async void SaveData() + { + storage.Values["settings"] = JsonConvert.SerializeObject(settings); + ExportSettings(); + } + + public static async void ExportSettings() + { + try + { + bool[] notificationsSettings = new[] { VideoNotifications, DevNotifications }; + await FileIO.WriteTextAsync( + await ApplicationData.Current.RoamingFolder.CreateFileAsync("notifications.json", CreationCollisionOption.ReplaceExisting), + JsonConvert.SerializeObject(notificationsSettings)); + } + catch { } + } + } +} diff --git a/FoxTube/Controls/Advert.xaml b/FoxTube/Controls/Advert.xaml new file mode 100644 index 0000000..5c2bd8e --- /dev/null +++ b/FoxTube/Controls/Advert.xaml @@ -0,0 +1,17 @@ + + + + + + diff --git a/FoxTube/Controls/Advert.xaml.cs b/FoxTube/Controls/Advert.xaml.cs new file mode 100644 index 0000000..dfdf5e7 --- /dev/null +++ b/FoxTube/Controls/Advert.xaml.cs @@ -0,0 +1,69 @@ +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; + +namespace FoxTube.Controls +{ + public sealed partial class Advert : UserControl + { + public string AdUnitId { get; set; } = "test"; + public string AppId => "3f83fe91-d6be-434d-a0ae-7351c5a997f1"; + public bool OverrideSize { get; set; } = false; + + public new double Height + { + get { return ad.Height; } + set + { + ad.Height = value; + OverrideSize = true; + } + } + + public new double Width + { + get { return ad.Width; } + set + { + ad.Width = value; + OverrideSize = true; + } + } + + public Advert() + { + InitializeComponent(); + if (!SecretsVault.AdsDisabled) + Visibility = Visibility.Visible; + else + Visibility = Visibility.Collapsed; + SecretsVault.NotPurchased += () => Visibility = Visibility.Visible; + } + + private void Grid_SizeChanged(object sender, SizeChangedEventArgs e) + { + if (OverrideSize) + return; + + if(grid.ActualWidth >= 728) + { + ad.Width = 728; + ad.Height = 90; + } + else if (grid.ActualWidth >= 640) + { + ad.Width = 640; + ad.Height = 100; + } + else if (grid.ActualWidth >= 320) + { + ad.Width = 320; + ad.Height = 50; + } + else + { + ad.Width = 300; + ad.Height = 50; + } + } + } +} diff --git a/FoxTube/Controls/ChannelCard.xaml.cs b/FoxTube/Controls/ChannelCard.xaml.cs index 7ccd966..327417d 100644 --- a/FoxTube/Controls/ChannelCard.xaml.cs +++ b/FoxTube/Controls/ChannelCard.xaml.cs @@ -39,7 +39,7 @@ namespace FoxTube.Controls public async void Initialize(string id, string live) { - ChannelsResource.ListRequest request = SecretsVault.NoAuthService.Channels.List("snippet,statistics,brandingSettings"); + ChannelsResource.ListRequest request = SecretsVault.Service.Channels.List("snippet,statistics,brandingSettings"); request.Id = id; ChannelListResponse response = await request.ExecuteAsync(); diff --git a/FoxTube/Controls/ChannelCardWide.xaml b/FoxTube/Controls/ChannelCardWide.xaml deleted file mode 100644 index 5327558..0000000 --- a/FoxTube/Controls/ChannelCardWide.xaml +++ /dev/null @@ -1,36 +0,0 @@ - - - - diff --git a/FoxTube/Controls/ChannelCardWide.xaml.cs b/FoxTube/Controls/ChannelCardWide.xaml.cs deleted file mode 100644 index 312a0b6..0000000 --- a/FoxTube/Controls/ChannelCardWide.xaml.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System; -using Windows.UI.Xaml; -using Windows.UI.Xaml.Controls; -using Windows.UI.Xaml.Media.Imaging; -using Google.Apis.Services; -using Google.Apis.YouTube.v3; -using Google.Apis.YouTube.v3.Data; - -namespace FoxTube.Controls -{ - public sealed partial class ChannelCardWide : UserControl - { - string channelId; - public ChannelCardWide(string id, string live) - { - this.InitializeComponent(); - Initialize(id, live); - } - - public async void Initialize(string id, string live) - { - YouTubeService ytService = new YouTubeService(new BaseClientService.Initializer() - { - ApiKey = "AIzaSyBgHrCnrlzlVmk0cJKL8RqP9Y8x6XSuk_0", - ApplicationName = this.GetType().ToString() - }); - - ChannelsResource.ListRequest request = ytService.Channels.List("snippet,contentDetails,statistics"); - request.Id = id; - ChannelListResponse response = await request.ExecuteAsync(); - - var item = response.Items[0]; - - channelId = id; - - channelName.Text = item.Snippet.Title; - subscribers.Text = string.Format("{0} subscribers", item.Statistics.SubscriberCount); - videoCount.Text = string.Format("{0} videos", item.Statistics.VideoCount); - - avatar.ProfilePicture = new BitmapImage(new Uri(item.Snippet.Thumbnails.Medium.Url)); - if (live == "live") - liveTag.Visibility = Visibility.Visible; - } - - private void Button_Click(object sender, RoutedEventArgs e) - { - Methods.MainPage.GoToChannel(channelId); - } - } -} diff --git a/FoxTube/Controls/DownloadItem.xaml b/FoxTube/Controls/DownloadItem.xaml index 212cb5c..7076e5d 100644 --- a/FoxTube/Controls/DownloadItem.xaml +++ b/FoxTube/Controls/DownloadItem.xaml @@ -10,7 +10,7 @@ d:DesignWidth="1500"> - + @@ -19,10 +19,11 @@ - + + - + @@ -43,10 +44,10 @@ - - + + - - diff --git a/FoxTube/Controls/PlaylistCardWide.xaml.cs b/FoxTube/Controls/PlaylistCardWide.xaml.cs deleted file mode 100644 index e89c450..0000000 --- a/FoxTube/Controls/PlaylistCardWide.xaml.cs +++ /dev/null @@ -1,74 +0,0 @@ -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.Media.Imaging; -using Windows.UI.Xaml.Navigation; - -using Google.Apis.Services; -using Google.Apis.YouTube.v3; -using Google.Apis.YouTube.v3.Data; -using System.Threading.Tasks; -using System.Threading; -using Google.Apis.Util.Store; - -// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236 - -namespace FoxTube -{ - public sealed partial class PlaylistCardWide : UserControl - { - public string playlistId; - Playlist item; - public PlaylistCardWide(string id, bool hideAuthor = false) - { - this.InitializeComponent(); - Initialize(id, hideAuthor); - } - - public async void Initialize(string id, bool hideAuthor) - { - PlaylistsResource.ListRequest request = SecretsVault.NoAuthService.Playlists.List("snippet,contentDetails"); - request.Id = id; - PlaylistListResponse response = await request.ExecuteAsync(); - - item = response.Items[0]; - - playlistId = id; - - title.Text = item.Snippet.Title; - info.Text = string.Format("{0} | {1} videos", item.Snippet.PublishedAt, item.ContentDetails.ItemCount); - thumbCount.Text = item.ContentDetails.ItemCount.ToString(); - thumbnail.Source = new BitmapImage(new Uri(item.Snippet.Thumbnails.Medium.Url)); - - if (hideAuthor) - authorData.Visibility = Visibility.Collapsed; - else - { - var request1 = SecretsVault.NoAuthService.Channels.List("snippet,contentDetails,statistics"); - request1.Id = item.Snippet.ChannelId; - ChannelListResponse response1 = await request1.ExecuteAsync(); - - var item1 = response1.Items[0]; - - avatar.ProfilePicture = new BitmapImage(new Uri(item1.Snippet.Thumbnails.Medium.Url)); - channelName.Text = item1.Snippet.Title; - channelSubs.Text = string.Format("{0} subscribers", item1.Statistics.SubscriberCount); - } - } - - private void channelLink_Click(object sender, RoutedEventArgs e) - { - Methods.MainPage.GoToChannel(item.Snippet.ChannelId); - } - } -} diff --git a/FoxTube/Controls/VideoCard.xaml b/FoxTube/Controls/VideoCard.xaml index 277d740..133eb85 100644 --- a/FoxTube/Controls/VideoCard.xaml +++ b/FoxTube/Controls/VideoCard.xaml @@ -18,10 +18,11 @@ - + + @@ -50,4 +51,15 @@ + + + + + + + + + + + diff --git a/FoxTube/Controls/VideoCard.xaml.cs b/FoxTube/Controls/VideoCard.xaml.cs index 132b6b7..4ad9977 100644 --- a/FoxTube/Controls/VideoCard.xaml.cs +++ b/FoxTube/Controls/VideoCard.xaml.cs @@ -30,9 +30,7 @@ namespace FoxTube.Controls public async void Initialize(string id, string playlist = null) { - YouTubeService ytService = SecretsVault.NoAuthService; - - VideosResource.ListRequest request = ytService.Videos.List("snippet,contentDetails,statistics,liveStreamingDetails"); + VideosResource.ListRequest request = SecretsVault.Service.Videos.List("snippet,contentDetails,statistics,liveStreamingDetails"); request.Id = id; VideoListResponse response = await request.ExecuteAsync(); @@ -71,7 +69,7 @@ namespace FoxTube.Controls embed = false; } - var request1 = ytService.Channels.List("snippet"); + var request1 = SecretsVault.Service.Channels.List("snippet"); request1.Id = item.Snippet.ChannelId; ChannelListResponse response1 = await request1.ExecuteAsync(); @@ -82,12 +80,11 @@ namespace FoxTube.Controls } catch { } - foreach(PlaylistItem i in SecretsVault.UserHistory) - if (i.Snippet.ResourceId.VideoId == id) - { - watched.Visibility = Visibility.Visible; - break; - } + /*if(SecretsVault.UserHistory.Exists(x => x.Id == videoId)) + { + watched.Visibility = Visibility.Visible; + leftOn.Value = SecretsVault.UserHistory.Find(x => x.Id == videoId).LeftOn; + }*/ } public async void Button_Click(object sender, RoutedEventArgs e) diff --git a/FoxTube/Controls/VideoCardWide.xaml b/FoxTube/Controls/VideoCardWide.xaml deleted file mode 100644 index 3bcb1ff..0000000 --- a/FoxTube/Controls/VideoCardWide.xaml +++ /dev/null @@ -1,53 +0,0 @@ - - - - diff --git a/FoxTube/Controls/VideoCardWide.xaml.cs b/FoxTube/Controls/VideoCardWide.xaml.cs deleted file mode 100644 index 96c0c7a..0000000 --- a/FoxTube/Controls/VideoCardWide.xaml.cs +++ /dev/null @@ -1,112 +0,0 @@ -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.Media.Imaging; -using Windows.UI.Xaml.Navigation; - -using Google.Apis.Services; -using Google.Apis.YouTube.v3; -using Google.Apis.YouTube.v3.Data; -using System.Threading.Tasks; -using System.Threading; -using Google.Apis.Util.Store; -using System.Xml; -using Windows.System; - -// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236 - -namespace FoxTube -{ - public sealed partial class VideoCardWide : UserControl - { - public string videoId; - Google.Apis.YouTube.v3.Data.Video item; - - bool embed = false; - public VideoCardWide(string id) - { - this.InitializeComponent(); - Initialize(id); - } - - public async void Initialize(string id) - { - YouTubeService ytService = SecretsVault.NoAuthService; - - VideosResource.ListRequest request = ytService.Videos.List("snippet,contentDetails,statistics,liveStreamingDetails"); - request.Id = id; - VideoListResponse response = await request.ExecuteAsync(); - - item = response.Items[0]; - - videoId = id; - - title.Text = item.Snippet.Title; - - string duration; - if (item.ContentDetails.Duration != null || item.ContentDetails.Duration != "") - { - TimeSpan ts = XmlConvert.ToTimeSpan(item.ContentDetails.Duration); - duration = string.Format("{0}{1:00}:{2:00} | ", ts.Hours == 0 ? "" : ts.Hours + ":", ts.Minutes, ts.Seconds); - } - else duration = string.Empty; - - info.Text = string.Format("{0}{1} | {2}", duration, Methods.GetAgo(item.Snippet.PublishedAt.Value), (item.LiveStreamingDetails != null && item.LiveStreamingDetails.ConcurrentViewers.HasValue) ? item.LiveStreamingDetails.ConcurrentViewers + " viewers" : item.Statistics.ViewCount + " views"); - thumbnail.Source = new BitmapImage(new Uri(item.Snippet.Thumbnails.Medium.Url)); - if (item.Snippet.LiveBroadcastContent == "live") - { - embed = true; - liveTag.Visibility = Visibility.Visible; - } - else if(item.Snippet.LiveBroadcastContent == "upcoming") - { - embed = true; - TimeSpan span; - if (item.LiveStreamingDetails.ScheduledStartTime != null && (item.LiveStreamingDetails.ScheduledStartTime - DateTime.Now).Value.TotalMilliseconds > 0) - { - span = (TimeSpan)(item.LiveStreamingDetails.ScheduledStartTime - DateTime.Now); - liveContent.Text = "Goes live in " + string.Format("{0}{1:00}:{2:00}:{3:00}", span.Days != 0 ? span.Days + ":" : "", span.Hours, span.Minutes, span.Seconds); - } - else - liveContent.Text = "Upcoming"; - liveTag.Visibility = Visibility.Visible; - } - - var request1 = ytService.Channels.List("snippet,contentDetails,statistics"); - request1.Id = item.Snippet.ChannelId; - ChannelListResponse response1 = await request1.ExecuteAsync(); - - var item1 = response1.Items[0]; - - avatar.ProfilePicture = new BitmapImage(new Uri(item1.Snippet.Thumbnails.Medium.Url)); - channelName.Text = item1.Snippet.Title; - channelSubs.Text = string.Format("{0} subscribers", item1.Statistics.SubscriberCount); - - //if (SecretsVault.UserHistory.Contains(item.Id)) - //watched.Visibility = Visibility.Visible; - } - - private void channelLink_Click(object sender, RoutedEventArgs e) - { - Methods.MainPage.GoToChannel(item.Snippet.ChannelId); - } - - private async void Button_Click(object sender, RoutedEventArgs e) - { - if (embed) - await Launcher.LaunchUriAsync(new Uri(string.Format("https://www.youtube.com/watch?v={0}", videoId))); - else - Methods.MainPage.GoToVideo(videoId); - } - } -} diff --git a/FoxTube/Controls/VideoPlayer.xaml b/FoxTube/Controls/VideoPlayer.xaml index e1fdb50..0a9a56f 100644 --- a/FoxTube/Controls/VideoPlayer.xaml +++ b/FoxTube/Controls/VideoPlayer.xaml @@ -98,7 +98,7 @@ - + @@ -168,5 +168,13 @@ public sealed partial class Downloads : Page { - ApplicationDataContainer settings = ApplicationData.Current.LocalSettings; public Downloads() { this.InitializeComponent(); - path.Text = settings.Values["defaultDownload"] as string; + SetPath(); } - private async void changePath_Click(object sender, RoutedEventArgs e) + protected override void OnNavigatedFrom(NavigationEventArgs e) { - FolderPicker picker = new FolderPicker() + base.OnNavigatedFrom(e); + stack.Children.Clear(); + } + + protected override void OnNavigatedTo(NavigationEventArgs e) + { + base.OnNavigatedTo(e); + DownloadAgent.items.ForEach(i => { - SuggestedStartLocation = PickerLocationId.Downloads, - ViewMode = PickerViewMode.Thumbnail - }; - picker.FileTypeFilter.Add(".shit"); //Because overwise it trhows an exception - - StorageFolder p = await picker.PickSingleFolderAsync(); - if (p != null) - settings.Values["defaultDownload"] = p.Path; - path.Text = settings.Values["defaultDownload"] as string; + stack.Children.Add(i); + i.Initialize(); + }); + empty.Visibility = stack.Children.Count > 0 ? Visibility.Collapsed : Visibility.Visible; } - private async void openFolder_Click(object sender, RoutedEventArgs e) + void SetPath() { - await Launcher.LaunchFolderAsync( await StorageFolder.GetFolderFromPathAsync(settings.Values["defaultDownload"] as string)); + path.Text = DownloadAgent.Downloads.Path; + } + + void Refresh(object sender, RoutedEventArgs e) + { + stack.Children.Clear(); + + DownloadAgent.items.ForEach(i => + { + stack.Children.Add(i); + i.Initialize(); + }); + empty.Visibility = stack.Children.Count > 0 ? Visibility.Collapsed : Visibility.Visible; + } + + private async void Open_Click(object sender, RoutedEventArgs e) + { + await Launcher.LaunchFolderAsync(DownloadAgent.Downloads); } } } diff --git a/FoxTube/Pages/History.xaml b/FoxTube/Pages/History.xaml index 5adfa85..5f274ca 100644 --- a/FoxTube/Pages/History.xaml +++ b/FoxTube/Pages/History.xaml @@ -12,16 +12,17 @@ Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> - - - - - + + + + + + - + + - - + diff --git a/FoxTube/Pages/History.xaml.cs b/FoxTube/Pages/History.xaml.cs index 3d6ac42..6211a17 100644 --- a/FoxTube/Pages/History.xaml.cs +++ b/FoxTube/Pages/History.xaml.cs @@ -1,17 +1,8 @@ using FoxTube.Controls; 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.System; 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 Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238 @@ -24,38 +15,35 @@ namespace FoxTube.Pages public sealed partial class History : Page { LoadingPage loading; - ShowMore more; VideoGrid list; public History() { - this.InitializeComponent(); + InitializeComponent(); + } + + protected override void OnNavigatedTo(NavigationEventArgs e) + { + base.OnNavigatedTo(e); + loading = grid.Children[2] as LoadingPage; - more = stack.Children[1] as ShowMore; - list = stack.Children[0] as VideoGrid; + list = scroll.Content as VideoGrid; Initialize(); } public void Initialize() { loading.Refresh(); - - more.Complete(true); - - loading.Block(); + + loading.Close(); } - private void ShowMore_Clicked() + private async void toBrowser_Click(object sender, RoutedEventArgs e) { - + await Launcher.LaunchUriAsync(new Uri("youtube.com/feed/history")); } - private void toBrowser_Click(object sender, RoutedEventArgs e) - { - - } - - private void refresh_Click(object sender, RoutedEventArgs e) + private void Refresh_Click(object sender, RoutedEventArgs e) { } diff --git a/FoxTube/Pages/Home.xaml b/FoxTube/Pages/Home.xaml index f1bca84..4b3dfdc 100644 --- a/FoxTube/Pages/Home.xaml +++ b/FoxTube/Pages/Home.xaml @@ -1,5 +1,4 @@  - + - - - - + @@ -35,10 +31,7 @@ - - - - + diff --git a/FoxTube/Pages/Home.xaml.cs b/FoxTube/Pages/Home.xaml.cs index 64b99d5..42574ae 100644 --- a/FoxTube/Pages/Home.xaml.cs +++ b/FoxTube/Pages/Home.xaml.cs @@ -1,68 +1,39 @@ 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; -using System.Globalization; - using Google.Apis.YouTube.v3; using Google.Apis.YouTube.v3.Data; using Windows.Storage; -using Windows.UI.Text; using FoxTube.Controls; using FoxTube.Pages; -using System.Collections.ObjectModel; -using System.Diagnostics; - -// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238 +using System.Globalization; namespace FoxTube { /// - /// An empty page that can be used on its own or navigated to within a Frame. + /// Home page /// public sealed partial class Home : Page { - private bool recLoaded = false; private bool trendLoaded = false; - private bool subsLoaded = false; - VideoGrid recGrid, trendGrid, subsGrid; - ShowMore recMore, trendMore, subsMore; + VideoGrid trendGrid; + ShowMore trendMore; LoadingPage loading; - string trendToken, recToken; + string trendToken; Dictionary subsTokens = new Dictionary(); string reg; public Home() { - this.InitializeComponent(); - try - { - reg = (ApplicationData.Current.LocalSettings.Values["region"] as string).ToLower().Remove(0, 3); - } - catch (ArgumentOutOfRangeException) - { - reg = (ApplicationData.Current.LocalSettings.Values["region"] as string).ToUpper(); - } - - recGrid = ((recommended.Content as ScrollViewer).Content as StackPanel).Children[0] as VideoGrid; + InitializeComponent(); + reg = CultureInfo.GetCultures(CultureTypes.AllCultures).Find(i => i.IetfLanguageTag == SettingsStorage.Region).IetfLanguageTag.Remove(0, 3); + trendGrid = ((trending.Content as ScrollViewer).Content as StackPanel).Children[0] as VideoGrid; - subsGrid = ((subscriptions.Content as ScrollViewer).Content as StackPanel).Children[0] as VideoGrid; - - recMore = ((recommended.Content as ScrollViewer).Content as StackPanel).Children[1] as ShowMore; - trendMore = ((trending.Content as ScrollViewer).Content as StackPanel).Children[1] as ShowMore; ; - subsMore = ((subscriptions.Content as ScrollViewer).Content as StackPanel).Children[1] as ShowMore; + trendMore = ((trending.Content as ScrollViewer).Content as StackPanel).Children[1] as ShowMore; loading = grid.Children[2] as LoadingPage; @@ -71,12 +42,7 @@ namespace FoxTube private void refreshPage(object sender, RoutedEventArgs e) { - (Parent as Frame).Navigate(typeof(Home)); - } - - private void RecMore_Clicked() - { - throw new NotImplementedException(); + Methods.MainPage.GoToHome(); } private async void TrendMore_Clicked() @@ -99,7 +65,7 @@ namespace FoxTube foreach (Video vid in response.Items) { VideoCard vCard = new VideoCard(vid.Id); - recGrid.Add(vCard); + trendGrid.Add(vCard); } trendMore.Complete(); } @@ -109,45 +75,6 @@ namespace FoxTube } } - private async void SubsMore_Clicked() - { - try - { - List items = new List(); - Dictionary pairs = new Dictionary(); - SearchResource.ListRequest request = SecretsVault.Service.Search.List("snippet"); - request.Type = "video"; - request.MaxResults = 10; - request.Order = SearchResource.ListRequest.OrderEnum.Date; - - foreach (KeyValuePair i in subsTokens) - { - request.ChannelId = i.Key; - request.PageToken = i.Value; - SearchListResponse response = await request.ExecuteAsync(); - foreach (SearchResult result in response.Items) - items.Add(result); - if (response.NextPageToken != null) - pairs.Add(i.Value, response.NextPageToken); - } - if (pairs.Count == 0) - subsMore.Complete(true); - else - subsTokens = pairs; - - items = items.OrderByDescending(x => x.Snippet.PublishedAt).ToList(); - - foreach (SearchResult i in items) - subsGrid.Add(new VideoCard(i.Id.VideoId)); - - subsMore.Complete(); - } - catch - { - subsMore.Complete(true); - } - } - public void Initialize() { if(SecretsVault.IsAuthorized) @@ -164,11 +91,11 @@ namespace FoxTube private void pivot_SelectionChanged(object sender, SelectionChangedEventArgs e) { loading.Close(); - if (pivot.SelectedItem == recommended && !recLoaded) + if (pivot.SelectedItem == recommended) LoadRecommendations(); else if (pivot.SelectedItem == trending && !trendLoaded) LoadTrending(); - else if (pivot.SelectedItem == subscriptions && !subsLoaded) + else if (pivot.SelectedItem == subscriptions) LoadSubscriptions(); } @@ -215,63 +142,31 @@ namespace FoxTube try { loading.Refresh(); - - throw new NotImplementedException(); - - loading.Close(); - recLoaded = true; + throw new NotImplementedException("This page has not implemented yet."); } catch (System.Net.Http.HttpRequestException) { - recLoaded = false; loading.Error("System.Net.Http.HttpRequestException", "Unable to connect to Google servers.", true); } catch (Exception e) { - recLoaded = false; loading.Error(e.GetType().ToString(), e.Message); } } - async void LoadSubscriptions() + void LoadSubscriptions() { try { loading.Refresh(); - List items = new List(); - SearchResource.ListRequest request = SecretsVault.Service.Search.List("snippet"); - request.Type = "video"; - request.MaxResults = 10; - request.Order = SearchResource.ListRequest.OrderEnum.Date; - - foreach (Subscription i in SecretsVault.Subscriptions) - { - request.ChannelId = i.Snippet.ResourceId.ChannelId; - SearchListResponse response = await request.ExecuteAsync(); - foreach (SearchResult result in response.Items) - items.Add(result); - if (response.NextPageToken != null) - subsTokens.Add(i.Snippet.ResourceId.ChannelId, response.NextPageToken); - } - if (subsTokens.Count == 0) - subsMore.Complete(true); - - items = items.OrderByDescending(x => x.Snippet.PublishedAt).ToList(); - - foreach (SearchResult i in items) - subsGrid.Add(new VideoCard(i.Id.VideoId)); - - loading.Close(); - subsLoaded = true; + throw new NotImplementedException("This page has not implemented yet."); } catch (System.Net.Http.HttpRequestException) { - subsLoaded = false; loading.Error("System.Net.Http.HttpRequestException", "Unable to connect to Google servers.", true); } catch (Exception e) { - subsLoaded = false; loading.Error(e.GetType().ToString(), e.Message); } } diff --git a/FoxTube/Pages/MainPage.xaml b/FoxTube/Pages/MainPage.xaml index 2ada653..f75b267 100644 --- a/FoxTube/Pages/MainPage.xaml +++ b/FoxTube/Pages/MainPage.xaml @@ -2,36 +2,15 @@ x:Class="FoxTube.MainPage" 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:ads="using:Microsoft.Advertising.WinRT.UI" - xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls" - xmlns:pages="using:FoxTube.Pages" xmlns:Windows10version1803="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractPresent(Windows.Foundation.UniversalApiContract, 6)" mc:Ignorable="d" SizeChanged="Page_SizeChanged" PreviewKeyUp="Page_PreviewKeyUp"> - - - - - - - - - - - - - - - - - - + @@ -45,72 +24,59 @@ - + - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - diff --git a/FoxTube/Pages/MainPage.xaml.cs b/FoxTube/Pages/MainPage.xaml.cs index 1d5961b..c326a6b 100644 --- a/FoxTube/Pages/MainPage.xaml.cs +++ b/FoxTube/Pages/MainPage.xaml.cs @@ -9,122 +9,61 @@ using Windows.UI.Xaml.Navigation; using System.Diagnostics; using Windows.UI.Notifications; using Windows.UI.Xaml.Media.Imaging; -using Windows.Storage; using System.Xml; using Google.Apis.YouTube.v3.Data; -using System.Globalization; using Windows.ApplicationModel.Core; using Windows.System; using Google.Apis.Oauth2.v2; using Google.Apis.Oauth2.v2.Data; -using FoxTube.Controls; using FoxTube.Pages; using Windows.ApplicationModel; using System.Net; using Windows.UI.Popups; using Windows.Networking.Connectivity; using Windows.UI.Core; -using Syroot.Windows.IO; - -// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409 +using System.Threading; +using System.Threading.Tasks; namespace FoxTube { - /// - /// An empty page that can be used on its own or navigated to within a Frame. - /// - public enum Sender { Menu, Frame, None } + /// + /// Main app's layout + /// public sealed partial class MainPage : Page - { - public DownloadAgent Agent = new DownloadAgent(); - - ApplicationDataContainer settings = ApplicationData.Current.LocalSettings; - - NotificationsCenter notificationsCenter = new NotificationsCenter(); + { Sender s = Sender.None; public MainPage() { - this.InitializeComponent(); - - if (settings.Values["quality"] == null) - settings.Values.Add("quality", "remember"); - if (settings.Values["rememberedQuality"] == null) - settings.Values.Add("rememberedQuality", "1080p"); - - if (settings.Values["newVideoNotification"] == null) - settings.Values.Add("newVideoNotification", true); - if (settings.Values["newmessagesNotification"] == null) - settings.Values.Add("newmessagesNotification", true); - - if (settings.Values["moblieWarning"] == null) - settings.Values.Add("moblieWarning", false); - if (settings.Values["videoAutoplay"] == null) - settings.Values.Add("videoAutoplay", true); - if (settings.Values["themeMode"] == null) - settings.Values.Add("themeMode", 2); - if (settings.Values["volume"] == null) - settings.Values.Add("volume", 100); - - if (settings.Values["region"] == null) - settings.Values.Add("region", CultureInfo.CurrentCulture.Name); - if (settings.Values["safeSearch"] == null) - settings.Values.Add("safeSearch", 0); - - if (settings.Values["defaultDownload"] == null) - settings.Values.Add("defaultDownload", Syroot.Windows.IO.KnownFolders.Downloads.Path + "\\DownloadedVideos"); - - if (settings.Values["notificationsHistory"] == null) - { - XmlDocument doc = new XmlDocument(); - doc.AppendChild(doc.CreateXmlDeclaration("1.0", "utf-8", null)); - doc.AppendChild(doc.CreateElement("history")); - settings.Values.Add("notificationsHistory", doc.InnerXml); - } + InitializeComponent(); + //Comparing current version with last recorded version. If doesn't match, poping up changelog notification PackageVersion ver = Package.Current.Id.Version; - if (settings.Values["ver"] == null) - settings.Values.Add("ver", $"{ver.Major}.{ver.Minor}"); - - if((string)settings.Values["ver"] != $"{ver.Major}.{ver.Minor}") + if(SettingsStorage.Version != $"{ver.Major}.{ver.Minor}") { try { XmlDocument changelog = new XmlDocument(); - changelog.Load("http://foxgame.hol.es/foxtube-changelog.xml"); + changelog.Load("http://foxgame-studio.000webhostapp.com/foxtube-changelog.xml"); XmlElement e = changelog["items"].ChildNodes[0] as XmlElement; - XmlDocument doc = new XmlDocument(); - doc.LoadXml(settings.Values["notificationsHistory"] as string); + ToastNotificationManager.CreateToastNotifier().Show(FoxTube.Background.Notification.GetChangelogToast(e.GetAttribute("version"))); - Background.Notification n = new Background.Notification("changelog", - $"changelog-{e.GetAttribute("version").Replace('.', '-')}", - "Changelog", - $"What's new in version {e.GetAttribute("version")}", - DateTime.Parse(e.GetAttribute("time")), - "http://foxgame.hol.es/FoxTubeAssets/WhatsNewThumb.png", - "http://foxgame.hol.es/FoxTubeAssets/NewsAvatar.png"); - - doc["history"].InnerXml += n.GetXml(); - settings.Values["notificationsHistory"] = doc.InnerXml; - - ToastNotificationManager.CreateToastNotifier().Show(n.GetToast()); - - settings.Values["ver"] = $"{ver.Major}.{ver.Minor}"; + SettingsStorage.Version = $"{ver.Major}.{ver.Minor}"; + } + catch + { + Debug.WriteLine("Unable to retrieve changelog"); } - catch { } } - notificationsCenter.Initialize(); - SecretsVault.AuthorizationStateChanged += Vault_AuthorizationStateChanged; + SecretsVault.AuthorizationStateChanged += AuthorizationStateChanged; SecretsVault.SubscriptionsChanged += SecretsVault_SubscriptionsChanged; - SetTitleBar(); - } + SecretsVault.NotPurchased += () => removeAds.Visibility = Visibility.Visible; + SecretsVault.CheckAuthorization(); + SecretsVault.CheckAddons(); - protected override void OnNavigatedTo(NavigationEventArgs e) - { - base.OnNavigatedTo(e); SetTitleBar(); } @@ -137,66 +76,88 @@ namespace FoxTube public void SetTitleBar() { var titleBar = ApplicationView.GetForCurrentView().TitleBar; - - titleBar.ButtonBackgroundColor = Colors.Transparent; + + titleBar.BackgroundColor = Colors.Red; + titleBar.ButtonBackgroundColor = Colors.Red; titleBar.ButtonHoverBackgroundColor = Colors.IndianRed; titleBar.ButtonPressedBackgroundColor = Colors.DarkRed; - titleBar.ButtonInactiveBackgroundColor = Colors.Transparent; + titleBar.ButtonInactiveBackgroundColor = Colors.Black; + titleBar.ForegroundColor = Colors.White; - if((int)settings.Values["themeMode"] == 2) - { - Color uiTheme = new UISettings().GetColorValue(UIColorType.Background); - if (uiTheme == Colors.Black) - titleBar.ButtonForegroundColor = Colors.White; - else - titleBar.ButtonForegroundColor = Colors.Black; - } - else - { - if (RequestedTheme == ElementTheme.Dark) - titleBar.ButtonForegroundColor = Colors.White; - else if (RequestedTheme == ElementTheme.Light) - titleBar.ButtonForegroundColor = Colors.Black; - } - - CoreApplicationViewTitleBar coreTitleBar = CoreApplication.GetCurrentView().TitleBar; - coreTitleBar.ExtendViewIntoTitleBar = true; + CoreApplication.GetCurrentView().TitleBar.ExtendViewIntoTitleBar = false; } + /// + /// Invoked when subscriptions are edited to edit menu + /// + /// + /// private void SecretsVault_SubscriptionsChanged(object sender, params object[] args) { if ((string)args[0] == "add" && nav.MenuItems.Count < 19) { + subsHeader.Visibility = Visibility.Visible; + Subscription s = args[1] as Subscription; - StackPanel panel = new StackPanel() { Orientation = Orientation.Horizontal }; + StackPanel panel = new StackPanel() + { + Orientation = Orientation.Horizontal, + Padding = new Thickness(5) + }; panel.Children.Add(new PersonPicture() { Height = 20, - Margin = new Thickness(0, 0, 13, 0), + Margin = new Thickness(-5, 0, 15, 0), ProfilePicture = new BitmapImage(new Uri(s.Snippet.Thumbnails.Medium.Url)) }); panel.Children.Add(new TextBlock() { Text = s.Snippet.Title }); nav.MenuItems.Add(new NavigationViewItem() { Content = panel, - Name = (nav.MenuItems.Count - 9).ToString() + Name = (nav.MenuItems.Count - 9).ToString(), + Padding = new Thickness(-5) }); } else if ((string)args[0] == "remove" && (int)args[1] < 10) + { nav.MenuItems.RemoveAt((int)args[1] + 9); + if(SecretsVault.Subscriptions.Count >= 10) + { + Subscription s = SecretsVault.Subscriptions[9]; + StackPanel panel = new StackPanel() + { + Orientation = Orientation.Horizontal, + Padding = new Thickness(5) + }; + panel.Children.Add(new PersonPicture() + { + Height = 20, + Margin = new Thickness(-5, 0, 15, 0), + ProfilePicture = new BitmapImage(new Uri(s.Snippet.Thumbnails.Medium.Url)) + }); + panel.Children.Add(new TextBlock() { Text = s.Snippet.Title }); + nav.MenuItems.Add(new NavigationViewItem() + { + Content = panel, + Name = (nav.MenuItems.Count - 9).ToString(), + Padding = new Thickness(-5) + }); + } + } } - private async void Vault_AuthorizationStateChanged(object sender, EventArgs e) + + private async void AuthorizationStateChanged(object sender, params object[] e) { - if(SecretsVault.IsAuthorized) + if(e[0] as bool? == true) { account.Visibility = Visibility.Collapsed; try { Userinfoplus info = await new Oauth2Service(SecretsVault.Initializer).Userinfo.Get().ExecuteAsync(); - ToolTipService.SetToolTip(avatar, new ToolTip() { Content = info.Name }); - (avatar.Content as PersonPicture).ProfilePicture = new BitmapImage(new Uri(info.Picture)); + myName.Text = info.Name; + ((avatar.Content as StackPanel).Children[0] as PersonPicture).ProfilePicture = new BitmapImage(new Uri(info.Picture)); } catch { } avatar.Visibility = Visibility.Visible; @@ -207,8 +168,6 @@ namespace FoxTube toHistory.Visibility = Visibility.Visible; toLiked.Visibility = Visibility.Visible; toLater.Visibility = Visibility.Visible; - toDownloads.Visibility = Visibility.Visible; - subsHeader.Visibility = Visibility.Visible; if (SecretsVault.Subscriptions.Count > 0) { @@ -217,24 +176,29 @@ namespace FoxTube try { Subscription s = SecretsVault.Subscriptions[k]; - StackPanel panel = new StackPanel() { Orientation = Orientation.Horizontal }; + StackPanel panel = new StackPanel() + { + Orientation = Orientation.Horizontal, + Padding = new Thickness(5) + }; panel.Children.Add(new PersonPicture() { Height = 20, - Margin = new Thickness(0, 0, 13, 0), + Margin = new Thickness(-5, 0, 15, 0), ProfilePicture = new BitmapImage(new Uri(s.Snippet.Thumbnails.Medium.Url)) }); panel.Children.Add(new TextBlock() { Text = s.Snippet.Title }); nav.MenuItems.Add(new NavigationViewItem() { Content = panel, - Name = k.ToString() + Name = k.ToString(), + Padding = new Thickness(-5) }); } catch { continue; } } } - else + else if (e[0] as bool? == false) { account.Visibility = Visibility.Visible; avatar.Visibility = Visibility.Collapsed; @@ -245,32 +209,41 @@ namespace FoxTube toHistory.Visibility = Visibility.Collapsed; toLiked.Visibility = Visibility.Collapsed; toLater.Visibility = Visibility.Collapsed; - toDownloads.Visibility = Visibility.Collapsed; subsHeader.Visibility = Visibility.Collapsed; subsHeader.Visibility = Visibility.Collapsed; for(int k = 9; k < nav.MenuItems.Count; k++) nav.MenuItems.RemoveAt(k); } + else + { + MessageDialog dialog = new MessageDialog("We were unabled to retrieve your account information due to weak internet connection or Google servers' problems. PLease, try again later", "Failed to connect"); + + dialog.Commands.Add(new UICommand("Try again", (command) => + { + SecretsVault.Authorize(); + })); + dialog.Commands.Add(new UICommand("Quit", (command) => + { + Methods.CloseApp(); + })); + + dialog.CancelCommandIndex = 1; + dialog.DefaultCommandIndex = 0; + + await dialog.ShowAsync(); + } + + if(e[0] as bool? != null) + DownloadAgent.Initialize(); - nav.SelectedItem = toHome; content.Navigate(typeof(Home)); if (videoPlaceholder.Content != null) GoToVideo((videoPlaceholder.Content as VideoPage).videoId); } - public void GotNotification() - { - notificationMenu.Content = "\xED0C"; - } - - public void notificationMenu_Click(object sender, RoutedEventArgs e) - { - notificationMenu.Content = "\xED0D"; - } - - private async void feedback_Click(object sender, RoutedEventArgs e) + private async void feedback_Click(object sender, TappedRoutedEventArgs e) { await Launcher.LaunchUriAsync(new Uri("feedback-hub:")); } @@ -287,7 +260,7 @@ namespace FoxTube private void myChannel_Click(object sender, RoutedEventArgs e) { - content.Navigate(typeof(Channel), SecretsVault.UserChannel.Id); + GoToChannel(SecretsVault.AccountId); } private void logout_Click(object sender, RoutedEventArgs e) @@ -298,26 +271,27 @@ namespace FoxTube public void GoToSearch(SearchParameters args) { nav.IsPaneOpen = false; - MinimizeAsInitializer(); content.Navigate(typeof(Search), args); } public void GoToChannel(string id) { - Debug.WriteLine($"Channel id: {id}"); - MinimizeAsInitializer(); content.Navigate(typeof(ChannelPage), id); } + public void GoToHome() + { + content.Navigate(typeof(Home)); + } + public async void GoToVideo(string id, string playlistId = null) { - Debug.WriteLine($"Video id: {id}; Playlist id: {playlistId}"); + bool cancel = false; try { var connection = NetworkInformation.GetInternetConnectionProfile().GetConnectionCost(); - if ((bool)settings.Values["moblieWarning"] && (connection.NetworkCostType == NetworkCostType.Fixed || connection.NetworkCostType == NetworkCostType.Variable)) + if (SettingsStorage.CheckConnection && (connection.NetworkCostType == NetworkCostType.Fixed || connection.NetworkCostType == NetworkCostType.Variable)) { - bool cancel = false; MessageDialog dialog = new MessageDialog("You are on metered connection now. Additional charges may apply. Do you want to continue?") { DefaultCommandIndex = 2, @@ -325,41 +299,62 @@ namespace FoxTube }; dialog.Commands.Add(new UICommand("Yes")); dialog.Commands.Add(new UICommand("No", (command) => cancel = true)); - dialog.Commands.Add(new UICommand("Add to 'Watch later' playlist", (command) => - { - //TO-DO: Adding video to "Watch later" - cancel = true; - })); - await dialog.ShowAsync(); + if(SecretsVault.IsAuthorized) + dialog.Commands.Add(new UICommand("Add to 'Watch later' playlist", (command) => + { + try + { + PlaylistItem item = new PlaylistItem() + { + Snippet = new PlaylistItemSnippet() + { + ResourceId = new ResourceId() + { + Kind = "youtube#video", + VideoId = id + }, + PlaylistId = "WL" + } + }; - if (cancel) - return; + SecretsVault.Service.PlaylistItems.Insert(item, "snippet").Execute(); + } + catch (Exception e) + { + Debug.WriteLine(e.Message); + } + cancel = true; + })); + + await dialog.ShowAsync(); } } catch { } - - nav.IsPaneOpen = false; - + if (cancel) + return; + videoPlaceholder.Content = null; - MaximizeVideo(); Fullscreen(false); videoPlaceholder.Navigate(typeof(VideoPage), new string[2] { id, playlistId }); + MaximizeVideo(); } public void GoToDeveloper(string id) { - MinimizeAsInitializer(); content.Navigate(typeof(Settings), $"inbox&{id}"); } public void GoToPlaylist(string id) { - Debug.WriteLine($"Playlist id: {id}"); - MinimizeAsInitializer(); content.Navigate(typeof(PlaylistPage), id); } + public void GoToDownloads() + { + content.Navigate(typeof(Downloads)); + } + private void Page_SizeChanged(object sender, SizeChangedEventArgs e) { if (videoPlaceholder.Content != null) @@ -392,6 +387,30 @@ namespace FoxTube nav.IsBackEnabled = true; else nav.IsBackEnabled = false; + + Dictionary switchCase = new Dictionary() + { + { typeof(Settings), () => nav.Header = "Settings" }, + { typeof(ChannelPage), () => nav.Header = "Channel" }, + { typeof(PlaylistPage), () => nav.Header = "Playlist" }, + { typeof(Search), () => nav.Header = "Search" }, + { typeof(Subscriptions), () => nav.Header = "Subscriptions" }, + { typeof(History), () => nav.Header = "History" }, + { typeof(Home), () => nav.Header = "Home" }, + { typeof(Downloads), () => nav.Header = "Downloads" } + }; + + if (content.SourcePageType == typeof(Home) || content.SourcePageType == typeof(Settings) || content.SourcePageType == typeof(Subscriptions)) + { + nav.ExpandedModeThresholdWidth = 1008; + if (nav.DisplayMode == NavigationViewDisplayMode.Expanded) + nav.IsPaneOpen = true; + } + else + nav.ExpandedModeThresholdWidth = short.MaxValue; + + try { switchCase[content.SourcePageType](); } + catch { } } public void MaximizeVideo() @@ -403,24 +422,38 @@ namespace FoxTube videoPlaceholder.Margin = new Thickness(0); nav.IsBackEnabled = true; + + if (videoPlaceholder.Content != null) + { + nav.Header = "Video"; + nav.ExpandedModeThresholdWidth = short.MaxValue; + nav.IsPaneOpen = false; + } } public void Fullscreen(bool on) { if (on) { + nav.CompactModeThresholdWidth = short.MaxValue; + nav.ExpandedModeThresholdWidth = short.MaxValue; nav.OpenPaneLength = 0; nav.CompactPaneLength = 0; - if ((videoPlaceholder.Content as VideoPage).player.MiniView) - nav.Margin = new Thickness(0, -80, 0, 0); - else - nav.Margin = new Thickness(0, -91, 0, 0); + nav.Margin = new Thickness(0, -45, 0, 0); } else { + nav.CompactModeThresholdWidth = 641; + nav.ExpandedModeThresholdWidth = 1008; nav.Margin = new Thickness(0); - nav.OpenPaneLength = 300; - nav.CompactPaneLength = 48; + if (videoPlaceholder.Content != null && nav.IsPaneOpen) + nav.IsPaneOpen = false; + else + { + nav.OpenPaneLength = 300; + nav.CompactPaneLength = 40; + } + SetTitleBar(); } } @@ -473,47 +506,52 @@ namespace FoxTube private void nav_SelectionChanged(NavigationView sender, NavigationViewSelectionChangedEventArgs args) { - if (s == Sender.None) + Debug.WriteLine("Menu selection changed"); + try { - s = Sender.Menu; - if (args.IsSettingsSelected) - content.Navigate(typeof(Settings)); - else + if (s == Sender.None) { - if (args.SelectedItem == toHome) - content.Navigate(typeof(Home)); - else if (args.SelectedItem == toHistory) - content.Navigate(typeof(History)); - else if (args.SelectedItem == toLiked) - content.Navigate(typeof(PlaylistPage), SecretsVault.UserChannel.ContentDetails.RelatedPlaylists.Likes); - else if (args.SelectedItem == toLater) - content.Navigate(typeof(PlaylistPage), SecretsVault.UserChannel.ContentDetails.RelatedPlaylists.WatchLater); - else if (args.SelectedItem == toSubscriptions) - content.Navigate(typeof(Subscriptions)); - else if (args.SelectedItem == toDownloads) - content.Navigate(typeof(Downloads)); - else if (args.SelectedItem == toChannel) - content.Navigate(typeof(ChannelPage), SecretsVault.UserChannel.Id); + s = Sender.Menu; + if (args.IsSettingsSelected) + content.Navigate(typeof(Settings)); else - content.Navigate(typeof(ChannelPage), SecretsVault.Subscriptions[Convert.ToInt32((args.SelectedItem as NavigationViewItem).Name)].Snippet.ResourceId.ChannelId); + { + if (args.SelectedItem == toHome) + content.Navigate(typeof(Home)); + else if (args.SelectedItem == toHistory) + content.Navigate(typeof(History)); + else if (args.SelectedItem == toLiked) + content.Navigate(typeof(PlaylistPage), SecretsVault.UserChannel.ContentDetails.RelatedPlaylists.Likes); + else if (args.SelectedItem == toLater) + content.Navigate(typeof(PlaylistPage), SecretsVault.UserChannel.ContentDetails.RelatedPlaylists.WatchLater); + else if (args.SelectedItem == toSubscriptions) + content.Navigate(typeof(Subscriptions)); + else if (args.SelectedItem == toDownloads) + content.Navigate(typeof(Downloads)); + else if (args.SelectedItem == toChannel) + content.Navigate(typeof(ChannelPage), SecretsVault.UserChannel.Id); + else + content.Navigate(typeof(ChannelPage), SecretsVault.Subscriptions[Convert.ToInt32((args.SelectedItem as NavigationViewItem).Name)].Snippet.ResourceId.ChannelId); + } } + else + s = Sender.None; } - else - s = Sender.None; + catch { } } public void content_Navigated(object sender, NavigationEventArgs e) { Dictionary switchCase = new Dictionary() { - { typeof(Settings), () => header.Text = "Settings" }, - { typeof(ChannelPage), () => header.Text = "Channel" }, - { typeof(PlaylistPage), () => header.Text = "Playlist" }, - { typeof(Search), () => header.Text = "Search" }, - { typeof(Subscriptions), () => header.Text = "Subscriptions" }, - { typeof(History), () => header.Text = "History" }, - { typeof(Home), () => header.Text = "Home" }, - { typeof(Downloads), () => header.Text = "Downloads" } + { typeof(Settings), () => nav.Header = "Settings" }, + { typeof(ChannelPage), () => nav.Header = "Channel" }, + { typeof(PlaylistPage), () => nav.Header = "Playlist" }, + { typeof(Search), () => nav.Header = "Search" }, + { typeof(Subscriptions), () => nav.Header = "Subscriptions" }, + { typeof(History), () => nav.Header = "History" }, + { typeof(Home), () => nav.Header = "Home" }, + { typeof(Downloads), () => nav.Header = "Downloads" } }; try { switchCase[e.SourcePageType](); } @@ -654,17 +692,12 @@ namespace FoxTube nav.IsPaneOpen = true; } else - nav.ExpandedModeThresholdWidth = int.MaxValue; + nav.ExpandedModeThresholdWidth = short.MaxValue; if (videoPlaceholder.Content != null && videoPlaceholder.HorizontalAlignment == HorizontalAlignment.Stretch) MinimizeAsInitializer(); } - private void toChannel_Click(object sender, RoutedEventArgs e) - { - GoToChannel(SecretsVault.UserChannel.Id); - } - private void nav_BackRequested(NavigationView sender, NavigationViewBackRequestedEventArgs args) { if (videoPlaceholder.Content != null) @@ -673,8 +706,6 @@ namespace FoxTube CloseVideo(); else if (videoPlaceholder.HorizontalAlignment == HorizontalAlignment.Stretch) MinimizeAsInitializer(); - else - content.GoBack(); } else content.GoBack(); @@ -688,5 +719,10 @@ namespace FoxTube (videoPlaceholder.Content as VideoPage).player.KeyUpPressed(sender, e); } } + + private void openContext(object sender, TappedRoutedEventArgs e) + { + ((NavigationViewItem)sender).ContextFlyout.ShowAt((NavigationViewItem)sender); + } } } diff --git a/FoxTube/Pages/PlaylistPage.xaml.cs b/FoxTube/Pages/PlaylistPage.xaml.cs index 3b815e1..a385327 100644 --- a/FoxTube/Pages/PlaylistPage.xaml.cs +++ b/FoxTube/Pages/PlaylistPage.xaml.cs @@ -2,32 +2,18 @@ using Google.Apis.YouTube.v3; using Google.Apis.YouTube.v3.Data; using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Runtime.InteropServices.WindowsRuntime; -using Windows.ApplicationModel; using Windows.ApplicationModel.DataTransfer; using Windows.Foundation; -using Windows.Foundation.Collections; -using Windows.Storage; -using Windows.Storage.Streams; using Windows.System; 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.Media.Imaging; using Windows.UI.Xaml.Navigation; -// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238 - namespace FoxTube.Pages { /// - /// An empty page that can be used on its own or navigated to within a Frame. + /// Playlist page /// public sealed partial class PlaylistPage : Page { @@ -39,7 +25,7 @@ namespace FoxTube.Pages public PlaylistPage() { - this.InitializeComponent(); + InitializeComponent(); loading = grid.Children[2] as LoadingPage; list = ((grid.Children[0] as ScrollViewer).Content as Grid).Children[1] as VideoGrid; loading.RefreshPage += refresh_Click; @@ -129,7 +115,7 @@ namespace FoxTube.Pages private void refresh_Click(object sender, RoutedEventArgs e) { - Initialize(playlistId); + Methods.MainPage.GoToPlaylist(playlistId); } private void share_Click(object sender, RoutedEventArgs e) @@ -137,42 +123,13 @@ namespace FoxTube.Pages DataTransferManager.ShowShareUI(); } - private async void Share(DataTransferManager sender, DataRequestedEventArgs args) + private void Share(DataTransferManager sender, DataRequestedEventArgs args) { - DataRequest request = args.Request; - request.Data.Properties.Title = item.Snippet.Title; - request.Data.Properties.Description = "Sharing a playlist"; - - // Handle errors - //request.FailWithDisplayText("Something unexpected could happen."); - - // Plain text - request.Data.SetText(item.Snippet.Title + "\n" + "#YouTube #FoxTube #SharedWithFoxTube"); - - // Uniform Resource Identifiers (URIs) - request.Data.SetWebLink(new Uri($"https://www.youtube.com/playlist?list={item.Id}")); - - // HTML - //request.Data.SetHtmlFormat("Bold Text"); - - // Because we are making async calls in the DataRequested event handler, - // we need to get the deferral first. - DataRequestDeferral deferral = request.GetDeferral(); - - // Make sure we always call Complete on the deferral. - try - { - StorageFile thumbnailFile = await Package.Current.InstalledLocation.GetFileAsync(item.Snippet.Thumbnails.Medium.Url); - request.Data.Properties.Thumbnail = RandomAccessStreamReference.CreateFromFile(thumbnailFile); - StorageFile imageFile = await Package.Current.InstalledLocation.GetFileAsync(item.Snippet.Thumbnails.Medium.Url); - - // Bitmaps - request.Data.SetBitmap(RandomAccessStreamReference.CreateFromFile(imageFile)); - } - finally - { - deferral.Complete(); - } + Methods.Share(args, + item.Snippet.Thumbnails.Medium.Url, + item.Snippet.Title, + $"https://www.youtube.com/playlist?list={item.Id}", + "playlist"); } } } diff --git a/FoxTube/Pages/Search.xaml.cs b/FoxTube/Pages/Search.xaml.cs index 0fe757c..32842b2 100644 --- a/FoxTube/Pages/Search.xaml.cs +++ b/FoxTube/Pages/Search.xaml.cs @@ -3,29 +3,17 @@ using FoxTube.Pages; using Google.Apis.YouTube.v3; using Google.Apis.YouTube.v3.Data; using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Runtime.InteropServices.WindowsRuntime; -using Windows.Foundation; -using Windows.Foundation.Collections; using Windows.Storage; 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; using Windows.System; - -// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238 +using System.Globalization; namespace FoxTube { /// - /// An empty page that can be used on its own or navigated to within a Frame. + /// Search page /// public sealed partial class Search : Page { @@ -40,7 +28,7 @@ namespace FoxTube public Search() { - this.InitializeComponent(); + InitializeComponent(); loading = grid.Children[2] as LoadingPage; list = ((grid.Children[0] as ScrollViewer).Content as StackPanel).Children[4] as VideoGrid; more = ((grid.Children[0] as ScrollViewer).Content as StackPanel).Children[5] as ShowMore; @@ -108,14 +96,10 @@ namespace FoxTube } request.Q = arg.Term; request.SafeSearch = (SearchResource.ListRequest.SafeSearchEnum)(int)settings.Values["safeSearch"]; - try - { - request.RelevanceLanguage = settings.Values["region"].ToString().Remove(2).ToLower(); - } - catch (ArgumentOutOfRangeException) - { - request.RelevanceLanguage = settings.Values["region"].ToString().ToLower(); - } + + request.RegionCode = CultureInfo.GetCultures(CultureTypes.AllCultures).Find(i => i.IetfLanguageTag == SettingsStorage.Region).IetfLanguageTag.Remove(0, 3); + request.RelevanceLanguage = CultureInfo.GetCultures(CultureTypes.AllCultures).Find(i => i.IetfLanguageTag == SettingsStorage.Region).TwoLetterISOLanguageName; + request.MaxResults = 48; try { @@ -185,7 +169,7 @@ namespace FoxTube private void AppBarButton_Click(object sender, RoutedEventArgs e) { - Initialize(Parameters); + Methods.MainPage.GoToSearch(Parameters); } private async void more_Clicked() diff --git a/FoxTube/Pages/Settings.xaml.cs b/FoxTube/Pages/Settings.xaml.cs index 613ef5b..16cc505 100644 --- a/FoxTube/Pages/Settings.xaml.cs +++ b/FoxTube/Pages/Settings.xaml.cs @@ -28,6 +28,7 @@ namespace FoxTube public sealed partial class Settings : Page { bool inboxLoaded = false; + string inboxId = null; public Settings() { this.InitializeComponent(); @@ -38,21 +39,21 @@ namespace FoxTube base.OnNavigatedTo(e); if(!string.IsNullOrWhiteSpace(e.Parameter as string)) { - if ((e.Parameter as string).Contains("inbox")) + if ((e.Parameter as string).Contains("inbox") || (e.Parameter as string).Contains("changelog")) { - pivot.SelectedIndex = 3; - if ((string)e.Parameter != "inbox") - ((pivot.SelectedItem as PivotItem).Content as Inbox).Open((e.Parameter as string).Split('&')[1]); + if ((string)e.Parameter != "inbox" && (string)e.Parameter != "changelog") + inboxId = e.Parameter as string; + pivot.SelectedIndex = 2; } else switch(e.Parameter as string) { case "about": - pivot.SelectedIndex = 2; + pivot.SelectedIndex = 1; break; - case "translate": + /*case "translate": pivot.SelectedIndex = 3; - break; + break;*/ } } } @@ -63,6 +64,11 @@ namespace FoxTube { (((pivot.Items[2] as PivotItem).Content as ScrollViewer).Content as Inbox).LoadItems(); inboxLoaded = true; + if(inboxId != null) + { + (((pivot.Items[2] as PivotItem).Content as ScrollViewer).Content as Inbox).Open(inboxId as string); + inboxId = null; + } } } } diff --git a/FoxTube/Pages/SettingsPages/General.xaml b/FoxTube/Pages/SettingsPages/General.xaml index cbdfac1..1f9d57f 100644 --- a/FoxTube/Pages/SettingsPages/General.xaml +++ b/FoxTube/Pages/SettingsPages/General.xaml @@ -42,6 +42,7 @@ + diff --git a/FoxTube/Pages/SettingsPages/General.xaml.cs b/FoxTube/Pages/SettingsPages/General.xaml.cs index fb0f11f..801adcc 100644 --- a/FoxTube/Pages/SettingsPages/General.xaml.cs +++ b/FoxTube/Pages/SettingsPages/General.xaml.cs @@ -1,48 +1,42 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Globalization; -using System.IO; +using System.Globalization; using System.Linq; -using System.Runtime.InteropServices.WindowsRuntime; using Windows.ApplicationModel.Core; -using Windows.Foundation; -using Windows.Foundation.Collections; -using Windows.Storage; using Windows.UI; 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 Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238 namespace FoxTube.Pages.SettingsPages { /// - /// An empty page that can be used on its own or navigated to within a Frame. + /// Settings page with general preferences /// public sealed partial class General : Page { - ApplicationDataContainer settings = ApplicationData.Current.LocalSettings; public General() { - this.InitializeComponent(); + InitializeComponent(); - language.SelectedIndex = (string)settings.Values["language"] == "en-US"? 0 : 1; - quality.SelectedIndex = (int)settings.Values["quality"]; + language.SelectedItem = language.Items.Find(i => ((ComboBoxItem)i).Tag.ToString() == SettingsStorage.Language); + CultureInfo.GetCultures(CultureTypes.AllCultures).FindAll(i => !i.IsNeutralCulture).ForEach(i => + { + region.Items.Add(new ComboBoxItem + { + Content = i.DisplayName, + Tag = i.IetfLanguageTag + }); + if (i.IetfLanguageTag == SettingsStorage.Region) + region.SelectedItem = region.Items.Last(); + }); + safeSearch.SelectedIndex = SettingsStorage.SafeSearch; - newVideo.IsOn = (bool)settings.Values["newVideoNotification"]; + quality.SelectedItem = quality.Items.ToList().Find(i => ((ComboBoxItem)i).Tag.ToString() == SettingsStorage.VideoQuality); + mobileWarning.IsOn = SettingsStorage.CheckConnection; + autoplay.IsOn = SettingsStorage.Autoplay; - mobileWarning.IsOn = (bool)settings.Values["moblieWarning"]; - autoplay.IsOn = (bool)settings.Values["videoAutoplay"]; + newVideo.IsOn = SettingsStorage.VideoNotifications; + devNews.IsOn = SettingsStorage.DevNotifications; - safeSearch.SelectedIndex = (int)settings.Values["safeSearch"]; - - switch((int)settings.Values["themeMode"]) + switch(SettingsStorage.Theme) { case 0: light.IsChecked = true; @@ -54,79 +48,68 @@ namespace FoxTube.Pages.SettingsPages system.IsChecked = true; break; } - - foreach (CultureInfo culture in CultureInfo.GetCultures(CultureTypes.AllCultures)) - { - region.Items.Add(culture.DisplayName); - if (culture.Name == (string)settings.Values["region"]) - region.SelectedIndex = region.Items.Count - 1; - } } private void language_SelectionChanged(object sender, SelectionChangedEventArgs e) { - if ((string)settings.Values["language"] != (language.SelectedItem as ComboBoxItem).Tag.ToString()) - { - settings.Values["language"] = (language.SelectedItem as ComboBoxItem).Tag.ToString(); - restartNote.Visibility = Visibility.Visible; - } - else - restartNote.Visibility = Visibility.Collapsed; + if (SettingsStorage.Language == (language.SelectedItem as ComboBoxItem).Tag.ToString()) + return; + + SettingsStorage.Language = (language.SelectedItem as ComboBoxItem).Tag.ToString(); + restartNote.Visibility = Visibility.Visible; } private void quality_SelectionChanged(object sender, SelectionChangedEventArgs e) { - settings.Values["quality"] = (quality.SelectedItem as ComboBoxItem).Tag as string; + SettingsStorage.VideoQuality = (quality.SelectedItem as ComboBoxItem).Tag as string; } private void mobileWarning_Toggled(object sender, RoutedEventArgs e) { - settings.Values["moblieWarning"] = mobileWarning.IsOn; + SettingsStorage.CheckConnection = mobileWarning.IsOn; } private void autoplay_Toggled(object sender, RoutedEventArgs e) { - - settings.Values["videoAutoplay"] = autoplay.IsOn; + SettingsStorage.Autoplay = autoplay.IsOn; } private void notification_IsEnabledChanged(object sender, RoutedEventArgs e) { - settings.Values["newVideoNotification"] = newVideo.IsOn; + SettingsStorage.VideoNotifications = newVideo.IsOn; } private void region_SelectionChanged(object sender, SelectionChangedEventArgs e) { - settings.Values["region"] = CultureInfo.GetCultures(CultureTypes.AllCultures)[region.SelectedIndex].Name; + SettingsStorage.Region = CultureInfo.GetCultures(CultureTypes.AllCultures)[region.SelectedIndex].Name; } private void safeSearch_SelectionChanged(object sender, SelectionChangedEventArgs e) { - settings.Values["safeSearch"] = safeSearch.SelectedIndex; + SettingsStorage.SafeSearch = safeSearch.SelectedIndex; } private void RadioButton_Checked(object sender, RoutedEventArgs e) { - if (sender == light && (int)settings.Values["themeMode"] != 0) + if (sender == light && SettingsStorage.Theme != 0) { - settings.Values["themeMode"] = 0; + SettingsStorage.Theme = 0; Methods.MainPage.RequestedTheme = ElementTheme.Light; } - if (sender == dark && (int)settings.Values["themeMode"] != 1) + else if (sender == dark && SettingsStorage.Theme != 1) { - settings.Values["themeMode"] = 1; + SettingsStorage.Theme = 1; Methods.MainPage.RequestedTheme = ElementTheme.Dark; } - if (sender == system && (int)settings.Values["themeMode"] != 2) + else if (sender == system && SettingsStorage.Theme != 2) { - settings.Values["themeMode"] = 2; - Color uiTheme = (new Windows.UI.ViewManagement.UISettings()).GetColorValue(Windows.UI.ViewManagement.UIColorType.Background); + SettingsStorage.Theme = 2; + Color uiTheme = new Windows.UI.ViewManagement.UISettings().GetColorValue(Windows.UI.ViewManagement.UIColorType.Background); if (uiTheme == Colors.Black) Methods.MainPage.RequestedTheme = ElementTheme.Dark; else Methods.MainPage.RequestedTheme = ElementTheme.Light; } - Methods.MainPage.SetTitleBar(); } @@ -134,5 +117,10 @@ namespace FoxTube.Pages.SettingsPages { CoreApplication.Exit(); } + + private void devNews_Toggled(object sender, RoutedEventArgs e) + { + SettingsStorage.DevNotifications = devNews.IsOn; + } } } diff --git a/FoxTube/Pages/SettingsPages/Inbox.xaml.cs b/FoxTube/Pages/SettingsPages/Inbox.xaml.cs index a408174..b4eb1a0 100644 --- a/FoxTube/Pages/SettingsPages/Inbox.xaml.cs +++ b/FoxTube/Pages/SettingsPages/Inbox.xaml.cs @@ -27,7 +27,6 @@ namespace FoxTube.Pages.SettingsPages /// public sealed partial class Inbox : Page { - List backup = new List(); List items = new List(); public Inbox() { @@ -40,62 +39,51 @@ namespace FoxTube.Pages.SettingsPages { XmlDocument doc = new XmlDocument(); - doc.Load("http://foxgame.hol.es/foxtube-changelog.xml"); + doc.Load("http://foxgame-studio.000webhostapp.com/foxtube-changelog.xml"); foreach (XmlElement e in doc["items"].ChildNodes) items.Add(new InboxItem( e.GetAttribute("version"), e["content"].InnerText, - e.GetAttribute("time"), - e.GetAttribute("id") - )); + e.GetAttribute("time"))); - doc.Load("http://foxgame.hol.es/foxtube-messages.xml"); + doc.Load("http://foxgame-studio.000webhostapp.com/foxtube-messages.xml"); foreach (XmlElement e in doc["posts"].ChildNodes) items.Add(new InboxItem( e["header"].InnerText, e["content"].InnerText, - DateTime.Parse(e.GetAttribute("time")), - e.GetAttribute("id") + DateTime.Parse(e["time"].InnerText), + e["id"].InnerText )); items.OrderBy(item => item.TimeStamp); - - foreach (InboxItem i in items) - backup.Add(i); } catch { } - list.ItemsSource = items; + items.ForEach(i => list.Items.Add(i)); } private void filter_SelectionChanged(object sender, SelectionChangedEventArgs e) { try { - items.Clear(); - list.ItemsSource = null; + list.Items.Clear(); switch (filter.SelectedIndex) { case 0: - foreach (InboxItem i in backup) - items.Add(i); + items.ForEach(i => list.Items.Add(i)); break; case 1: - foreach (InboxItem i in backup) - if(i.Type == InboxItemType.Default) - items.Add(i); + List messages = items.FindAll(i => i.Type == InboxItemType.Default); + messages.ForEach(i => list.Items.Add(i)); break; case 2: - foreach (InboxItem i in backup) - if (i.Type == InboxItemType.PatchNote) - items.Add(i); + List notes = items.FindAll(i => i.Type == InboxItemType.PatchNote); + notes.ForEach(i => list.Items.Add(i)); break; } - - list.ItemsSource = items; } catch(NullReferenceException) { } } @@ -141,11 +129,12 @@ namespace FoxTube.Pages.SettingsPages } } - public void Open(string id) + public void Open(string arg) { + string id = arg.Split('&')[1]; InboxItem item = items.Find(x => x.Id == id); if(item != null) - list.SelectedIndex = items.IndexOf(item); + list.SelectedItem = item; } } } diff --git a/FoxTube/Pages/SettingsPages/Translate.xaml b/FoxTube/Pages/SettingsPages/Translate.xaml deleted file mode 100644 index 89796d6..0000000 --- a/FoxTube/Pages/SettingsPages/Translate.xaml +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - - - - - - - - - @@ -106,7 +113,47 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -116,7 +163,10 @@ - + + + + diff --git a/FoxTube/Pages/VideoPage.xaml.cs b/FoxTube/Pages/VideoPage.xaml.cs index 8a632f2..36f4765 100644 --- a/FoxTube/Pages/VideoPage.xaml.cs +++ b/FoxTube/Pages/VideoPage.xaml.cs @@ -13,12 +13,10 @@ using Windows.UI.Xaml.Media.Imaging; using System.Diagnostics; using Windows.ApplicationModel.DataTransfer; using Windows.Storage; -using Windows.ApplicationModel; -using Windows.Storage.Streams; using Windows.UI; using FoxTube.Controls; - -// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238 +using YoutubeExplode.Models.MediaStreams; +using YoutubeExplode; namespace FoxTube.Pages { @@ -40,7 +38,7 @@ namespace FoxTube.Pages } /// - /// An empty page that can be used on its own or navigated to within a Frame. + /// Video page /// public sealed partial class VideoPage : Page { @@ -61,7 +59,7 @@ namespace FoxTube.Pages public VideoPage() { - this.InitializeComponent(); + InitializeComponent(); loading = grid.Children[3] as LoadingPage; loading.RefreshPage += refresh_Click; player = mainContent.Children[0] as VideoPlayer; @@ -173,7 +171,7 @@ namespace FoxTube.Pages license.Text = "Standard YouTube License"; else license.Text = "Creative Commons Attribution license (reuse allowed)"; - VideoCategoriesResource.ListRequest categoryRequest = SecretsVault.NoAuthService.VideoCategories.List("snippet"); + VideoCategoriesResource.ListRequest categoryRequest = SecretsVault.Service.VideoCategories.List("snippet"); categoryRequest.Id = item.Snippet.CategoryId; category.Text = (await categoryRequest.ExecuteAsync()).Items[0].Snippet.Title; @@ -207,6 +205,12 @@ namespace FoxTube.Pages } subscribe.Visibility = Visibility.Visible; } + else + { + download.Visibility = Visibility.Collapsed; + addTo.Visibility = Visibility.Collapsed; + subscribe.Visibility = Visibility.Collapsed; + } ChannelsResource.ListRequest channelRequest = SecretsVault.Service.Channels.List("snippet, statistics"); channelRequest.Id = item.Snippet.ChannelId; @@ -235,38 +239,37 @@ namespace FoxTube.Pages async void LoadDownloads() { - /*List uris = (await YouTube.GetUrisAsync(item.Id)).ToList(); - if (uris.Count > 0) - foreach (YouTubeUri u in uris) + try + { + MediaStreamInfoSet infoSet = await new YoutubeClient().GetVideoMediaStreamInfosAsync(videoId); + foreach (MuxedStreamInfo i in infoSet.Muxed) { - if (u.HasAudio && u.HasVideo) + MenuFlyoutItem menuItem = new MenuFlyoutItem() { - MenuFlyoutItem menuItem = new MenuFlyoutItem() - { - Text = Methods.QualityToString(u.VideoQuality), - Tag = u.Uri.AbsoluteUri - }; - menuItem.Click += downloadItemSelected; - downloadSelector.Items.Add(menuItem); - } - else if (u.HasAudio) - { - MenuFlyoutItem menuItem = new MenuFlyoutItem() - { - Text = Methods.QualityToString(u.AudioQuality), - Tag = u.Uri.AbsoluteUri - }; - menuItem.Click += downloadItemSelected; - downloadSelector.Items.Add(menuItem); - } + Text = i.VideoQualityLabel, + Tag = new object[] { i, i.VideoQualityLabel } + }; + menuItem.Click += downloadItemSelected; + downloadSelector.Items.Add(menuItem); } - else - download.Visibility = Visibility.Collapsed;*/ + + MenuFlyoutItem audioItem = new MenuFlyoutItem() + { + Text = "Audio track", + Tag = new object[] { infoSet.Audio[0], "Audio only" } + }; + audioItem.Click += downloadItemSelected; + downloadSelector.Items.Add(audioItem); + } + catch (Exception e) + { + loading.Error(e.GetType().ToString(), e.Message); + } } private void downloadItemSelected(object sender, RoutedEventArgs e) { - Methods.MainPage.Agent.Add((sender as MenuFlyoutItem).Tag.ToString()); + DownloadAgent.Add(((sender as MenuFlyoutItem).Tag as object[])[0] as MediaStreamInfo, item, ((sender as MenuFlyoutItem).Tag as object[])[1] as string); } async void LoadRelatedVideos() @@ -325,8 +328,7 @@ namespace FoxTube.Pages public void refresh_Click(object sender, RoutedEventArgs e) { - player = new VideoPlayer(); - Initialize(new string[2] { videoId, playlistId }); + Methods.MainPage.GoToVideo(videoId, playlistId); } private void grid_SizeChanged(object sender, SizeChangedEventArgs e) @@ -363,43 +365,15 @@ namespace FoxTube.Pages } } - private async void Share(DataTransferManager sender, DataRequestedEventArgs args) + private void Share(DataTransferManager sender, DataRequestedEventArgs args) { player.Pause(); - DataRequest request = args.Request; - request.Data.Properties.Title = item.Snippet.Title; - request.Data.Properties.Description = "Sharing a video"; - // Handle errors - //request.FailWithDisplayText("Something unexpected could happen."); - - // Plain text - request.Data.SetText(item.Snippet.Title + "\n" + "#YouTube #FoxTube #SharedWithFoxTube"); - - // Uniform Resource Identifiers (URIs) - request.Data.SetWebLink(new Uri(string.Format("https://www.youtube.com/watch?v={0}", videoId))); - - // HTML - //request.Data.SetHtmlFormat("Bold Text"); - - // Because we are making async calls in the DataRequested event handler, - // we need to get the deferral first. - DataRequestDeferral deferral = request.GetDeferral(); - - // Make sure we always call Complete on the deferral. - try - { - StorageFile thumbnailFile = await Package.Current.InstalledLocation.GetFileAsync(item.Snippet.Thumbnails.Medium.Url); - request.Data.Properties.Thumbnail = RandomAccessStreamReference.CreateFromFile(thumbnailFile); - StorageFile imageFile = await Package.Current.InstalledLocation.GetFileAsync(item.Snippet.Thumbnails.Medium.Url); - - // Bitmaps - request.Data.SetBitmap(RandomAccessStreamReference.CreateFromFile(imageFile)); - } - finally - { - deferral.Complete(); - } + Methods.Share(args, + item.Snippet.Thumbnails.Medium.Url, + item.Snippet.Title, + $"https://www.youtube.com/watch?v={videoId}", + "video"); } private void share_Click(object sender, RoutedEventArgs e) diff --git a/FoxTube/Strings/en-US/Main.resw b/FoxTube/Strings/en-US/Main.resw index d3b5ac1..ba22dcd 100644 --- a/FoxTube/Strings/en-US/Main.resw +++ b/FoxTube/Strings/en-US/Main.resw @@ -117,13 +117,13 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - + Remove ads Downloads - + Give a feedback diff --git a/FoxTube/Strings/ru-RU/Main.resw b/FoxTube/Strings/ru-RU/Main.resw index d907b3b..5d461a8 100644 --- a/FoxTube/Strings/ru-RU/Main.resw +++ b/FoxTube/Strings/ru-RU/Main.resw @@ -117,13 +117,13 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - + Убрать рекламу Загрузки - + Оставить отзыв diff --git a/Src/FoxTubeLogoPadding.png b/Src/FoxTubeLogoPadding.png new file mode 100644 index 0000000..5a80f21 Binary files /dev/null and b/Src/FoxTubeLogoPadding.png differ