diff --git a/FoxTube/App.xaml.cs b/FoxTube/App.xaml.cs index e3fc7c4..6e8a466 100644 --- a/FoxTube/App.xaml.cs +++ b/FoxTube/App.xaml.cs @@ -10,7 +10,6 @@ using System.Xml; using Windows.ApplicationModel; using Windows.ApplicationModel.Activation; using Windows.ApplicationModel.Background; -using Windows.ApplicationModel.Core; using Windows.Globalization; using Windows.Storage; using Windows.System.Power; @@ -70,38 +69,32 @@ namespace FoxTube SettingsStorage.Version = $"{ver.Major}.{ver.Minor}.{ver.Build}"; } - catch + catch (Exception e) { - Debug.WriteLine("Unable to retrieve changelog"); + Analytics.TrackEvent("Unable to retrieve changelog", new Dictionary + { + { "Exception", e.GetType().ToString() }, + { "Message", e.Message }, + { "App version", $"{ver.Major}.{ver.Minor}.{ver.Revision}.{ver.Build}" } + }); } } } protected override void OnLaunched(LaunchActivatedEventArgs e) { - // Do not repeat app initialization when the Window already has content, - // just ensure that the window is active if (!(Window.Current.Content is Frame rootFrame)) { - // Create a Frame to act as the navigation context and navigate to the first page rootFrame = new Frame(); - rootFrame.NavigationFailed += OnNavigationFailed; - - // Place the frame in the current Window Window.Current.Content = rootFrame; } if (e.PrelaunchActivated == false) { if (rootFrame.Content == null) - { - // When the navigation stack isn't restored navigate to the first page, - // configuring the new page by passing required information as a navigation - // parameter rootFrame.Navigate(typeof(MainPage), e.Arguments); - } - // Ensure the current window is active + Window.Current.Activate(); } @@ -153,7 +146,7 @@ namespace FoxTube BackgroundTaskRegistration registration = builder.Register(); } - protected async override void OnBackgroundActivated(BackgroundActivatedEventArgs args) + protected override void OnBackgroundActivated(BackgroundActivatedEventArgs args) { var deferral = args.TaskInstance.GetDeferral(); base.OnBackgroundActivated(args); @@ -167,29 +160,36 @@ namespace FoxTube case "later": try { - if (!SecretsVault.IsAuthorized) - SecretsVault.CheckAuthorization(false); - if (!SecretsVault.IsAuthorized) - throw new Exception("Not authenticated"); - - PlaylistItem item = new PlaylistItem() + SecretsVault.AuthorizationStateChanged += async (s, e) => { - Snippet = new PlaylistItemSnippet() + if ((bool)e[0]) { - ResourceId = new ResourceId() + PlaylistItem item = new PlaylistItem() { - Kind = "youtube#video", - VideoId = arguments[1] - }, - PlaylistId = "WL" + Snippet = new PlaylistItemSnippet() + { + ResourceId = new ResourceId() + { + Kind = "youtube#video", + VideoId = arguments[1] + }, + PlaylistId = "WL" + } + }; + + await SecretsVault.Service.PlaylistItems.Insert(item, "snippet").ExecuteAsync(); } }; - - await SecretsVault.Service.PlaylistItems.Insert(item, "snippet").ExecuteAsync(); + SecretsVault.CheckAuthorization(false); } catch (Exception e) { - Debug.WriteLine(e.Message); + Analytics.TrackEvent("Failed to add video to WL from toast", new Dictionary + { + { "Exception", e.GetType().ToString() }, + { "Message", e.Message }, + { "Video ID", arguments[1] } + }); } break; } @@ -211,46 +211,46 @@ namespace FoxTube } if (rootFrame.Content == null) - { rootFrame.Navigate(typeof(MainPage)); - } Window.Current.Activate(); switch (e.Kind) { - case ActivationKind.Protocol: - break; case ActivationKind.ToastNotification: - 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.Cancel(args[1]); - break; - } + if (SecretsVault.IsAuthorized) + ProcessToast((e as ToastNotificationActivatedEventArgs).Argument); + else + SecretsVault.AuthorizationStateChanged += (s, arg) => ProcessToast((e as ToastNotificationActivatedEventArgs).Argument); break; } } - void Launch(string e = null) + private void ProcessToast(string arg) { + string[] args = arg.Split('|'); + switch (args[0]) + { + case "changelog": + case "inbox": + Methods.MainPage.GoToDeveloper(args[1]); + break; + case "video": + Methods.MainPage.GoToVideo(args[1]); + break; + + case "channel": + Methods.MainPage.GoToChannel(args[1]); + break; + + case "download": + Methods.MainPage.GoToDownloads(); + break; + case "dcancel": + DownloadAgent.Cancel(args[1]); + break; + } } void OnNavigationFailed(object sender, NavigationFailedEventArgs e) @@ -265,6 +265,7 @@ namespace FoxTube sw.Stop(); SettingsStorage.Uptime += sw.Elapsed; + HistorySet.Save(); SettingsStorage.SaveData(); DownloadAgent.QuitPrompt(); Controls.Player.ManifestGenerator.ClearRoaming(); @@ -277,7 +278,6 @@ namespace FoxTube Analytics.TrackEvent("The app crashed", new Dictionary() { { "Exception", e.Exception.GetType().ToString() }, - { "Class", e.ToString() }, { "Details", e.Message } }); } diff --git a/FoxTube/Assets/Data/Patchnotes.xml b/FoxTube/Assets/Data/Patchnotes.xml index e27240e..3e6b18f 100644 --- a/FoxTube/Assets/Data/Patchnotes.xml +++ b/FoxTube/Assets/Data/Patchnotes.xml @@ -6,13 +6,23 @@ ### What's new: - In-video advert now doesn't appear on minimized playback - Fixed small header appearing on channel page -- Fixed home page loading after in long active sessions +- Fixed home page loading in long active sessions +- Optimization and bugfixes +- Fixed crash when local watch history reaches 87 entries (now its capacity is 200) +- Added backward navigation to video page +- Improved authentication process +- Removed outdated logo from 'About' page and updated Twitter link ##[Патч #1] ### Что нового: - Теперь реклама в видео не появляется в компактном режиме - Исправлено появление меленького заголовка на странице канала - Исправлено отображение видео на домашней странице при долгой активной сессии +- Оптимизация и исправление ошибок +- Исправлен сбой приложения при достижении локальной историей 87 записей (текущая емкость журнала - 200 записей) +- Добавлена обратная навигация для страниц просмотра +- Улучшен процесс аутентификации +- Удален старый логотип с страницы 'О приложении' и обновлена ссылка на Твиттер diff --git a/FoxTube/Classes/DownloadAgent.cs b/FoxTube/Classes/DownloadAgent.cs index c46fdb6..f4c59e8 100644 --- a/FoxTube/Classes/DownloadAgent.cs +++ b/FoxTube/Classes/DownloadAgent.cs @@ -6,13 +6,14 @@ using YoutubeExplode.Models.MediaStreams; using Google.Apis.YouTube.v3.Data; using FoxTube.Controls; using FoxTube.Pages; +using Microsoft.AppCenter.Analytics; namespace FoxTube { public static class DownloadAgent { - public static List items = new List(); - private static ApplicationDataContainer settings = ApplicationData.Current.LocalSettings; + public static List Items { get; set; } = new List(); + private static readonly ApplicationDataContainer settings = ApplicationData.Current.LocalSettings; public static Downloads Page { get; set; } public static StorageFolder Downloads { get; set; } @@ -21,45 +22,52 @@ namespace FoxTube Downloads = await KnownFolders.VideosLibrary.CreateFolderAsync("FoxTube", CreationCollisionOption.OpenIfExists); try { - List containers = JsonConvert.DeserializeObject>((string)settings.Values["downloads"]); - containers.ForEach(i => items.Add(new DownloadItem(i))); + List containers = JsonConvert.DeserializeObject>((string)settings.Values[$"downloads"]); + containers.ForEach(i => Items.Add(new DownloadItem(i))); + } + catch (Exception e) + { + Analytics.TrackEvent("Failed to load downloads history", new Dictionary + { + { "Exception", e.GetType().ToString() }, + { "Message", e.Message } + }); } - catch { } } public static void Add(MediaStreamInfo info, Video meta, string qualty) { - items.Insert(0, new DownloadItem(info, meta, qualty)); + Items.Insert(0, new DownloadItem(info, meta, qualty)); } public static void Remove(DownloadItem item) { - try { Page.Remove(item); } - catch { } - items.Remove(item); + Page?.Remove(item); + Items.Remove(item); } + public static void Cancel(string id) { - DownloadItem item = items.Find(i => i.Container.Id == id); + DownloadItem item = Items.Find(i => i.Container.Id == id); if (item != null) item.Cancel(); } public static void QuitPrompt() { - foreach (DownloadItem i in items.FindAll(i => !i.Container.IsDownloaded)) + foreach (DownloadItem i in Items.FindAll(i => !i.Container.IsDownloaded)) { i.Cancel(); - items.Remove(i); + Items.Remove(i); } List containers = new List(); - items.ForEach(i => containers.Add(i.Container)); + Items.ForEach(i => containers.Add(i.Container)); string data = JsonConvert.SerializeObject(containers); - settings.Values["downloads"] = data; + settings.Values[$"downloads"] = data; } } } diff --git a/FoxTube/Classes/HistorySet.cs b/FoxTube/Classes/HistorySet.cs new file mode 100644 index 0000000..7e95ccc --- /dev/null +++ b/FoxTube/Classes/HistorySet.cs @@ -0,0 +1,87 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using Windows.Storage; + +namespace FoxTube +{ + public class HistoryItem + { + public string Id { get; set; } + public TimeSpan LeftOn { get; set; } = TimeSpan.FromSeconds(0); + } + + public static class HistorySet + { + public static List Items { get; set; } = new List(); + + public static void Update(HistoryItem item) + { + if (!SecretsVault.IsAuthorized) + return; + + Items.RemoveAll(i => i.Id == item.Id); + + Items.Insert(0, item); + if (Items.Count > 200) + Items.RemoveRange(200, Items.Count - 200); + Save(); + } + + public static void Delete(HistoryItem item) + { + if (!SecretsVault.IsAuthorized) + return; + + Items.Remove(item); + Save(); + } + + public static void Clear() + { + if (!SecretsVault.IsAuthorized) + return; + + Items.Clear(); + Save(); + } + + public static void Save() + { + List[] parts = new List[4] + { + new List(), new List(), + new List(), new List() + }; + + foreach(HistoryItem i in Items) + if (parts[0].Count < 50) + parts[0].Add(i); + else + { + if (parts[1].Count < 50) + parts[1].Add(i); + else + { + if (parts[2].Count < 50) + parts[2].Add(i); + else + parts[3].Add(i); + } + } + + for(int k = 0; k < parts.Length; k++) + ApplicationData.Current.RoamingSettings.Values[$"history-{SecretsVault.AccountId}-level{k}"] = JsonConvert.SerializeObject(parts[k]); + } + + public static void Load() + { + try + { + for (int k = 0; k < 4; k++) + Items.AddRange(JsonConvert.DeserializeObject>(ApplicationData.Current.RoamingSettings.Values[$"history-{SecretsVault.AccountId}-level{k}"] as string)); + } + catch { } + } + } +} diff --git a/FoxTube/Classes/InboxItem.cs b/FoxTube/Classes/InboxItem.cs index 21ff0cc..f73a0e3 100644 --- a/FoxTube/Classes/InboxItem.cs +++ b/FoxTube/Classes/InboxItem.cs @@ -3,7 +3,7 @@ using Windows.ApplicationModel.Resources; namespace FoxTube.Classes { - public enum InboxItemType { Default, PatchNote} + public enum InboxItemType { Default, PatchNote } public class InboxItem { @@ -59,11 +59,11 @@ namespace FoxTube.Classes } - public InboxItem(string version, string content, string timeStamp) + public InboxItem(string version, string content, DateTime timeStamp) { Type = InboxItemType.PatchNote; Content = content; - TimeStamp = DateTime.Parse(timeStamp); + TimeStamp = timeStamp; Id = version; } diff --git a/FoxTube/Classes/ManifestGenerator.cs b/FoxTube/Classes/ManifestGenerator.cs index 0ce6ea5..66a05bf 100644 --- a/FoxTube/Classes/ManifestGenerator.cs +++ b/FoxTube/Classes/ManifestGenerator.cs @@ -1,6 +1,7 @@ using AngleSharp.Dom.Html; using AngleSharp.Parser.Html; using Google.Apis.YouTube.v3.Data; +using Microsoft.AppCenter.Analytics; using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; @@ -23,17 +24,11 @@ namespace FoxTube.Controls.Player public static async Task GetManifest(Video meta, VideoStreamInfo requestedQuality, MediaStreamInfoSet list) { StorageFile manifest; - try - { - manifest = await roaming.CreateFileAsync("manifest.mpd", CreationCollisionOption.ReplaceExisting); - } - catch - { - manifest = await roaming.CreateFileAsync("manifest.mpd", CreationCollisionOption.GenerateUniqueName); - } - try - { + try { manifest = await roaming.CreateFileAsync("manifest.mpd", CreationCollisionOption.ReplaceExisting); } + catch { manifest = await roaming.CreateFileAsync("manifest.mpd", CreationCollisionOption.GenerateUniqueName); } + try + { XmlDocument doc = new XmlDocument(); XmlElement mpd = doc.CreateElement("MPD"); @@ -75,6 +70,13 @@ namespace FoxTube.Controls.Player } catch (Exception e) { + Analytics.TrackEvent("Failed to generate manifest", new Dictionary + { + { "Exception", e.GetType().ToString() }, + { "Message", e.Message }, + { "Video ID", meta.Id }, + { "Requested quality", requestedQuality.VideoQualityLabel } + }); return null; } } diff --git a/FoxTube/Classes/Methods.cs b/FoxTube/Classes/Methods.cs index 13d41d0..11e1c5d 100644 --- a/FoxTube/Classes/Methods.cs +++ b/FoxTube/Classes/Methods.cs @@ -1,4 +1,5 @@ using FoxTube.Pages; +using Microsoft.AppCenter.Analytics; using Newtonsoft.Json; using System; using System.Collections.Generic; @@ -10,7 +11,6 @@ using System.Xml; using Windows.ApplicationModel.Core; using Windows.ApplicationModel.DataTransfer; using Windows.ApplicationModel.Resources; -using Windows.Storage; using Windows.Storage.Streams; using Windows.System; using Windows.UI.Xaml; @@ -21,64 +21,21 @@ using YoutubeExplode.Models.MediaStreams; namespace FoxTube { - public interface NavigationPage + public delegate void Event(); + + public delegate void ObjectEventHandler(object sender = null, params object[] args); + + public interface INavigationPage { object Parameter { get; set; } } - public class HistoryItem - { - public string Id { get; set; } - public TimeSpan LeftOn { get; set; } = TimeSpan.FromSeconds(0); - } - - public static class HistorySet - { - public static List Items { get; set; } = new List(); - - public static void Update(HistoryItem item) - { - if(Items.Exists(i => i.Id == item.Id)) - Items.RemoveAll(i => i.Id == item.Id); - - Items.Insert(0, item); - Save(); - } - - public static void Delete(HistoryItem item) - { - Items.Remove(item); - Save(); - } - - public static void Clear() - { - Items.Clear(); - Save(); - } - - private static void Save() - { - try { ApplicationData.Current.RoamingSettings.Values[$"history-{SecretsVault.AccountId}"] = JsonConvert.SerializeObject(Items); } - catch { } - } - - public static void Load() - { - if (ApplicationData.Current.RoamingSettings.Values[$"history-{SecretsVault.AccountId}"] != null) - Items = JsonConvert.DeserializeObject>(ApplicationData.Current.RoamingSettings.Values[$"history-{SecretsVault.AccountId}"] as string); - } - } - public static class Methods { - private static ResourceLoader resources = ResourceLoader.GetForCurrentView("Methods"); - public static CommentsPage CommentsPage { get; set; } + private static readonly ResourceLoader resources = ResourceLoader.GetForCurrentView("Methods"); - public static MainPage MainPage - { - get { return (Window.Current.Content as Frame).Content as MainPage; } - } + public static CommentsPage CommentsPage { get; set; } + public static MainPage MainPage => (Window.Current.Content as Frame).Content as MainPage; public static void CloseApp() { @@ -87,20 +44,15 @@ namespace FoxTube public static Uri ToUri(this string url) { - if (string.IsNullOrWhiteSpace(url)) - return null; - else - return new Uri(url); + return string.IsNullOrWhiteSpace(url) ? null : new Uri(url); } public static string GuardFromNull(string str) { - if (string.IsNullOrWhiteSpace(str)) - return string.Empty; - else - return str; + return str ?? string.Empty; } + [Obsolete] public static string GetChars(this string str, int count) { try @@ -140,6 +92,7 @@ namespace FoxTube return array.ToList().FindAll(match); } + [Obsolete] public static string ReplaceInvalidChars(this string str, char newValue) { foreach (char i in Path.GetInvalidFileNameChars()) @@ -147,6 +100,7 @@ namespace FoxTube return str; } + [Obsolete] public static string Last(this string[] arr) { return arr[arr.Length - 1]; @@ -161,13 +115,18 @@ namespace FoxTube catch (FormatException) { TimeSpan time = XmlConvert.ToTimeSpan("PT" + str.Split('T')[1]); - TimeSpan date = TimeSpan.FromDays(int.Parse(str.Split('W')[0].Replace("P", "")) * 7); + TimeSpan date = TimeSpan.FromDays(int.Parse(str.Split('W')[0].Remove('P')) * 7); date.Add(time); return date; } - catch + catch (Exception e) { + Analytics.TrackEvent("Failed to parse duration", new Dictionary + { + { "Exception", e.GetType().ToString() }, + { "Message", e.Message } + }); return TimeSpan.FromMilliseconds(0); } } @@ -204,7 +163,7 @@ namespace FoxTube return Math.Round(span.TotalDays / 365) + " " + resources.GetString("/Methods/years"); } - public static void FormatText(ref TextBlock block, string text) + public static void FormatText(this TextBlock block, string text) { block.Inlines.Clear(); Regex filter = new Regex(@"\b((?:https?://|www\.)\S+)|(\S+@\S+)\b", RegexOptions.IgnoreCase); @@ -268,10 +227,9 @@ namespace FoxTube public async static void ProcessLink(string url) { - string output; string type; - if (YoutubeClient.TryParseChannelId(url, out output)) + if (YoutubeClient.TryParseChannelId(url, out string output)) { type = "channel"; goto LinkFound; @@ -295,7 +253,7 @@ namespace FoxTube await Launcher.LaunchUriAsync(new Uri(url)); return; - LinkFound: + LinkFound: switch (type) { case "channel": @@ -313,32 +271,23 @@ namespace FoxTube } } - public static async void Share(DataRequestedEventArgs args, string thumbnail, string title, string url, string type) + public static void Share(DataRequestedEventArgs args, string thumbnail, string title, string url, string type) { DataRequest request = args.Request; + request.Data.Properties.Title = title; request.Data.Properties.Description = $"{resources.GetString("/Methods/sharing")} {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(); - } + request.Data.Properties.Thumbnail = RandomAccessStreamReference.CreateFromUri(thumbnail.ToUri()); + request.Data.SetBitmap(RandomAccessStreamReference.CreateFromUri(thumbnail.ToUri())); } public static async Task> GetHistory() { + SecretsVault.RefreshToken(); List list = new List(); string output = await SecretsVault.HttpClient.GetStringAsync($"https://www.youtube.com/list_ajax?style=json&action_get_list=1&list=HL&hl={SettingsStorage.RelevanceLanguage}"); @@ -352,6 +301,7 @@ namespace FoxTube public static async Task> GetLater() { + SecretsVault.RefreshToken(); List list = new List(); string output = await SecretsVault.HttpClient.GetStringAsync($"https://www.youtube.com/list_ajax?style=json&action_get_list=1&list=WL&hl={SettingsStorage.RelevanceLanguage}"); diff --git a/FoxTube/Classes/SearchPaameters.cs b/FoxTube/Classes/SearchPaameters.cs index 323cb70..17299bd 100644 --- a/FoxTube/Classes/SearchPaameters.cs +++ b/FoxTube/Classes/SearchPaameters.cs @@ -4,10 +4,6 @@ using static Google.Apis.YouTube.v3.SearchResource.ListRequest; namespace FoxTube { - public delegate void Event(); - - public delegate void ObjectEventHandler(object sender = null, params object[] args); - public class SearchParameters { public class Filters diff --git a/FoxTube/Classes/SecretsVault.cs b/FoxTube/Classes/SecretsVault.cs index 7065056..5df4f04 100644 --- a/FoxTube/Classes/SecretsVault.cs +++ b/FoxTube/Classes/SecretsVault.cs @@ -13,6 +13,7 @@ using System.Net.Http; using Google.Apis.Oauth2.v2.Data; using Google.Apis.Oauth2.v2; using static Google.Apis.Auth.OAuth2.UwpCodeReceiver; +using Microsoft.AppCenter.Analytics; namespace FoxTube { @@ -24,7 +25,7 @@ namespace FoxTube public static event ObjectEventHandler SubscriptionsChanged; public static event ObjectEventHandler Purchased; //Rising when app finds out that it's not a PRO version - //Private properties + //Properties private static ClientSecrets Secrets => new ClientSecrets() { ClientId = "349735264870-2ekqlm0a4mkg3mmrfcv90s3qp3o15dq0.apps.googleusercontent.com", @@ -41,15 +42,16 @@ namespace FoxTube ApplicationName = "FoxTube" }; public static YouTubeService Service => IsAuthorized ? new YouTubeService(Initializer) : NoAuthService; + public static HttpClient HttpClient { get; } = new HttpClient(); - private static bool TestAds => true; //Change this bool + private static bool TestAds => true; //TODO: Change this bool public static string AppId => TestAds ? "d25517cb-12d4-4699-8bdc-52040c712cab" : "9ncqqxjtdlfh"; public static string AdUnitId => TestAds ? "test" : "1100044398"; public static bool AdsDisabled { get; private set; } = true; //User info public static bool IsAuthorized => Credential != null; - private static UserCredential Credential { get; set; } + private static UserCredential Credential { get; set; } = null; public static string AccountId => UserChannel?.Id; public static Channel UserChannel { get; private set; } @@ -73,9 +75,6 @@ namespace FoxTube /// 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.Exists(x => x.Snippet.ResourceId.ChannelId == id)) { Subscription s = Subscriptions.Find(x => x.Snippet.ResourceId.ChannelId == id); @@ -83,7 +82,7 @@ namespace FoxTube try { await Service.Subscriptions.Delete(s.Id).ExecuteAsync(); } catch { return true; } - SubscriptionsChanged?.Invoke(null, "remove", s); + SubscriptionsChanged?.Invoke(null, "remove", s.Snippet.ResourceId.ChannelId); Subscriptions.Remove(s); return false; } @@ -129,19 +128,19 @@ namespace FoxTube try { Credential = await GoogleWebAuthorizationBroker.AuthorizeAsync( - Secrets, - new[] - { - Oauth2Service.Scope.UserinfoProfile, - Oauth2Service.Scope.UserinfoEmail, - YouTubeService.Scope.YoutubeForceSsl, - YouTubeService.Scope.Youtube, - YouTubeService.Scope.YoutubeUpload, - YouTubeService.Scope.YoutubeReadonly, - YouTubeService.Scope.Youtubepartner - }, - "user", - CancellationToken.None); + Secrets, + new[] + { + Oauth2Service.Scope.UserinfoProfile, + Oauth2Service.Scope.UserinfoEmail, + YouTubeService.Scope.YoutubeForceSsl, + YouTubeService.Scope.Youtube, + YouTubeService.Scope.YoutubeUpload, + YouTubeService.Scope.YoutubeReadonly, + YouTubeService.Scope.Youtubepartner + }, + "user", + CancellationToken.None); await Credential.RefreshTokenAsync(CancellationToken.None); } @@ -150,15 +149,19 @@ namespace FoxTube if (e.Message.Contains("UserCancel")) return; else - throw e; + Analytics.TrackEvent("Failed to authorize", new Dictionary + { + { "Exception", e.GetType().ToString() }, + { "Message", e.Message } + }); } if (Credential == null || !retrieveSubs) return; - SettingsStorage.HasAccount = true; - HttpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", Credential.Token.AccessToken); + + SettingsStorage.HasAccount = true; #endregion try @@ -166,12 +169,8 @@ namespace FoxTube #region Retrieving user's data UserInfo = await new Oauth2Service(Initializer).Userinfo.Get().ExecuteAsync(); - try - { - WatchLater = await Methods.GetLater(); - History = await Methods.GetHistory(); - } - catch { } + WatchLater = await Methods.GetLater(); + History = await Methods.GetHistory(); SubscriptionsResource.ListRequest subRequest = Service.Subscriptions.List("snippet"); subRequest.Mine = true; @@ -201,9 +200,14 @@ namespace FoxTube AuthorizationStateChanged?.Invoke(args: true); } - catch + catch (Exception e) { AuthorizationStateChanged?.Invoke(args: new bool?[] { null }); + Analytics.TrackEvent("Failed to retrieve user's info", new Dictionary + { + { "Exception", e.GetType().ToString() }, + { "Message", e.Message } + }); } } @@ -222,14 +226,19 @@ namespace FoxTube /// public static async void Deauthenticate() { - if(await Credential.RevokeTokenAsync(CancellationToken.None)) - { - Credential = null; - AuthorizationStateChanged?.Invoke(args: false); - SettingsStorage.HasAccount = false; + if (!await Credential.RevokeTokenAsync(CancellationToken.None)) + return; + + Credential = null; + UserChannel = null; + UserInfo = null; + History.Clear(); + WatchLater.Clear(); + Subscriptions.Clear(); + ApplicationData.Current.RoamingSettings.Values["subscriptions"] = ""; - ApplicationData.Current.RoamingSettings.Values["subscriptions"] = ""; - } + AuthorizationStateChanged?.Invoke(args: false); + SettingsStorage.HasAccount = false; } /// @@ -254,32 +263,24 @@ namespace FoxTube { try { - StoreContext store = StoreContext.GetDefault(); - StoreProductQueryResult requset = await store.GetAssociatedStoreProductsAsync(new[] { "Durable" }); - Dictionary l = new Dictionary(); - requset.Products.ForEach(i => l.Add(i.Key, i.Value)); + StoreProductQueryResult requset = await StoreContext.GetDefault().GetAssociatedStoreProductsAsync(new[] { "Durable" }); - if (!requset.Products["9NP1QK556625"].IsInUserCollection) - { - AdsDisabled = false; - Purchased?.Invoke(null, false, requset.Products["9NP1QK556625"].Price.FormattedPrice); - } + if (requset.Products["9NP1QK556625"].IsInUserCollection) + return; + + AdsDisabled = false; + Purchased?.Invoke(null, false, requset.Products["9NP1QK556625"].Price.FormattedPrice); } catch { } } public static async void GetAdblock() { - StoreContext store = StoreContext.GetDefault(); - StorePurchaseResult request = await store.RequestPurchaseAsync("9NP1QK556625"); + StorePurchaseResult request = await StoreContext.GetDefault().RequestPurchaseAsync("9NP1QK556625"); switch (request.Status) { case StorePurchaseStatus.AlreadyPurchased: - Purchased?.Invoke(args: true); - AdsDisabled = true; - break; - case StorePurchaseStatus.Succeeded: Purchased?.Invoke(args: true); AdsDisabled = true; diff --git a/FoxTube/Classes/SettingsStorage.cs b/FoxTube/Classes/SettingsStorage.cs index 09197ca..cdc348d 100644 --- a/FoxTube/Classes/SettingsStorage.cs +++ b/FoxTube/Classes/SettingsStorage.cs @@ -1,5 +1,7 @@ -using Newtonsoft.Json; +using Microsoft.AppCenter.Analytics; +using Newtonsoft.Json; using System; +using System.Collections.Generic; using System.Globalization; using System.Linq; using Windows.ApplicationModel; @@ -221,7 +223,7 @@ namespace FoxTube //Settings storage private static readonly ApplicationDataContainer storage = ApplicationData.Current.RoamingSettings; - private static SettingsContainer Container; + private static SettingsContainer Container = new SettingsContainer(); public static void LoadData() { @@ -229,10 +231,15 @@ namespace FoxTube { Container = JsonConvert.DeserializeObject(storage.Values["settings"] as string); } - catch + catch (Exception e) { - Container = new SettingsContainer(); SaveData(); + if (storage.Values["settings"] != null) + Analytics.TrackEvent("Failed to retrieve settings", new Dictionary + { + { "Exception", e.GetType().ToString() }, + { "Message", e.Message } + }); } } diff --git a/FoxTube/Controls/Adverts/CardAdvert.xaml.cs b/FoxTube/Controls/Adverts/CardAdvert.xaml.cs index 33c869b..7959d53 100644 --- a/FoxTube/Controls/Adverts/CardAdvert.xaml.cs +++ b/FoxTube/Controls/Adverts/CardAdvert.xaml.cs @@ -13,21 +13,14 @@ namespace FoxTube.Controls.Adverts { NativeAdsManagerV2 manager = new NativeAdsManagerV2(SecretsVault.AppId, SecretsVault.AdUnitId); public NativeAdV2 advert; - public CardAdvert(bool isOnVideoPage = false) + public CardAdvert() { InitializeComponent(); - if(!isOnVideoPage) - MainPage.VideoPageSizeChanged += Methods_VideoPageSizeChanged; manager.AdReady += AdReady; manager.ErrorOccurred += ErrorOccurred; manager.RequestAd(); } - private void Methods_VideoPageSizeChanged(object sender = null, params object[] args) - { - Visibility = !(bool)args[0] && advert != null ? Visibility.Visible : Visibility.Collapsed; - } - private void ErrorOccurred(object sender, NativeAdErrorEventArgs e) { System.Diagnostics.Debug.WriteLine("Error has occured while loading ad"); diff --git a/FoxTube/Controls/ChannelCard.xaml b/FoxTube/Controls/ChannelCard.xaml index c19f69c..a68f90b 100644 --- a/FoxTube/Controls/ChannelCard.xaml +++ b/FoxTube/Controls/ChannelCard.xaml @@ -9,22 +9,18 @@ VerticalAlignment="Top" d:DesignHeight="290" d:DesignWidth="384" + MaxWidth="700" Opacity="0" - Name="card"> + Name="card" + SizeChanged="Card_SizeChanged"> - - - - - - - - + + + + + + + + - + - + + diff --git a/FoxTube/Pages/CommentsPage.xaml.cs b/FoxTube/Pages/CommentsPage.xaml.cs index c1c614c..7abd708 100644 --- a/FoxTube/Pages/CommentsPage.xaml.cs +++ b/FoxTube/Pages/CommentsPage.xaml.cs @@ -6,6 +6,8 @@ using Google.Apis.YouTube.v3.Data; using FoxTube.Controls; using Windows.UI.Popups; using Windows.ApplicationModel.Resources; +using Microsoft.AppCenter.Analytics; +using System.Collections.Generic; namespace FoxTube.Pages { @@ -52,18 +54,18 @@ namespace FoxTube.Pages foreach (CommentThread comment in response.Items) { - if ((placeholder.Children.Count - 5) % 20 == 0 && !SecretsVault.AdsDisabled) - placeholder.Children.Add(new Controls.Adverts.CommentAdvert()); - placeholder.Children.Add(new CommentCard(comment)); + if ((list.Children.Count - 5) % 20 == 0 && !SecretsVault.AdsDisabled) + list.Children.Add(new Controls.Adverts.CommentAdvert()); + list.Children.Add(new CommentCard(comment)); } } public void RemoveComment(CommentCard commentCard, string topCommentId = null) { if (string.IsNullOrWhiteSpace(topCommentId)) - placeholder.Children.Remove(commentCard); + list.Children.Remove(commentCard); else - (placeholder.Children.Find(i => (i as CommentCard).thread.Id == topCommentId) as CommentCard).DeleteComment(commentCard); + (list.Children.Find(i => (i as CommentCard).thread.Id == topCommentId) as CommentCard)?.DeleteComment(commentCard); } private async void toRelevance_Click(object sender, RoutedEventArgs e) @@ -71,12 +73,12 @@ namespace FoxTube.Pages if (order == CommentThreadsResource.ListRequest.OrderEnum.Relevance) return; - more.Show(); + more.Visibility = Visibility.Visible; order = CommentThreadsResource.ListRequest.OrderEnum.Relevance; orderBtn.Content = resources.GetString("/CommentsPage/relevance/Text"); - placeholder.Children.Clear(); + list.Children.Clear(); request.Order = order; var response = await request.ExecuteAsync(); @@ -86,7 +88,11 @@ namespace FoxTube.Pages more.Visibility = Visibility.Collapsed; foreach (CommentThread comment in response.Items) - placeholder.Children.Add(new CommentCard(comment)); + { + if ((list.Children.Count - 5) % 20 == 0 && !SecretsVault.AdsDisabled) + list.Children.Add(new Controls.Adverts.CommentAdvert()); + list.Children.Add(new CommentCard(comment)); + } more.Complete(); } @@ -96,12 +102,12 @@ namespace FoxTube.Pages if (order == CommentThreadsResource.ListRequest.OrderEnum.Time) return; - more.Show(); + more.Visibility = Visibility.Visible; order = CommentThreadsResource.ListRequest.OrderEnum.Time; orderBtn.Content = resources.GetString("/CommentsPage/publish"); - placeholder.Children.Clear(); + list.Children.Clear(); request.Order = order; var response = await request.ExecuteAsync(); @@ -111,12 +117,16 @@ namespace FoxTube.Pages more.Visibility = Visibility.Collapsed; foreach (CommentThread comment in response.Items) - placeholder.Children.Add(new CommentCard(comment)); + { + if ((list.Children.Count - 5) % 20 == 0 && !SecretsVault.AdsDisabled) + list.Children.Add(new Controls.Adverts.CommentAdvert()); + list.Children.Add(new CommentCard(comment)); + } more.Complete(); } - private async void send_Click(object sender, RoutedEventArgs e) + private async void send_Click(object sender, RoutedEventArgs args) { if (string.IsNullOrWhiteSpace(newComment.Text)) return; @@ -125,13 +135,13 @@ namespace FoxTube.Pages send.IsEnabled = false; sending.Visibility = Visibility.Visible; - CommentThread thread = new CommentThread() + CommentThread thread = new CommentThread { - Snippet = new CommentThreadSnippet() + Snippet = new CommentThreadSnippet { - TopLevelComment = new Comment() + TopLevelComment = new Comment { - Snippet = new CommentSnippet() + Snippet = new CommentSnippet { TextOriginal = newComment.Text } @@ -143,11 +153,20 @@ namespace FoxTube.Pages try { CommentThread response = await SecretsVault.Service.CommentThreads.Insert(thread, "snippet").ExecuteAsync(); - placeholder.Children.Insert(0, new CommentCard(response)); + list.Children.Insert(0, new CommentCard(response)); newComment.Text = ""; scroll.ChangeView(null, 0, null); } - catch { await new MessageDialog("Failed to publish your comment. Please, try again later.").ShowAsync(); } + catch (Exception e) + { + await new MessageDialog("Failed to publish your comment. Please, try again later.").ShowAsync(); + Analytics.TrackEvent("Failed to post comment", new Dictionary + { + { "Exception", e.GetType().ToString() }, + { "Message", e.Message }, + { "Thread ID", threadId } + }); + } newComment.IsEnabled = true; send.IsEnabled = true; @@ -158,18 +177,19 @@ namespace FoxTube.Pages { request.PageToken = token; var response = await request.ExecuteAsync(); + + token = response.NextPageToken; + if (string.IsNullOrWhiteSpace(token)) + more.Visibility = Visibility.Collapsed; foreach (CommentThread comment in response.Items) { - if ((placeholder.Children.Count - 5) % 20 == 0 && !SecretsVault.AdsDisabled) - placeholder.Children.Add(new Controls.Adverts.CommentAdvert()); - placeholder.Children.Add(new CommentCard(comment)); + if ((list.Children.Count - 5) % 20 == 0 && !SecretsVault.AdsDisabled) + list.Children.Add(new Controls.Adverts.CommentAdvert()); + list.Children.Add(new CommentCard(comment)); } - - token = response.NextPageToken; + more.Complete(); - if (string.IsNullOrWhiteSpace(token)) - more.Visibility = Visibility.Collapsed; } } } diff --git a/FoxTube/Pages/Downloads.xaml b/FoxTube/Pages/Downloads.xaml index 0fb933e..ff93b89 100644 --- a/FoxTube/Pages/Downloads.xaml +++ b/FoxTube/Pages/Downloads.xaml @@ -11,7 +11,6 @@ - @@ -22,7 +21,6 @@ - - - - - - - - - - - - - - - - - @@ -116,30 +99,20 @@ - - - - - - - - - - - - - - - + + + + + - + - - + + diff --git a/FoxTube/Pages/MainPage.xaml.cs b/FoxTube/Pages/MainPage.xaml.cs index b524f0c..9ea77ea 100644 --- a/FoxTube/Pages/MainPage.xaml.cs +++ b/FoxTube/Pages/MainPage.xaml.cs @@ -6,7 +6,6 @@ using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Navigation; -using System.Diagnostics; using Windows.UI.Xaml.Media.Imaging; using System.Xml; using Google.Apis.YouTube.v3.Data; @@ -14,11 +13,11 @@ using Windows.ApplicationModel.Core; using Windows.System; using FoxTube.Pages; using Windows.UI.Popups; -using Windows.Networking.Connectivity; using Windows.ApplicationModel.Resources; using Microsoft.Services.Store.Engagement; using Windows.UI.Xaml.Shapes; using Windows.UI.Xaml.Media; +using FoxTube.Controls; namespace FoxTube { @@ -28,38 +27,14 @@ namespace FoxTube public sealed partial class MainPage : Page { bool wasInvoked = false; - public static event ObjectEventHandler VideoPageSizeChanged; readonly ResourceLoader resources = ResourceLoader.GetForCurrentView("Main"); Dictionary headers; - public Page PageContent => content.Content as Page; + public ContentFrame PageContent => content; + public ContentFrame VideoContent => videoPlaceholder; public MainPage() { - InitializeComponent(); - - Window.Current.SetTitleBar(AppTitleBar); - CoreApplication.GetCurrentView().TitleBar.ExtendViewIntoTitleBar = true; - CoreApplication.GetCurrentView().TitleBar.LayoutMetricsChanged += (s, e) => SetTitleBar(s); - - SecretsVault.AuthorizationStateChanged += AuthorizationStateChanged; - SecretsVault.SubscriptionsChanged += SecretsVault_SubscriptionsChanged; - SecretsVault.Purchased += async (sender, e) => - { - removeAds.Visibility = (e[0] as bool?).Value ? Visibility.Collapsed : Visibility.Visible; - removeAds.Content = $"{resources.GetString("/Main/adsFree/Content")} ({e[1]})"; - if (!(bool)e[0]) - return; - - MessageDialog dialog = new MessageDialog(resources.GetString("/Main/purchaseSuccess")); - dialog.Commands.Add(new UICommand(resources.GetString("/Main/close"), (command) => Methods.CloseApp())); - dialog.Commands.Add(new UICommand(resources.GetString("/Main/delay"))); - dialog.CancelCommandIndex = 1; - dialog.DefaultCommandIndex = 0; - await dialog.ShowAsync(); - }; - SecretsVault.Initialize(); - headers = new Dictionary() { { typeof(Settings), resources.GetString("/Main/settings/Content") }, @@ -72,6 +47,33 @@ namespace FoxTube { typeof(Downloads), resources.GetString("/Main/downloads/Content") } }; + InitializeComponent(); + + Window.Current.SetTitleBar(AppTitleBar); + CoreApplication.GetCurrentView().TitleBar.ExtendViewIntoTitleBar = true; + CoreApplication.GetCurrentView().TitleBar.LayoutMetricsChanged += (s, e) => SetTitleBar(s); + + SecretsVault.AuthorizationStateChanged += AuthorizationStateChanged; + SecretsVault.SubscriptionsChanged += SecretsVault_SubscriptionsChanged; + SecretsVault.Purchased += async (sender, e) => + { + removeAds.Visibility = (e[0] as bool?).Value ? Visibility.Collapsed : Visibility.Visible; + + if (!(bool)e[0]) + { + removeAds.Content = $"{resources.GetString("/Main/adsFree/Content")} ({e[1]})"; + return; + } + + MessageDialog dialog = new MessageDialog(resources.GetString("/Main/purchaseSuccess")); + dialog.Commands.Add(new UICommand(resources.GetString("/Main/close"), (command) => Methods.CloseApp())); + dialog.Commands.Add(new UICommand(resources.GetString("/Main/delay"))); + dialog.CancelCommandIndex = 1; + dialog.DefaultCommandIndex = 0; + await dialog.ShowAsync(); + }; + SecretsVault.Initialize(); + if(StoreServicesFeedbackLauncher.IsSupported()) feedback.Visibility = Visibility.Visible; @@ -121,16 +123,15 @@ namespace FoxTube } } - public string GetPlaylist() - { - try { return (videoPlaceholder.Content as VideoPage).playlistId; } - catch { return null; } - } - public void SetTitleBar(CoreApplicationViewTitleBar coreTitleBar = null) { if (coreTitleBar != null) + { + bool full = ApplicationView.GetForCurrentView().IsFullScreenMode; + double left = 12 + (full ? 0 : coreTitleBar.SystemOverlayLeftInset); + AppTitle.Margin = new Thickness(left, 8, 0, 0); AppTitleBar.Height = coreTitleBar.Height; + } var titleBar = ApplicationView.GetForCurrentView().TitleBar; @@ -148,7 +149,7 @@ namespace FoxTube private void SecretsVault_SubscriptionsChanged(object sender, params object[] args) { - switch(args[0] as string) + switch((string)args[0]) { case "add": if (nav.MenuItems.Count < 19) @@ -156,21 +157,21 @@ namespace FoxTube break; case "remove": - Microsoft.UI.Xaml.Controls.NavigationViewItem item = nav.MenuItems.Find(i => ((i as Microsoft.UI.Xaml.Controls.NavigationViewItem).Content as StackPanel).Tag.ToString() == (args[1] as Subscription).Snippet.ResourceId.ChannelId) as Microsoft.UI.Xaml.Controls.NavigationViewItem; - if (item == null) - break; - else + if (nav.MenuItems.Find(i => ((i as Microsoft.UI.Xaml.Controls.NavigationViewItem).Content as StackPanel).Tag.ToString() == (string)args[1]) is Microsoft.UI.Xaml.Controls.NavigationViewItem item) + { nav.MenuItems.Remove(item); - - if (SecretsVault.Subscriptions.Count >= 10) - nav.MenuItems.Add(SecretsVault.Subscriptions[9]); + if (SecretsVault.Subscriptions.Count >= 10) + nav.MenuItems.Add(SecretsVault.Subscriptions[9]); + } break; } } private async void AuthorizationStateChanged(object sender, params object[] e) { - switch(e[0] as bool?) + wasInvoked = false; + + switch (e[0] as bool?) { case true: account.Visibility = Visibility.Collapsed; @@ -183,8 +184,7 @@ namespace FoxTube avatar.Visibility = Visibility.Visible; - if(SecretsVault.UserChannel != null) - toChannel.Visibility = Visibility.Visible; + toChannel.Visibility = Visibility.Visible; toSubscriptions.Visibility = Visibility.Visible; libHeader.Visibility = Visibility.Visible; toHistory.Visibility = Visibility.Visible; @@ -198,9 +198,16 @@ namespace FoxTube nav.MenuItems.Add(SecretsVault.Subscriptions[k]); } HistorySet.Load(); + + if (content.Frame.Content != null) + content.Refresh(); + else + content.Frame.Navigate(typeof(Home)); break; case false: + content.Frame.Navigate(typeof(Home)); + for (int k = nav.MenuItems.Count - 1; k > 8; k--) nav.MenuItems.RemoveAt(k); @@ -216,6 +223,9 @@ namespace FoxTube subsHeader.Visibility = Visibility.Collapsed; subsHeader.Visibility = Visibility.Collapsed; + + content.Frame.BackStack.Clear(); + content.Frame.ForwardStack.Clear(); break; default: @@ -237,17 +247,13 @@ namespace FoxTube break; } - await Dispatcher.RunIdleAsync((command) => DownloadAgent.Initialize()); + if (videoPlaceholder.Frame.Content != null) + { + MaximizeVideo(); + videoPlaceholder.Refresh(); + } - wasInvoked = false; - - if (content.Content != null) - content.Navigate(content.CurrentSourcePageType, (content.Content as NavigationPage).Parameter); - else - content.Navigate(typeof(Home)); - - if (videoPlaceholder.Content != null) - GoToVideo((videoPlaceholder.Content as VideoPage).videoId, (videoPlaceholder.Content as VideoPage).playlistId); + DownloadAgent.Initialize(); } private async void Feedback_Click(object sender, RoutedEventArgs e) @@ -262,120 +268,69 @@ namespace FoxTube private void Logout_Click(object sender, RoutedEventArgs e) { + avatar.Flyout.Hide(); SecretsVault.Deauthenticate(); } public void GoToSearch(SearchParameters args) { - nav.IsPaneOpen = false; - content.Navigate(typeof(Search), args); + content.Frame.Navigate(typeof(Search), new object[] { args, content }); } public void GoToChannel(string id) { - content.Navigate(typeof(ChannelPage), id); + content.Frame.Navigate(typeof(ChannelPage), id); } public void GoToHome() { - content.Navigate(typeof(Home)); + content.Frame.Navigate(typeof(Home)); } - public async void GoToVideo(string id, string playlistId = null, bool incognito = false) + public void GoToVideo(string id, string playlistId = null, bool incognito = false) { - if (SettingsStorage.CheckConnection) - try - { - bool cancel = false; - ConnectionCost connection = NetworkInformation.GetInternetConnectionProfile().GetConnectionCost(); - if (connection.NetworkCostType == NetworkCostType.Fixed || connection.NetworkCostType == NetworkCostType.Variable) - { - MessageDialog dialog = new MessageDialog(resources.GetString("/Main/metered")) - { - DefaultCommandIndex = 2, - CancelCommandIndex = 1 - }; - dialog.Commands.Add(new UICommand(resources.GetString("/Main/yes"))); - dialog.Commands.Add(new UICommand(resources.GetString("/Main/no"), (command) => cancel = true)); - if (SecretsVault.IsAuthorized) - dialog.Commands.Add(new UICommand(resources.GetString("/Main/addLater"), (command) => - { - try - { - PlaylistItem item = new PlaylistItem() - { - Snippet = new PlaylistItemSnippet() - { - ResourceId = new ResourceId() - { - Kind = "youtube#video", - VideoId = id - }, - PlaylistId = "WL" - } - }; - - SecretsVault.Service.PlaylistItems.Insert(item, "snippet").Execute(); - } - catch (Exception e) - { - Debug.WriteLine(e.Message); - } - cancel = true; - })); - - await dialog.ShowAsync(); - - if (cancel) - return; - } - } - catch { } - - if (videoPlaceholder.Content != null) - (videoPlaceholder.Content as VideoPage).CloseVideo(); + MaximizeVideo(); nav.IsBackEnabled = true; nav.ExpandedModeThresholdWidth = short.MaxValue; nav.IsPaneOpen = false; - VideoPageSizeChanged?.Invoke(this, true); - videoPlaceholder.Navigate(typeof(VideoPage), new object[3] { id, playlistId, incognito }); + videoPlaceholder.Frame.Navigate(typeof(VideoPage), new object[3] { id, playlistId, incognito }); Title.Text = resources.GetString("/Main/video"); } public void GoToDeveloper(string id) { - content.Navigate(typeof(Settings), id); + content.Frame.Navigate(typeof(Settings), id); } public void GoToPlaylist(string id) { - content.Navigate(typeof(PlaylistPage), id); + content.Frame.Navigate(typeof(PlaylistPage), id); } public void GoToHistory() { - content.Navigate(typeof(History)); + content.Frame.Navigate(typeof(History)); } public void GoToDownloads() { - content.Navigate(typeof(Downloads)); + content.Frame.Navigate(typeof(Downloads)); } public void MinimizeAsInitializer() { - if (videoPlaceholder.Content == null) + if (videoPlaceholder.Frame.Content == null) return; - if ((videoPlaceholder.Content as VideoPage).LoadingPage.State != LoadingState.Loaded) + if (videoPlaceholder.LoadingPage.State != LoadingState.Loaded) CloseVideo(); else - (videoPlaceholder.Content as VideoPage).Player.Minimize(); + (videoPlaceholder.Frame.Content as VideoPage).Player.Minimize(); - Title.Text = headers[content.SourcePageType]; + Title.Text = headers[content.Frame.SourcePageType]; } public void MinimizeVideo() @@ -386,27 +341,28 @@ namespace FoxTube videoPlaceholder.HorizontalAlignment = HorizontalAlignment.Right; videoPlaceholder.Margin = new Thickness(0, 0, 25, 50); - if (content.CanGoBack) + if (content.Frame.CanGoBack) nav.IsBackEnabled = true; else nav.IsBackEnabled = false; - VideoPageSizeChanged?.Invoke(this, false); - SetNavigationMenu(); - Title.Text = headers[content.SourcePageType]; + Title.Text = headers[content.Frame.SourcePageType]; } void SetNavigationMenu() { - if (content.SourcePageType == typeof(Home) || content.SourcePageType == typeof(Settings) || content.SourcePageType == typeof(Subscriptions)) + if (content.Frame.SourcePageType == typeof(Home) || content.Frame.SourcePageType == typeof(Settings) || content.Frame.SourcePageType == typeof(Subscriptions)) { nav.ExpandedModeThresholdWidth = 1008; nav.IsPaneOpen = nav.DisplayMode == Microsoft.UI.Xaml.Controls.NavigationViewDisplayMode.Expanded ? true : false; } else + { nav.ExpandedModeThresholdWidth = short.MaxValue; + nav.IsPaneOpen = false; + } } public void MaximizeVideo() @@ -417,15 +373,13 @@ namespace FoxTube videoPlaceholder.HorizontalAlignment = HorizontalAlignment.Stretch; videoPlaceholder.Margin = new Thickness(0); - if (videoPlaceholder.Content == null) + if (videoPlaceholder.Frame.Content == null) return; nav.IsBackEnabled = true; Title.Text = resources.GetString("/Main/video"); nav.ExpandedModeThresholdWidth = short.MaxValue; nav.IsPaneOpen = false; - - VideoPageSizeChanged?.Invoke(this, true); } public void CloseVideo() @@ -433,20 +387,15 @@ namespace FoxTube if (ApplicationView.GetForCurrentView().IsFullScreenMode) ApplicationView.GetForCurrentView().ExitFullScreenMode(); - videoPlaceholder.Content = null; + videoPlaceholder.Frame.Content = null; GC.Collect(); MaximizeVideo(); - if (content.CanGoBack) - nav.IsBackEnabled = true; - else - nav.IsBackEnabled = false; - - VideoPageSizeChanged?.Invoke(this, false); + nav.IsBackEnabled = content.Frame.CanGoBack; SetNavigationMenu(); - Title.Text = headers[content.SourcePageType]; + Title.Text = headers[content.Frame.SourcePageType]; } private void Search_QuerySubmitted(AutoSuggestBox sender, AutoSuggestBoxQuerySubmittedEventArgs args) @@ -464,7 +413,7 @@ namespace FoxTube try { XmlDocument doc = new XmlDocument(); - doc.Load($"http://suggestqueries.google.com/complete/search?ds=yt&client=toolbar&q={search.Text}"); + doc.Load($"http://suggestqueries.google.com/complete/search?ds=yt&client=toolbar&q={search.Text}&hl={SettingsStorage.RelevanceLanguage}"); List suggestions = new List(); @@ -492,7 +441,7 @@ namespace FoxTube public void Content_Navigated(object sender, NavigationEventArgs e) { - Title.Text = headers[content.SourcePageType]; + Title.Text = headers[content.Frame.SourcePageType]; if (!wasInvoked) { @@ -508,12 +457,17 @@ namespace FoxTube SetNavigationItem(toHome); else if (e.SourcePageType == typeof(Search)) SetNavigationItem(null); - else if(e.SourcePageType == typeof(ChannelPage) && SecretsVault.IsAuthorized) + else if(e.SourcePageType == typeof(ChannelPage)) { - if (e.Parameter.ToString() == SecretsVault.AccountId) - SetNavigationItem(toChannel); - else if (nav.MenuItems.Contains(SecretsVault.Subscriptions.Find(i => i.Snippet.ResourceId.ChannelId == e.Parameter.ToString()))) - SetNavigationItem(SecretsVault.Subscriptions.Find(i => i.Snippet.ResourceId.ChannelId == e.Parameter.ToString())); + if (SecretsVault.IsAuthorized) + { + if (e.Parameter.ToString() == SecretsVault.AccountId) + SetNavigationItem(toChannel); + else if (nav.MenuItems.Contains(SecretsVault.Subscriptions.Find(i => i.Snippet.ResourceId.ChannelId == e.Parameter.ToString()))) + SetNavigationItem(SecretsVault.Subscriptions.Find(i => i.Snippet.ResourceId.ChannelId == e.Parameter.ToString())); + else + SetNavigationItem(null); + } else SetNavigationItem(null); } @@ -521,87 +475,79 @@ namespace FoxTube SetNavigationItem(toHistory); else if(e.SourcePageType == typeof(PlaylistPage)) { - if (e.Parameter.ToString() == SecretsVault.UserChannel.ContentDetails.RelatedPlaylists.Likes) - SetNavigationItem(toLiked); - else if (e.Parameter.Equals("WL")) - SetNavigationItem(toLater); + if (SecretsVault.IsAuthorized) + { + if (e.Parameter.ToString() == SecretsVault.UserChannel.ContentDetails.RelatedPlaylists.Likes) + SetNavigationItem(toLiked); + else if (e.Parameter.Equals("WL")) + SetNavigationItem(toLater); + } + else + SetNavigationItem(null); } } else wasInvoked = false; - if (content.CanGoBack) - nav.IsBackEnabled = true; - else - nav.IsBackEnabled = false; + nav.IsBackEnabled = content.Frame.CanGoBack; SetNavigationMenu(); - if (videoPlaceholder.Content != null && videoPlaceholder.HorizontalAlignment == HorizontalAlignment.Stretch) + if (videoPlaceholder.Frame.Content != null && videoPlaceholder.HorizontalAlignment == HorizontalAlignment.Stretch) MinimizeAsInitializer(); } - private void OpenContext(object sender, TappedRoutedEventArgs e) - { - ((Microsoft.UI.Xaml.Controls.NavigationViewItem)sender).ContextFlyout.ShowAt((Microsoft.UI.Xaml.Controls.NavigationViewItem)sender); - } - private void RemoveAds_Tapped(object sender, TappedRoutedEventArgs e) { SecretsVault.GetAdblock(); } - private void Web_Tapped(object sender, TappedRoutedEventArgs e) - { - content.Navigate(typeof(Home1)); - } - private void Nav_SelectionChanged(Microsoft.UI.Xaml.Controls.NavigationView sender, Microsoft.UI.Xaml.Controls.NavigationViewSelectionChangedEventArgs args) { - try + if (!wasInvoked) { - if (!wasInvoked) - { - wasInvoked = true; - if (args.IsSettingsSelected) - content.Navigate(typeof(Settings)); - else - { - 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), "WL"); - 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), (args.SelectedItem as Subscription).Snippet.ResourceId.ChannelId); - } - } + if (content == null) + return; + wasInvoked = true; + if (args.IsSettingsSelected) + content.Frame.Navigate(typeof(Settings)); else - wasInvoked = false; + { + if (args.SelectedItem == toHome) + content.Frame.Navigate(typeof(Home)); + else if (args.SelectedItem == toHistory) + content.Frame.Navigate(typeof(History)); + else if (args.SelectedItem == toLiked) + content.Frame.Navigate(typeof(PlaylistPage), SecretsVault.UserChannel.ContentDetails.RelatedPlaylists.Likes); + else if (args.SelectedItem == toLater) + content.Frame.Navigate(typeof(PlaylistPage), "WL"); + else if (args.SelectedItem == toSubscriptions) + content.Frame.Navigate(typeof(Subscriptions)); + else if (args.SelectedItem == toDownloads) + content.Frame.Navigate(typeof(Downloads)); + else if (args.SelectedItem == toChannel) + content.Frame.Navigate(typeof(ChannelPage), SecretsVault.UserChannel.Id); + else + content.Frame.Navigate(typeof(ChannelPage), (args.SelectedItem as Subscription).Snippet.ResourceId.ChannelId); + } } - catch { } + else + wasInvoked = false; } private void Nav_BackRequested(Microsoft.UI.Xaml.Controls.NavigationView sender, Microsoft.UI.Xaml.Controls.NavigationViewBackRequestedEventArgs args) { - if (videoPlaceholder.Content != null && videoPlaceholder.Width == double.NaN) + if (videoPlaceholder.Frame.Content != null && double.IsNaN(videoPlaceholder.Width)) { - if ((videoPlaceholder.Content as VideoPage).LoadingPage.State != LoadingState.Loaded) + if (videoPlaceholder.Frame.CanGoBack) + videoPlaceholder.Frame.GoBack(); + else if (videoPlaceholder.LoadingPage.State != LoadingState.Loaded) CloseVideo(); - else if (videoPlaceholder.HorizontalAlignment == HorizontalAlignment.Stretch) + else MinimizeAsInitializer(); } else - content.GoBack(); + content.Frame.GoBack(); } private void Nav_PaneClosing(Microsoft.UI.Xaml.Controls.NavigationView sender, Microsoft.UI.Xaml.Controls.NavigationViewPaneClosingEventArgs args) @@ -612,11 +558,6 @@ namespace FoxTube private void Nav_PaneOpened(Microsoft.UI.Xaml.Controls.NavigationView sender, object args) { AppTitle.Visibility = Visibility.Visible; - - if (sender.DisplayMode == Microsoft.UI.Xaml.Controls.NavigationViewDisplayMode.Expanded && sender.IsPaneOpen) - AppTitleBar.Margin = new Thickness(40, 0, 0, 0); - else - AppTitleBar.Margin = new Thickness(); } } } diff --git a/FoxTube/Pages/PlaylistPage.xaml b/FoxTube/Pages/PlaylistPage.xaml index fb2db57..7de6904 100644 --- a/FoxTube/Pages/PlaylistPage.xaml +++ b/FoxTube/Pages/PlaylistPage.xaml @@ -5,7 +5,6 @@ xmlns:local="using:FoxTube.Pages" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:foxtube="using:FoxTube" xmlns:controls="using:FoxTube.Controls" mc:Ignorable="d" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> @@ -40,19 +39,19 @@ - + - @@ -76,7 +75,7 @@ - + @@ -89,7 +88,5 @@ - - diff --git a/FoxTube/Pages/PlaylistPage.xaml.cs b/FoxTube/Pages/PlaylistPage.xaml.cs index d404e62..93f5154 100644 --- a/FoxTube/Pages/PlaylistPage.xaml.cs +++ b/FoxTube/Pages/PlaylistPage.xaml.cs @@ -19,7 +19,7 @@ namespace FoxTube.Pages /// /// Playlist page /// - public sealed partial class PlaylistPage : Page, NavigationPage + public sealed partial class PlaylistPage : Page, INavigationPage { public object Parameter { get; set; } = null; public string playlistId; @@ -32,17 +32,14 @@ namespace FoxTube.Pages public PlaylistPage() { InitializeComponent(); - - DataTransferManager.GetForCurrentView().DataRequested += new TypedEventHandler(Share); } protected override void OnNavigatedTo(NavigationEventArgs e) { base.OnNavigatedTo(e); Parameter = e.Parameter; - if (e.Parameter == null) - loading.Error("NullReferenceException", "Unable to initialize page. Playlist ID is not stated."); - else if (e.Parameter as string == "WL") + + if (e.Parameter as string == "WL") LoadWL(); else Initialize(e.Parameter as string); @@ -50,8 +47,6 @@ namespace FoxTube.Pages public async void Initialize(string id) { - loading.Refresh(); - try { playlistId = id; @@ -66,16 +61,10 @@ namespace FoxTube.Pages info.Text = $"{item.ContentDetails.ItemCount} {ResourceLoader.GetForCurrentView("Playlist").GetString("/Playlist/videos")}"; description.Text = item.Snippet.Localized.Description; - channelName.Text = item.Snippet.ChannelTitle; - - ChannelsResource.ListRequest channelRequest = SecretsVault.Service.Channels.List("snippet"); - channelRequest.Id = item.Snippet.ChannelId; - Channel channel = (await channelRequest.ExecuteAsync()).Items[0]; + channelName.Text = Methods.GuardFromNull(item.Snippet.ChannelTitle); - try { avatar.ProfilePicture = new BitmapImage(channel.Snippet.Thumbnails.Medium.Url.ToUri()) { DecodePixelWidth = 50, DecodePixelHeight = 50 }; } - catch { } - try { thumbnail.Source = new BitmapImage(item.Snippet.Thumbnails.Medium.Url.ToUri()); } - catch { } + avatar.ProfilePicture = new BitmapImage((await new YoutubeExplode.YoutubeClient().GetChannelAsync(item.Snippet.ChannelId)).LogoUrl.ToUri()) { DecodePixelWidth = 50, DecodePixelHeight = 50 }; + thumbnail.Source = new BitmapImage(item.Snippet.Thumbnails.Medium.Url.ToUri()); request = SecretsVault.Service.PlaylistItems.List("contentDetails"); request.PlaylistId = id; @@ -89,15 +78,15 @@ namespace FoxTube.Pages foreach (PlaylistItem i in response.Items) list.Add(new VideoCard(i.ContentDetails.VideoId, playlistId)); - loading.Close(); + Methods.MainPage.PageContent.LoadingPage.Close(); } catch (System.Net.Http.HttpRequestException) { - loading.Error("System.Net.Http.HttpRequestException", "Unable to connect to Google servers.", true); + Methods.MainPage.PageContent.LoadingPage.Error("System.Net.Http.HttpRequestException", "Unable to connect to Google servers.", true); } catch (Exception e) { - loading.Error(e.GetType().ToString(), e.Message); + Methods.MainPage.PageContent.LoadingPage.Error(e.GetType().ToString(), e.Message); Analytics.TrackEvent("Playlist loading error", new Dictionary() { { "Exception", e.GetType().ToString() }, @@ -109,8 +98,6 @@ namespace FoxTube.Pages public async void LoadWL() { - loading.Refresh(); - try { playlistId = "WL"; @@ -125,10 +112,8 @@ namespace FoxTube.Pages channelName.Text = SecretsVault.UserChannel.Snippet.Title; - try { avatar.ProfilePicture = new BitmapImage(SecretsVault.UserChannel.Snippet.Thumbnails.Medium.Url.ToUri()) { DecodePixelWidth = 50, DecodePixelHeight = 50 }; } - catch { } - try { thumbnail.Source = new BitmapImage((await new YoutubeExplode.YoutubeClient().GetVideoAsync(SecretsVault.WatchLater.First())).Thumbnails.HighResUrl.ToUri()); } - catch { } + avatar.ProfilePicture = new BitmapImage(SecretsVault.UserChannel.Snippet.Thumbnails.Medium.Url.ToUri()) { DecodePixelWidth = 50, DecodePixelHeight = 50 }; + thumbnail.Source = new BitmapImage((await new YoutubeExplode.YoutubeClient().GetVideoAsync(SecretsVault.WatchLater.First())).Thumbnails.HighResUrl.ToUri()); for (int k = 0; k < 25 && k < SecretsVault.WatchLater.Count; k++) list.Add(new VideoCard(SecretsVault.WatchLater[k], "WL")); @@ -136,11 +121,11 @@ namespace FoxTube.Pages if (list.Count >= SecretsVault.WatchLater.Count) more.Visibility = Visibility.Collapsed; - loading.Close(); + Methods.MainPage.PageContent.LoadingPage.Close(); } catch (Exception e) { - loading.Error(e.GetType().ToString(), e.Message); + Methods.MainPage.PageContent.LoadingPage.Error(e.GetType().ToString(), e.Message); Analytics.TrackEvent("WL playlist loading error", new Dictionary() { { "Exception", e.GetType().ToString() }, @@ -161,11 +146,12 @@ namespace FoxTube.Pages private void refresh_Click(object sender, RoutedEventArgs e) { - Methods.MainPage.GoToPlaylist(playlistId); + Methods.MainPage.VideoContent.Refresh(); } private void share_Click(object sender, RoutedEventArgs e) { + DataTransferManager.GetForCurrentView().DataRequested += new TypedEventHandler(Share); DataTransferManager.ShowShareUI(); } diff --git a/FoxTube/Pages/Search.xaml b/FoxTube/Pages/Search.xaml index ff7ff98..76ad1e6 100644 --- a/FoxTube/Pages/Search.xaml +++ b/FoxTube/Pages/Search.xaml @@ -76,7 +76,5 @@ - - diff --git a/FoxTube/Pages/Search.xaml.cs b/FoxTube/Pages/Search.xaml.cs index 1981774..cae9394 100644 --- a/FoxTube/Pages/Search.xaml.cs +++ b/FoxTube/Pages/Search.xaml.cs @@ -16,11 +16,12 @@ namespace FoxTube /// /// Search page /// - public sealed partial class Search : Page, NavigationPage + public sealed partial class Search : Page, INavigationPage { public object Parameter { get; set; } = null; readonly ResourceLoader resources = ResourceLoader.GetForCurrentView("Search"); + ContentFrame frame; public SearchParameters Parameters; SearchResource.ListRequest request; string nextToken; @@ -65,21 +66,13 @@ namespace FoxTube { base.OnNavigatedTo(e); Parameter = e.Parameter; - if (e.Parameter == null) - loading.Error("NullReferenceException", "Unable to initialize search. Search term is not stated."); - else - { - if (e.Parameter is SearchParameters) - Initialize(e.Parameter as SearchParameters); - else - loading.Error("ArgumentException", "Wrong parameter"); - } + + frame = ((object[])e.Parameter)[1] as ContentFrame; + Initialize(((object[])e.Parameter)[0] as SearchParameters); } public async void Initialize(SearchParameters arg) { - loading.Refresh(); - try { Parameters = arg; @@ -129,6 +122,7 @@ namespace FoxTube SearchListResponse response = await request.ExecuteAsync(); searchTerm.Text = $"{resources.GetString("/Search/header")} '{Parameters.Term}'"; resultsCount.Text = $"{resources.GetString("/Search/found")}: {SetResults(response.PageInfo.TotalResults)} {resources.GetString("/Search/items")}"; + if (!string.IsNullOrWhiteSpace(response.NextPageToken)) nextToken = response.NextPageToken; else @@ -138,15 +132,15 @@ namespace FoxTube foreach (SearchResult item in response.Items) AddItem(item); - loading.Close(); + frame.LoadingPage.Close(); } catch (System.Net.Http.HttpRequestException) { - loading.Error("System.Net.Http.HttpRequestException", "Unable to connect to Google servers.", true); + frame.LoadingPage.Error("System.Net.Http.HttpRequestException", "Unable to connect to Google servers.", true); } catch (Exception e) { - loading.Error(e.GetType().ToString(), e.Message); + frame.LoadingPage.Error(e.GetType().ToString(), e.Message); Analytics.TrackEvent("Search loading error", new Dictionary() { { "Exception", e.GetType().ToString() }, @@ -172,7 +166,7 @@ namespace FoxTube private void AppBarButton_Click(object sender, RoutedEventArgs e) { - Methods.MainPage.GoToSearch(Parameters); + frame.Refresh(); } private async void More_Clicked() diff --git a/FoxTube/Pages/Settings.xaml b/FoxTube/Pages/Settings.xaml index caa0dcd..92b0b35 100644 --- a/FoxTube/Pages/Settings.xaml +++ b/FoxTube/Pages/Settings.xaml @@ -9,19 +9,19 @@ - + - + - + - + diff --git a/FoxTube/Pages/Settings.xaml.cs b/FoxTube/Pages/Settings.xaml.cs index fcb9fab..8a4d4c3 100644 --- a/FoxTube/Pages/Settings.xaml.cs +++ b/FoxTube/Pages/Settings.xaml.cs @@ -7,9 +7,10 @@ namespace FoxTube /// /// Settings tabs placeholder /// - public sealed partial class Settings : Page, NavigationPage + public sealed partial class Settings : Page, INavigationPage { public object Parameter { get; set; } = null; + bool inboxLoaded = false; string inboxId = null; public Settings() @@ -21,24 +22,29 @@ namespace FoxTube { base.OnNavigatedTo(e); Parameter = e.Parameter; - if (!string.IsNullOrWhiteSpace(e.Parameter as string)) - { - inboxId = e.Parameter as string; - pivot.SelectedIndex = 2; - } + + if(!string.IsNullOrWhiteSpace((string)e.Parameter)) + switch((string)e.Parameter) + { + case "about": + pivot.SelectedItem = aboutTab; + break; + default: + inboxId = (string)e.Parameter; + pivot.SelectedItem = inboxTab; + break; + } + + Methods.MainPage.PageContent.LoadingPage.Close(); } private void Pivot_SelectionChanged(object sender, SelectionChangedEventArgs e) { - if (pivot.SelectedIndex == 2 && !inboxLoaded) + if (pivot.SelectedItem == inboxTab && !inboxLoaded) { - (((pivot.Items[2] as PivotItem).Content as ScrollViewer).Content as Inbox).LoadItems(); + inbox.LoadItems(inboxId); inboxLoaded = true; - if(inboxId != null) - { - (((pivot.Items[2] as PivotItem).Content as ScrollViewer).Content as Inbox).Open(inboxId as string); - inboxId = null; - } + inboxId = null; } } } diff --git a/FoxTube/Pages/SettingsPages/About.xaml b/FoxTube/Pages/SettingsPages/About.xaml index 761ec62..0f7471f 100644 --- a/FoxTube/Pages/SettingsPages/About.xaml +++ b/FoxTube/Pages/SettingsPages/About.xaml @@ -7,48 +7,27 @@ mc:Ignorable="d" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> - - - - - - - + + + - - - - - - - - - - + + - - - + + Twitter: @xfox111 + Vkontakte: @XFox.Mike + YouTube: @xfox + E-mail: michael.xfox@outlook.com + My website: https://michael-xfox.com - - - - - Twitter: @XFox_Mike - Vkontakte: @XFox.Mike - YouTube: @FoxGameStudioChannel - E-mail: michael.xfox@outlook.com - My blog (Russian language only): https://michael-xfox.com - - - - - - - - - public sealed partial class Inbox : Page { - List items = new List(); + readonly List items = new List(); - string open; public Inbox() { InitializeComponent(); } - public async void LoadItems() + public async void LoadItems(string id = null) { try { XmlDocument doc = new XmlDocument(); - - StorageFile file = await (await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFolderAsync(@"Assets\Data")).GetFileAsync("Patchnotes.xml"); + + StorageFile file = await StorageFile.GetFileFromApplicationUriAsync("ms-appx:///Assets/Data/Patchnotes.xml".ToUri()); doc.Load(await file.OpenStreamForReadAsync()); foreach (XmlElement e in doc["items"].ChildNodes) items.Add(new InboxItem( e.GetAttribute("version"), e["content"][SettingsStorage.Language].InnerText, - e.GetAttribute("time"))); + DateTime.Parse(e.GetAttribute("time")))); doc.Load("http://foxgame-studio.000webhostapp.com/foxtube-messages.xml"); foreach (XmlElement e in doc["posts"].ChildNodes) @@ -43,59 +43,55 @@ namespace FoxTube.Pages.SettingsPages e["header"][SettingsStorage.Language].InnerText, e["content"][SettingsStorage.Language].InnerText, DateTime.Parse(e.GetAttribute("time")), - e["id"].InnerText - )); - - items.OrderBy(item => item.TimeStamp); + e["id"].InnerText)); + } + catch (Exception e) + { + Analytics.TrackEvent("Failed to load inbox", new Dictionary + { + { "Exception", e.GetType().ToString() }, + { "Message", e.Message } + }); } - catch { } + items.OrderBy(item => item.TimeStamp); items.ForEach(i => list.Items.Add(i)); - if (!string.IsNullOrWhiteSpace(open)) - Open(open); - - open = null; + if (!string.IsNullOrWhiteSpace(id)) + list.SelectedItem = items.Find(i => i.Id == id); } private void filter_SelectionChanged(object sender, SelectionChangedEventArgs e) { - try + if (list == null) + return; + + list.Items.Clear(); + + switch (filter.SelectedIndex) { - list.Items.Clear(); + case 0: + items.ForEach(i => list.Items.Add(i)); + break; - switch (filter.SelectedIndex) - { - case 0: - items.ForEach(i => list.Items.Add(i)); - break; + case 1: + List messages = items.FindAll(i => i.Type == InboxItemType.Default); + messages.ForEach(i => list.Items.Add(i)); + break; - case 1: - List messages = items.FindAll(i => i.Type == InboxItemType.Default); - messages.ForEach(i => list.Items.Add(i)); - break; - - case 2: - List notes = items.FindAll(i => i.Type == InboxItemType.PatchNote); - notes.ForEach(i => list.Items.Add(i)); - break; - } + case 2: + List notes = items.FindAll(i => i.Type == InboxItemType.PatchNote); + notes.ForEach(i => list.Items.Add(i)); + break; } - catch(NullReferenceException) { } } private void list_SelectionChanged(object sender, SelectionChangedEventArgs e) { - InboxItem item = list.SelectedItem as InboxItem; - if(list.SelectedItem != null) - { - OpenView(item.Title, item.Content); - if (grid.ColumnDefinitions[1].Width.Value == 0) - { - grid.ColumnDefinitions[0].Width = new GridLength(0); - grid.ColumnDefinitions[1].Width = new GridLength(1, GridUnitType.Star); - } - } + if (!(list.SelectedItem is InboxItem item)) + return; + + OpenView(item.Title, item.Content); } void CloseView() @@ -104,6 +100,12 @@ namespace FoxTube.Pages.SettingsPages title.Text = ""; list.SelectedItem = null; block.Visibility = Visibility.Visible; + + if (grid.ColumnDefinitions[0].Width.Value == 0) + { + grid.ColumnDefinitions[1].Width = new GridLength(0); + grid.ColumnDefinitions[0].Width = new GridLength(1, GridUnitType.Star); + } } void OpenView(string header, string body) @@ -111,29 +113,23 @@ namespace FoxTube.Pages.SettingsPages content.Text = body; title.Text = header; block.Visibility = Visibility.Collapsed; + + if (grid.ColumnDefinitions[1].Width.Value == 0) + { + grid.ColumnDefinitions[0].Width = new GridLength(0); + grid.ColumnDefinitions[1].Width = new GridLength(1, GridUnitType.Star); + } } private void close_Click(object sender, RoutedEventArgs e) { CloseView(); - if (grid.ColumnDefinitions[0].Width.Value == 0) - { - grid.ColumnDefinitions[0].Width = new GridLength(1, GridUnitType.Star); - grid.ColumnDefinitions[1].Width = new GridLength(0); - } } - public void Open(string arg) + private void VisualStateGroup_CurrentStateChanged(object sender, VisualStateChangedEventArgs e) { - if(items.Count == 0) - { - open = arg; - return; - } - - InboxItem item = items.Find(i => i.Id == arg); - if(item != null) - list.SelectedItem = item; + if (e.NewState == null) + CloseView(); } } } diff --git a/FoxTube/Pages/Subscriptions.xaml b/FoxTube/Pages/Subscriptions.xaml index bac59c9..db544e9 100644 --- a/FoxTube/Pages/Subscriptions.xaml +++ b/FoxTube/Pages/Subscriptions.xaml @@ -4,34 +4,30 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:foxtube="using:FoxTube" xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls" mc:Ignorable="d" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> - - - - - - - - - - - - + + + + + + + + + diff --git a/FoxTube/Pages/Subscriptions.xaml.cs b/FoxTube/Pages/Subscriptions.xaml.cs index 503f1ba..cf72369 100644 --- a/FoxTube/Pages/Subscriptions.xaml.cs +++ b/FoxTube/Pages/Subscriptions.xaml.cs @@ -8,13 +8,15 @@ namespace FoxTube.Pages /// /// User's subscriptions page /// - public sealed partial class Subscriptions : Page, NavigationPage + public sealed partial class Subscriptions : Page, INavigationPage { public object Parameter { get; set; } = null; readonly List list = SecretsVault.Subscriptions; public Subscriptions() { InitializeComponent(); + + Methods.MainPage.PageContent.LoadingPage.Close(); } private void Button_Click(object sender, RoutedEventArgs e) diff --git a/FoxTube/Pages/VideoGrid.xaml b/FoxTube/Pages/VideoGrid.xaml index fc7e54e..22868ef 100644 --- a/FoxTube/Pages/VideoGrid.xaml +++ b/FoxTube/Pages/VideoGrid.xaml @@ -4,22 +4,17 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:ui="using:Microsoft.Toolkit.Uwp.UI.Controls" mc:Ignorable="d"> - - - - - - - - - - - - - - - + + + + + + + + + diff --git a/FoxTube/Pages/VideoGrid.xaml.cs b/FoxTube/Pages/VideoGrid.xaml.cs index b36012e..3d17e1a 100644 --- a/FoxTube/Pages/VideoGrid.xaml.cs +++ b/FoxTube/Pages/VideoGrid.xaml.cs @@ -1,5 +1,5 @@ -using FoxTube.Controls.Adverts; -using System.Collections.Generic; +using FoxTube.Controls; +using FoxTube.Controls.Adverts; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; @@ -10,19 +10,9 @@ namespace FoxTube.Pages /// public sealed partial class VideoGrid : Page { - public int Columns - { - get { return cols; } - set - { - cols = value; - UpdateGrid(); - } - } - private int cols = 1; - public int Count => Children.Count; - public bool IsRelatedVideos { get; set; } = false; - public List Children { get; } = new List(); + public int Count => list.Items.Count; + public ItemCollection Children => list.Items; + private int ItemsCount => Children.FindAll(i => i is VideoCard).Count + Children.FindAll(i => i is ChannelCard).Count + Children.FindAll(i => i is PlaylistCard).Count + Children.FindAll(i => i is CardAdvert).Count; public VideoGrid() { @@ -31,60 +21,21 @@ namespace FoxTube.Pages public void Add(UIElement card) { - (grid.Children[Count % cols + 1] as StackPanel).Children.Add(card); - Children.Add(card); - - if ((Children.Count - 5) % 25 == 0 && !SecretsVault.AdsDisabled) - { - CardAdvert advert = new CardAdvert(IsRelatedVideos); - (grid.Children[Count % cols + 1] as StackPanel).Children.Add(advert); - Children.Add(advert); - } - + list.Items.Add(card); + if ((list.Items.Count - 5) % 25 == 0) + list.Items.Add(new CardAdvert()); empty.Visibility = Visibility.Collapsed; } public void Clear() { - for (int k = 1; k <= 5; k++) - (grid.Children[k] as StackPanel).Children.Clear(); - + list.Items.Clear(); empty.Visibility = Visibility.Visible; } public void DeleteItem(FrameworkElement item) { Children.Remove(item); - UpdateGrid(); - } - - void UpdateGrid() - { - for (int k = 1; k <= 5; k++) - (grid.Children[k] as StackPanel).Children.Clear(); - - for (int k = 0; k < Count; k++) - (grid.Children[k % cols + 1] as StackPanel).Children.Add(Children[k]); - - for (int k = 0; k < cols; k++) - grid.ColumnDefinitions[k].Width = new GridLength(1, GridUnitType.Star); - - for (int k = cols; k < 5; k++) - grid.ColumnDefinitions[k].Width = new GridLength(0); - } - - private void Grid_SizeChanged(object sender, SizeChangedEventArgs e) - { - if (e.NewSize.Width >= 1600 && Columns != 5) - Columns = 5; - else if (e.NewSize.Width >= 1200 && e.NewSize.Width < 1600 && Columns != 4) - Columns = 4; - else if (e.NewSize.Width >= 900 && e.NewSize.Width < 1200 && Columns != 3) - Columns = 3; - else if (e.NewSize.Width >= 550 && e.NewSize.Width < 900 && Columns != 2) - Columns = 2; - else if (e.NewSize.Width < 550 && Columns != 1) - Columns = 1; } } } diff --git a/FoxTube/Pages/VideoPage.xaml b/FoxTube/Pages/VideoPage.xaml index c303df7..c22efef 100644 --- a/FoxTube/Pages/VideoPage.xaml +++ b/FoxTube/Pages/VideoPage.xaml @@ -29,8 +29,8 @@ - - + + @@ -125,10 +125,10 @@ - + - + @@ -174,7 +174,5 @@ - - diff --git a/FoxTube/Pages/VideoPage.xaml.cs b/FoxTube/Pages/VideoPage.xaml.cs index bfc9be7..335c165 100644 --- a/FoxTube/Pages/VideoPage.xaml.cs +++ b/FoxTube/Pages/VideoPage.xaml.cs @@ -42,11 +42,12 @@ namespace FoxTube.Pages /// /// Video page /// - public sealed partial class VideoPage : Page + public sealed partial class VideoPage : Page, INavigationPage { ResourceLoader resources = ResourceLoader.GetForCurrentView("VideoPage"); - public string videoId; + public object Parameter { get; set; } = null; + public string playlistId = null; public Video item; public HistoryItem history; @@ -59,14 +60,11 @@ namespace FoxTube.Pages DispatcherTimer liveTimer; DispatcherTimer countdownTimer; - public LoadingPage LoadingPage => loading; public VideoPlayer Player => player; public VideoPage() { InitializeComponent(); - - DataTransferManager.GetForCurrentView().DataRequested += new TypedEventHandler(Share); if (Window.Current.Bounds.Width <= 1000) { @@ -78,14 +76,12 @@ namespace FoxTube.Pages mainContent.Children.Add(pivot); grid.ColumnDefinitions[1].Width = new GridLength(0); - - pivot.SelectedIndex = 0; } } private void Player_NextClicked() { - if (playlistId != null) + if (playlistId != null && playlistList.SelectedIndex + 1 < playlistList.Items.Count) playlistList.SelectedIndex++; else (relatedVideos.Children[0] as VideoCard).Button_Click(this, null); @@ -94,19 +90,15 @@ namespace FoxTube.Pages protected override void OnNavigatedTo(NavigationEventArgs e) { base.OnNavigatedTo(e); - if (e.Parameter == null) - loading.Error("NullReferenceException", "Unable to initialize page. Video ID is not stated."); - else - Initialize(e.Parameter as object[]); + Parameter = e.Parameter; + + Initialize(e.Parameter as object[]); } public async void Initialize(object[] ids) { - loading.Refresh(); - try { - videoId = ids[0] as string; incognito = (bool)ids[2]; if (ids[1] != null) @@ -130,27 +122,26 @@ namespace FoxTube.Pages LoadInfo(); LoadAddTo(); - loading.Close(); + Methods.MainPage.VideoContent.LoadingPage.Close(); } catch (System.Net.Http.HttpRequestException) { - loading.Error("System.Net.Http.HttpRequestException", "Unable to connect to Google servers.", true); + Methods.MainPage.VideoContent.LoadingPage.Error("System.Net.Http.HttpRequestException", "Unable to connect to Google servers.", true); } catch (Exception e) { - loading.Error(e.GetType().ToString(), e.Message); + Methods.MainPage.VideoContent.LoadingPage.Error(e.GetType().ToString(), e.Message); Analytics.TrackEvent("Video loading error", new Dictionary() { { "Exception", e.GetType().ToString() }, { "Message", e.Message }, - { "Video ID", videoId } + { "Video ID", item.Id } }); } } void SetSchedule() { - views.Visibility = Visibility.Collapsed; upcoming.Visibility = Visibility.Visible; if (item.LiveStreamingDetails.ScheduledEndTime.HasValue || item.LiveStreamingDetails.ScheduledStartTime.HasValue) schedule.Visibility = Visibility.Visible; @@ -208,7 +199,6 @@ namespace FoxTube.Pages } else { - //Retrieving data PlaylistsResource.ListRequest playlistRequest = SecretsVault.Service.Playlists.List("snippet,contentDetails"); playlistRequest.Id = id; @@ -237,7 +227,7 @@ namespace FoxTube.Pages //Setting data playlistName.Text = playlistItem.Snippet.Localized.Title; - playlistChannel.Text = playlistItem.Snippet.ChannelTitle; + playlistChannel.Text = Methods.GuardFromNull(playlistItem.Snippet.ChannelTitle); playlistCounter.Text = $"{items.IndexOf(selection) + 1}/{playlistItem.ContentDetails.ItemCount}"; } @@ -249,9 +239,6 @@ namespace FoxTube.Pages await Task.Delay(500); playlistScroll.ChangeView(null, playlistList.SelectedIndex * 86 + 89, null, true); - - if (playlistList.SelectedIndex == playlistList.Items.Count - 1) - player.Controls.IsNextTrackButtonVisible = false; } async void LoadInfo() @@ -259,7 +246,7 @@ namespace FoxTube.Pages //Setting meta title.Text = item.Snippet.Localized.Title; date.Text = $"{resources.GetString("/VideoPage/publishedAt")}: {item.Snippet.PublishedAt} ({Methods.GetAgo(item.Snippet.PublishedAt.Value)})"; - Methods.FormatText(ref description, item.Snippet.Localized.Description); + description.FormatText(item.Snippet.Localized.Description); //Setting channel button ChannelsResource.ListRequest channelRequest = SecretsVault.Service.Channels.List("snippet, statistics"); @@ -278,28 +265,24 @@ namespace FoxTube.Pages //Setting User's rate if (SecretsVault.IsAuthorized) { - VideoGetRatingResponse ratingResponse = await SecretsVault.Service.Videos.GetRating(videoId).ExecuteAsync(); - if (ratingResponse.Items[0].Rating == "like") + VideoRating rating = (await SecretsVault.Service.Videos.GetRating(item.Id).ExecuteAsync()).Items[0]; + if (rating.Rating == "like") { userRating = Rating.Like; like.Foreground = new SolidColorBrush(Colors.Green); } - else if (ratingResponse.Items[0].Rating == "dislike") + else if (rating.Rating == "dislike") { userRating = Rating.Dislike; dislike.Foreground = new SolidColorBrush(Colors.Red); } - foreach (Subscription s in SecretsVault.Subscriptions) + if(SecretsVault.Subscriptions.Exists(i => i.Snippet.ResourceId.ChannelId == item.Snippet.ChannelId)) { - if (s.Snippet.ResourceId.ChannelId == item.Snippet.ChannelId) - { - subscribe.Background = new SolidColorBrush(Colors.Transparent); - subscribe.Foreground = new SolidColorBrush(Colors.Gray); - subscribe.Content = resources.GetString("/Cards/unsubscribe"); - } + subscribe.Background = new SolidColorBrush(Colors.Transparent); + subscribe.Foreground = new SolidColorBrush(Colors.Gray); + subscribe.Content = resources.GetString("/Cards/unsubscribe"); } - subscribe.Visibility = Visibility.Visible; } else { @@ -308,9 +291,9 @@ namespace FoxTube.Pages subscribe.Visibility = Visibility.Collapsed; } - if(HistorySet.Items.Exists(i => i.Id == videoId) && HistorySet.Items.Find(i => i.Id == videoId).LeftOn.TotalSeconds >= 30 && Methods.GetDuration(item.ContentDetails.Duration).TotalSeconds - HistorySet.Items.Find(i => i.Id == videoId).LeftOn.TotalSeconds >= 30) + + if ((history = HistorySet.Items.Find(i => i.Id == item.Id)) != null && history.LeftOn.TotalSeconds >= 30 && Methods.GetDuration(item.ContentDetails.Duration).TotalSeconds - history.LeftOn.TotalSeconds >= 30) { - history = HistorySet.Items.Find(i => i.Id == videoId); left.Visibility = Visibility.Visible; left.Content = $"\xE122 {resources.GetString("/VideoPage/continue")}: {history.LeftOn.ToString(@"hh\:mm\:ss")}"; } @@ -342,7 +325,7 @@ namespace FoxTube.Pages private async void LiveStatsUpdate(object sender = null, object e = null) { VideosResource.ListRequest request = SecretsVault.Service.Videos.List("liveStreamingDetails"); - request.Id = videoId; + request.Id = item.Id; views.Text = $"{(await request.ExecuteAsync()).Items[0].LiveStreamingDetails.ConcurrentViewers} {resources.GetString("/Cards/viewers")}"; } @@ -359,7 +342,7 @@ namespace FoxTube.Pages { try { - MediaStreamInfoSet infoSet = await new YoutubeClient().GetVideoMediaStreamInfosAsync(videoId); + MediaStreamInfoSet infoSet = await new YoutubeClient().GetVideoMediaStreamInfosAsync(item.Id); foreach (MuxedStreamInfo i in infoSet.Muxed) { MenuFlyoutItem menuItem = new MenuFlyoutItem() @@ -395,7 +378,7 @@ namespace FoxTube.Pages SearchResource.ListRequest request = SecretsVault.Service.Search.List("snippet"); request.RegionCode = SettingsStorage.Region; request.RelevanceLanguage = SettingsStorage.RelevanceLanguage; - request.RelatedToVideoId = videoId; + request.RelatedToVideoId = item.Id; request.SafeSearch = (SearchResource.ListRequest.SafeSearchEnum)SettingsStorage.SafeSearch; request.MaxResults = 20; request.Type = "video"; @@ -408,9 +391,6 @@ namespace FoxTube.Pages private void Player_Minimize(object sender, params object[] e) { - if (isExtended == (bool)e[0]) - return; - isExtended = (bool)e[0]; if(isExtended) { @@ -447,12 +427,12 @@ namespace FoxTube.Pages string timecode = player.Player.Position.TotalSeconds > 10 ? "&t=" + (int)player.Player.Position.TotalSeconds + "s" : string.Empty; - await Launcher.LaunchUriAsync($"https://www.youtube.com/watch?v={videoId}{timecode}".ToUri()); + await Launcher.LaunchUriAsync($"https://www.youtube.com/watch?v={item.Id}{timecode}".ToUri()); } public void refresh_Click(object sender, RoutedEventArgs e) { - Methods.MainPage.GoToVideo(videoId, playlistId); + Methods.MainPage.VideoContent.Refresh(); } public void CloseVideo() @@ -497,12 +477,13 @@ namespace FoxTube.Pages Methods.Share(args, item.Snippet.Thumbnails.Medium.Url, item.Snippet.Title, - $"https://www.youtube.com/watch?v={videoId}", + $"https://www.youtube.com/watch?v={item.Id}", resources.GetString("/Cards/videoShare")); } private void share_Click(object sender, RoutedEventArgs e) { + DataTransferManager.GetForCurrentView().DataRequested += new TypedEventHandler(Share); DataTransferManager.ShowShareUI(); } @@ -518,7 +499,7 @@ namespace FoxTube.Pages dislike.Foreground = new SolidColorBrush(Colors.Red); dislikes.Text = (int.Parse(dislikes.Text, NumberStyles.AllowThousands) + 1).ToString("0,0"); rating.Value--; - await SecretsVault.Service.Videos.Rate(videoId, VideosResource.RateRequest.RatingEnum.Dislike).ExecuteAsync(); + await SecretsVault.Service.Videos.Rate(item.Id, VideosResource.RateRequest.RatingEnum.Dislike).ExecuteAsync(); userRating = Rating.Dislike; break; @@ -527,7 +508,7 @@ namespace FoxTube.Pages dislike.Foreground = new SolidColorBrush(Colors.Red); dislikes.Text = (int.Parse(dislikes.Text, NumberStyles.AllowThousands) + 1).ToString("0,0"); rating.Maximum++; - await SecretsVault.Service.Videos.Rate(videoId, VideosResource.RateRequest.RatingEnum.Dislike).ExecuteAsync(); + await SecretsVault.Service.Videos.Rate(item.Id, VideosResource.RateRequest.RatingEnum.Dislike).ExecuteAsync(); userRating = Rating.Dislike; break; @@ -536,7 +517,7 @@ namespace FoxTube.Pages dislike.Foreground = new SolidColorBrush(Colors.Gray); dislikes.Text = (int.Parse(dislikes.Text, NumberStyles.AllowThousands) - 1).ToString("0,0"); rating.Maximum--; - await SecretsVault.Service.Videos.Rate(videoId, VideosResource.RateRequest.RatingEnum.None).ExecuteAsync(); + await SecretsVault.Service.Videos.Rate(item.Id, VideosResource.RateRequest.RatingEnum.None).ExecuteAsync(); break; } } @@ -553,7 +534,7 @@ namespace FoxTube.Pages like.Foreground = new SolidColorBrush(Colors.Green); likes.Text = (int.Parse(likes.Text, NumberStyles.AllowThousands) + 1).ToString("0,0"); rating.Value++; - await SecretsVault.Service.Videos.Rate(videoId, VideosResource.RateRequest.RatingEnum.Like).ExecuteAsync(); + await SecretsVault.Service.Videos.Rate(item.Id, VideosResource.RateRequest.RatingEnum.Like).ExecuteAsync(); userRating = Rating.Like; break; @@ -563,7 +544,7 @@ namespace FoxTube.Pages likes.Text = (int.Parse(likes.Text, NumberStyles.AllowThousands) + 1).ToString("0,0"); rating.Maximum++; rating.Value++; - await SecretsVault.Service.Videos.Rate(videoId, VideosResource.RateRequest.RatingEnum.Like).ExecuteAsync(); + await SecretsVault.Service.Videos.Rate(item.Id, VideosResource.RateRequest.RatingEnum.Like).ExecuteAsync(); userRating = Rating.Like; break; @@ -573,7 +554,7 @@ namespace FoxTube.Pages likes.Text = (int.Parse(likes.Text, NumberStyles.AllowThousands) - 1).ToString("0,0"); rating.Maximum--; rating.Value--; - await SecretsVault.Service.Videos.Rate(videoId, VideosResource.RateRequest.RatingEnum.None).ExecuteAsync(); + await SecretsVault.Service.Videos.Rate(item.Id, VideosResource.RateRequest.RatingEnum.None).ExecuteAsync(); break; } } @@ -582,7 +563,7 @@ namespace FoxTube.Pages { try { - if ((e.AddedItems[0] as VideoPlaylistItem).Id != videoId) + if ((e.AddedItems[0] as VideoPlaylistItem).Id != item.Id) Methods.MainPage.GoToVideo((e.AddedItems[0] as VideoPlaylistItem).Id, playlistId); } catch { } @@ -606,39 +587,46 @@ namespace FoxTube.Pages async void LoadAddTo() { - if(SecretsVault.UserChannel == null) + try + { + if (SecretsVault.UserChannel == null) + { + addTo.Visibility = Visibility.Collapsed; + return; + } + + if (SecretsVault.WatchLater.Contains(item.Id)) + (addList.Items[1] as ToggleMenuFlyoutItem).IsChecked = true; + + PlaylistsResource.ListRequest request = SecretsVault.Service.Playlists.List("snippet"); + request.Mine = true; + request.MaxResults = 50; + + PlaylistListResponse response = await request.ExecuteAsync(); + + PlaylistItemsResource.ListRequest itemRequest = SecretsVault.Service.PlaylistItems.List("snippet"); + itemRequest.VideoId = item.Id; + + foreach (Playlist i in response.Items) + { + itemRequest.PlaylistId = i.Id; + ToggleMenuFlyoutItem menuItem = new ToggleMenuFlyoutItem + { + Text = i.Snippet.Title, + IsChecked = (await itemRequest.ExecuteAsync()).Items.Count > 0, + Tag = i, + Icon = new FontIcon + { + Glyph = "\xE728" + } + }; + menuItem.Click += Item_Click; + addList.Items.Add(menuItem); + } + } + catch { addTo.Visibility = Visibility.Collapsed; - return; - } - - if (SecretsVault.WatchLater.Contains(item.Id)) - (addList.Items[1] as ToggleMenuFlyoutItem).IsChecked = true; - - PlaylistsResource.ListRequest request = SecretsVault.Service.Playlists.List("snippet"); - request.Mine = true; - request.MaxResults = 50; - - PlaylistListResponse response = await request.ExecuteAsync(); - - PlaylistItemsResource.ListRequest itemRequest = SecretsVault.Service.PlaylistItems.List("snippet"); - itemRequest.VideoId = item.Id; - - foreach (Playlist i in response.Items) - { - itemRequest.PlaylistId = i.Id; - ToggleMenuFlyoutItem menuItem = new ToggleMenuFlyoutItem - { - Text = i.Snippet.Title, - IsChecked = (await itemRequest.ExecuteAsync()).Items.Count > 0, - Tag = i, - Icon = new FontIcon - { - Glyph = "\xE728" - } - }; - menuItem.Click += Item_Click; - addList.Items.Add(menuItem); } } diff --git a/FoxTube/Strings/en-US/About.resw b/FoxTube/Strings/en-US/About.resw index 0a2ee97..96ef432 100644 --- a/FoxTube/Strings/en-US/About.resw +++ b/FoxTube/Strings/en-US/About.resw @@ -124,10 +124,10 @@ Contacts - © 2018 Michael Gordeev + © Michael Gordeev - © 2018 YouTube, LLC + © YouTube, LLC Developed by Michael Gordeev (also known as XFox) @@ -142,7 +142,7 @@ Legal stuff - My blog (Russian language only) + My website Our Privacy Policy diff --git a/FoxTube/Strings/en-US/General.resw b/FoxTube/Strings/en-US/General.resw index bc61e55..5e381f6 100644 --- a/FoxTube/Strings/en-US/General.resw +++ b/FoxTube/Strings/en-US/General.resw @@ -139,7 +139,7 @@ Windows color settings - English (United States of America) + English (United States) App interface language @@ -187,7 +187,7 @@ Reopen the app to apply changes (otherwise some elements may not be displayed correctly) - Russian (Russian Federation) + Russian (Russia) SafeSearch diff --git a/FoxTube/Strings/ru-RU/About.resw b/FoxTube/Strings/ru-RU/About.resw index 17f2e79..028d95f 100644 --- a/FoxTube/Strings/ru-RU/About.resw +++ b/FoxTube/Strings/ru-RU/About.resw @@ -124,10 +124,10 @@ Контакты - © 2018 Михаил Гордеев + © Михаил Гордеев - © 2018 YouTube, LLC + © YouTube, LLC Разработано Михаилом Гордеевым (также известным как XFox) @@ -142,7 +142,7 @@ Юридический материал - Мой блог + Мой веб-сайт Наша политика конфиденциальности diff --git a/FoxTube/Strings/ru-RU/General.resw b/FoxTube/Strings/ru-RU/General.resw index b7a646e..4f0b6e0 100644 --- a/FoxTube/Strings/ru-RU/General.resw +++ b/FoxTube/Strings/ru-RU/General.resw @@ -139,7 +139,7 @@ Цветовые настройки Windows - Английский (Соединенные Штаты Америки) + Английский (США) Язык интерфейса @@ -187,7 +187,7 @@ Перезапустите приложение, чтобы применить настройки (в противном случае некоторые элементы могут неправильно отображаться) - Русский (Российская Федерация) + Русский (Россия) Безопасный поиск