diff --git a/FoxTube.Background/BackgroundProcessor.cs b/FoxTube.Background/BackgroundProcessor.cs index 4e975c5..ae82e4e 100644 --- a/FoxTube.Background/BackgroundProcessor.cs +++ b/FoxTube.Background/BackgroundProcessor.cs @@ -1,7 +1,4 @@ -using Google.Apis.Services; -using Google.Apis.YouTube.v3; -using Google.Apis.YouTube.v3.Data; -using Newtonsoft.Json; +using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; @@ -11,6 +8,7 @@ using System.Xml; using Windows.ApplicationModel.Background; using Windows.Storage; using Windows.UI.Notifications; +using YoutubeExplode.Models; namespace FoxTube.Background { @@ -19,11 +17,6 @@ namespace FoxTube.Background private DateTime lastCheck; private readonly ApplicationDataContainer settings = ApplicationData.Current.RoamingSettings; dynamic prefs; - private readonly YouTubeService Service = new YouTubeService(new BaseClientService.Initializer() - { - ApiKey = "AIzaSyBgHrCnrlzlVmk0cJKL8RqP9Y8x6XSuk_0", - ApplicationName = "FoxTube" - }); BackgroundTaskDeferral def; public async void Run(IBackgroundTaskInstance taskInstance) @@ -60,33 +53,35 @@ namespace FoxTube.Background { Dictionary subscriptions = JsonConvert.DeserializeObject>(settings.Values["subscriptions"] as string); - List results = new List(); + List results = new List(); 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(); + XmlDocument doc = new XmlDocument(); + doc.LoadXml(await new HttpClient().GetStringAsync($"https://www.youtube.com/feeds/videos.xml?channel_id={s.Key}")); - foreach (SearchResult i in response.Items) + List items = new List(); + + foreach (XmlElement i in doc["feed"].ChildNodes) + if (i.Name == "entry" && DateTime.Parse(i["published"].InnerText) > lastCheck.Subtract(TimeSpan.FromDays(1))) + items.Add(i); + + items.OrderByDescending(i => DateTime.Parse(i["published"].InnerText)); + + foreach(XmlElement i in 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)); + Notification.GetVideoToast(i["yt:videoId"].InnerText, s.Key, i["title"].InnerText, i["author"]["name"].InnerText, (await new YoutubeExplode.YoutubeClient().GetVideoAsync(i["yt:videoId"].InnerText)).Thumbnails.MediumResUrl, DateTime.Parse(i["published"].InnerText), s.Value)); } } - results.OrderBy(i => i.Snippet.PublishedAt); - TileUpdater updater = TileUpdateManager.CreateTileUpdaterForApplication(); updater.EnableNotificationQueue(true); updater.Clear(); for (int i = 0; i < 5 && i < results.Count; i++) - updater.Update(Tiles.GetTileLayout(System.Security.SecurityElement.Escape(results[i].Snippet.Title), System.Security.SecurityElement.Escape(results[i].Snippet.ChannelTitle), results[i].Snippet.Thumbnails.Medium.Url.Replace("&", "%26"), subscriptions[results[i].Snippet.ChannelId])); + updater.Update(Tiles.GetTileLayout(System.Security.SecurityElement.Escape(results[i]["title"].InnerText), System.Security.SecurityElement.Escape(results[i]["author"]["name"].InnerText), (await new YoutubeExplode.YoutubeClient().GetVideoAsync(results[i]["yt:videoId"].InnerText)).Thumbnails.MediumResUrl.Replace("&", "%26"), subscriptions[results[i]["author"]["url"].InnerText.Split('/').Last()])); } catch { } } diff --git a/FoxTube.Background/FoxTube.Background.csproj b/FoxTube.Background/FoxTube.Background.csproj index 11a5b78..e8b0cea 100644 --- a/FoxTube.Background/FoxTube.Background.csproj +++ b/FoxTube.Background/FoxTube.Background.csproj @@ -128,10 +128,16 @@ 1.29.2.1006 - 1.13.0 + 1.13.2 - 6.1.5 + 6.2.8 + + + 5.1.1 + + + 4.6.7 diff --git a/FoxTube.Background/ResourceCreators.cs b/FoxTube.Background/ResourceCreators.cs index 539283b..50a29a0 100644 --- a/FoxTube.Background/ResourceCreators.cs +++ b/FoxTube.Background/ResourceCreators.cs @@ -1,4 +1,7 @@ -using Newtonsoft.Json; +using Google.Apis.YouTube.v3.Data; +using Microsoft.Toolkit.Uwp.Notifications; +using Newtonsoft.Json; +using System; using System.Collections.Generic; using Windows.Data.Xml.Dom; using Windows.Storage; @@ -51,11 +54,11 @@ namespace FoxTube.Background return new ToastNotification(template); } - public static ToastNotification GetVideoToast(string id, string channelId, string title, string channel, string thumbnail, string avatar) + public static ToastNotification GetVideoToast(string id, string channelId, string title, string channel, string thumbnail, DateTimeOffset timeStamp, string avatar) { XmlDocument template = new XmlDocument(); - - template.LoadXml($@" + string ts = $"{timeStamp.Year}-{timeStamp.Month:00}-{timeStamp.Day:00}T{timeStamp.Hour:00}:{timeStamp.Minute:00}:{timeStamp.Second:00}Z"; + template.LoadXml($@" diff --git a/FoxTube/App.xaml.cs b/FoxTube/App.xaml.cs index 3056e94..771f189 100644 --- a/FoxTube/App.xaml.cs +++ b/FoxTube/App.xaml.cs @@ -10,6 +10,7 @@ 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; @@ -22,6 +23,7 @@ namespace FoxTube { sealed partial class App : Application { + Stopwatch sw = new Stopwatch(); public App() { SettingsStorage.LoadData(); @@ -45,6 +47,8 @@ namespace FoxTube AppCenter.Start("45774462-9ea7-438a-96fc-03982666f39e", typeof(Analytics)); AppCenter.SetCountryCode(SettingsStorage.Region); + + sw.Start(); } /// @@ -257,6 +261,10 @@ namespace FoxTube private void OnSuspending(object sender, SuspendingEventArgs e) { var deferral = e.SuspendingOperation.GetDeferral(); + + sw.Stop(); + SettingsStorage.Uptime += sw.Elapsed; + SettingsStorage.SaveData(); DownloadAgent.QuitPrompt(); deferral.Complete(); diff --git a/FoxTube/Classes/Methods.cs b/FoxTube/Classes/Methods.cs index 97815e8..18890fe 100644 --- a/FoxTube/Classes/Methods.cs +++ b/FoxTube/Classes/Methods.cs @@ -27,6 +27,10 @@ using YoutubeExplode.Models.MediaStreams; namespace FoxTube { + public interface NavigationPage + { + object Parameter { get; set; } + } public static class Methods { private static ResourceLoader resources = ResourceLoader.GetForCurrentView("Methods"); diff --git a/FoxTube/Classes/SecretsVault.cs b/FoxTube/Classes/SecretsVault.cs index 98e3d5f..990e5a9 100644 --- a/FoxTube/Classes/SecretsVault.cs +++ b/FoxTube/Classes/SecretsVault.cs @@ -10,6 +10,9 @@ using Newtonsoft.Json; using Windows.Storage; using Windows.Services.Store; using System.Net.Http; +using Google.Apis.Oauth2.v2.Data; +using Google.Apis.Oauth2.v2; +using static Google.Apis.Auth.OAuth2.UwpCodeReceiver; namespace FoxTube { @@ -49,6 +52,7 @@ namespace FoxTube public static string AccountId => UserChannel?.Id; public static Channel UserChannel { get; private set; } + public static Userinfoplus UserInfo { get; private set; } public static List Subscriptions { get; } = new List(); public static List History { get; set; } = new List(); @@ -116,31 +120,45 @@ namespace FoxTube /// Loads user's subscriptions if true public static async void Authorize(bool retrieveSubs = true) { + #region Retrieving user's credential try { - #region Retrieving user's credential Credential = await GoogleWebAuthorizationBroker.AuthorizeAsync( - Secrets, - new[] - { - Google.Apis.Oauth2.v2.Oauth2Service.Scope.UserinfoProfile, + 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); - - if (Credential == null || !retrieveSubs) - goto InvokeEvent; + }, + "user", + CancellationToken.None); + } + catch (AuthenticateException e) + { + if (e.Message.Contains("UserCancel")) + return; + else + throw e; + } - SettingsStorage.HasAccount = true; - HttpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", Credential.Token.AccessToken); - #endregion + if (Credential == null || !retrieveSubs) + return; + SettingsStorage.HasAccount = true; + + HttpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", Credential.Token.AccessToken); + #endregion + + try + { #region Retrieving user's data + UserInfo = await new Oauth2Service(Initializer).Userinfo.Get().ExecuteAsync(); + try { WatchLater = await Methods.GetLater(); @@ -148,10 +166,6 @@ namespace FoxTube } catch { } - 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; @@ -169,13 +183,16 @@ namespace FoxTube nextToken = subResponse.NextPageToken; } while (!string.IsNullOrWhiteSpace(nextToken)); + + var request = Service.Channels.List("snippet,contentDetails"); + request.Mine = true; + UserChannel = (await request.ExecuteAsync()).Items[0]; #endregion //Saving user's subscriptions for background task SaveSubscriptions(); - InvokeEvent: - AuthorizationStateChanged?.Invoke(args: IsAuthorized); + AuthorizationStateChanged?.Invoke(args: true); } catch { @@ -189,7 +206,7 @@ namespace FoxTube public static void SaveSubscriptions() { Dictionary subs = new Dictionary(); - Subscriptions.ForEach(x => subs.Add(x.Snippet.ResourceId.ChannelId, x.Snippet.Thumbnails.Medium.Url)); + Subscriptions.ForEach(x => subs.Add(x.Snippet.ResourceId.ChannelId, x.Snippet.Thumbnails.Default__.Url)); ApplicationData.Current.RoamingSettings.Values["subscriptions"] = JsonConvert.SerializeObject(subs); } diff --git a/FoxTube/Classes/SettingsStorage.cs b/FoxTube/Classes/SettingsStorage.cs index 30f9368..b5a952b 100644 --- a/FoxTube/Classes/SettingsStorage.cs +++ b/FoxTube/Classes/SettingsStorage.cs @@ -19,7 +19,7 @@ namespace FoxTube public bool checkConnection = true; public bool autoplay = true; - public int volume = 100; + public double volume = 100; public string language = (new[] { "ua", "ru", "by", "kz", "kg", "md", "lv", "ee" }).Contains(CultureInfo.InstalledUICulture.TwoLetterISOLanguageName) ? "ru-RU" : "en-US"; public string relevanceLanguage = (new[] { "ua", "ru", "by", "kz", "kg", "md", "lv", "ee" }).Contains(CultureInfo.InstalledUICulture.TwoLetterISOLanguageName) ? "ru" : "en"; @@ -28,6 +28,10 @@ namespace FoxTube public bool hasAccount = false; public int theme = 2; + + public TimeSpan uptime = TimeSpan.FromSeconds(0); + public bool promptReview = true; + public bool promptFeedback = true; } public static class SettingsStorage @@ -88,7 +92,7 @@ namespace FoxTube SaveData(); } } - public static int Volume + public static double Volume { get { return Container.volume; } set @@ -187,6 +191,34 @@ namespace FoxTube } } + public static TimeSpan Uptime + { + get { return Container.uptime; } + set + { + Container.uptime = value; + SaveData(); + } + } + public static bool PromptReview + { + get { return Container.promptReview; } + set + { + Container.promptReview = value; + SaveData(); + } + } + public static bool PromptFeedback + { + get { return Container.promptFeedback; } + set + { + Container.promptFeedback = value; + SaveData(); + } + } + //Settings storage private static readonly ApplicationDataContainer storage = ApplicationData.Current.RoamingSettings; private static SettingsContainer Container; diff --git a/FoxTube/Controls/ChannelCard.xaml b/FoxTube/Controls/ChannelCard.xaml index a203ddd..8abf26d 100644 --- a/FoxTube/Controls/ChannelCard.xaml +++ b/FoxTube/Controls/ChannelCard.xaml @@ -10,7 +10,7 @@ VerticalAlignment="Top" d:DesignHeight="290" d:DesignWidth="384" - MaxWidth="500"> + Opacity="0"> diff --git a/FoxTube/Controls/Player/PlayerControls.cs b/FoxTube/Controls/Player/PlayerControls.cs index 8dd4c8e..8b9ae34 100644 --- a/FoxTube/Controls/Player/PlayerControls.cs +++ b/FoxTube/Controls/Player/PlayerControls.cs @@ -84,6 +84,11 @@ namespace FoxTube } } + public void Minimize() + { + Minimize_Click(GetTemplateChild("minimize"), null); + } + private void ProgressSlider_ValueChanged(object sender, RangeBaseValueChangedEventArgs e) { (GetTemplateChild("compactSeek") as ProgressBar).Value = e.NewValue; @@ -189,6 +194,8 @@ namespace FoxTube (GetTemplateChild("maximize") as Button).Visibility = Visibility.Collapsed; (GetTemplateChild("compactClose") as Button).Visibility = Visibility.Collapsed; + (GetTemplateChild("dragholder") as Button).Visibility = Visibility.Visible; + (GetTemplateChild("captions") as LiveCaptions).Size = 15; } @@ -237,6 +244,8 @@ namespace FoxTube (GetTemplateChild("footer") as Grid).Visibility = Visibility.Visible; (GetTemplateChild("captions") as LiveCaptions).Size = 24; + + (GetTemplateChild("dragholder") as Button).Visibility = Visibility.Collapsed; } public void SetMeta(string title, string channel) diff --git a/FoxTube/Controls/Player/VideoPlayer.xaml.cs b/FoxTube/Controls/Player/VideoPlayer.xaml.cs index 174ed56..e36e64f 100644 --- a/FoxTube/Controls/Player/VideoPlayer.xaml.cs +++ b/FoxTube/Controls/Player/VideoPlayer.xaml.cs @@ -1,32 +1,15 @@ using System; -using System.Collections.Generic; using System.Linq; -using Windows.Foundation; using Windows.UI.Core; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; -using Windows.UI.Xaml.Controls.Primitives; -using Windows.UI.Xaml.Input; using Google.Apis.YouTube.v3.Data; using Windows.UI.Xaml.Media.Imaging; using Windows.Media; using Windows.Storage.Streams; -using Windows.UI.ViewManagement; -using System.Xml; -using Windows.ApplicationModel.Core; -using Windows.UI; -using Windows.Media.Casting; using YoutubeExplode.Models.MediaStreams; using YoutubeExplode; -using YoutubeExplode.Models.ClosedCaptions; -using System.Globalization; -using FoxTube.Controls; -using Windows.System; -using Windows.Media.Core; -using Windows.Media.Playback; -using System.Net.Http; using System.Diagnostics; -using Windows.UI.Popups; namespace FoxTube { @@ -124,6 +107,11 @@ namespace FoxTube MiniMode?.Invoke(this, e); } + public void Minimize() + { + Controls.Minimize(); + } + private void Controls_QualityChanged(object sender, MediaStreamInfo requestedQuality, MediaStreamInfoSet list) { videoSource.Pause(); @@ -232,6 +220,7 @@ namespace FoxTube private void VideoSource_VolumeChanged(object sender, RoutedEventArgs e) { audioSource.Volume = videoSource.Volume; + SettingsStorage.Volume = videoSource.Volume; } } } diff --git a/FoxTube/Controls/PlaylistCard.xaml b/FoxTube/Controls/PlaylistCard.xaml index cbe4ed9..ee5d340 100644 --- a/FoxTube/Controls/PlaylistCard.xaml +++ b/FoxTube/Controls/PlaylistCard.xaml @@ -10,7 +10,6 @@ VerticalAlignment="Top" d:DesignHeight="290" d:DesignWidth="384" - MaxWidth="500" Opacity="0"> diff --git a/FoxTube/Controls/VideoCard.xaml b/FoxTube/Controls/VideoCard.xaml index 493bd1f..de1749c 100644 --- a/FoxTube/Controls/VideoCard.xaml +++ b/FoxTube/Controls/VideoCard.xaml @@ -10,7 +10,6 @@ VerticalAlignment="Top" d:DesignHeight="290" d:DesignWidth="384" - MaxWidth="500" Opacity="0"> diff --git a/FoxTube/FoxTube.csproj b/FoxTube/FoxTube.csproj index 84cf56d..58b1d88 100644 --- a/FoxTube/FoxTube.csproj +++ b/FoxTube/FoxTube.csproj @@ -393,7 +393,7 @@ - 1.1.0 + 1.1.2 1.30.0-beta02 @@ -414,25 +414,28 @@ 10.1811.22001 - 1.13.0 + 1.13.2 - 6.1.9 + 6.2.8 + + + 10.1901.28001 - 5.0.0 + 5.1.1 - 5.0.0 + 5.1.1 - 2.0.181018003.1 + 2.0.181018004 4.3.2 - 4.6.4 + 4.6.7 0.10.11 @@ -485,6 +488,9 @@ Microsoft Advertising SDK for XAML + + Microsoft Engagement Framework + diff --git a/FoxTube/Package.appxmanifest b/FoxTube/Package.appxmanifest index 39d3a12..8aa51d6 100644 --- a/FoxTube/Package.appxmanifest +++ b/FoxTube/Package.appxmanifest @@ -15,7 +15,7 @@ - + diff --git a/FoxTube/Pages/ChannelPage.xaml.cs b/FoxTube/Pages/ChannelPage.xaml.cs index d260031..d1e65de 100644 --- a/FoxTube/Pages/ChannelPage.xaml.cs +++ b/FoxTube/Pages/ChannelPage.xaml.cs @@ -21,8 +21,9 @@ namespace FoxTube.Pages /// /// Channel page /// - public sealed partial class ChannelPage : Page + public sealed partial class ChannelPage : Page, NavigationPage { + public object Parameter { get; set; } = null; readonly ResourceLoader resources = ResourceLoader.GetForCurrentView("Cards"); public string channelId; @@ -43,6 +44,7 @@ namespace FoxTube.Pages protected override void OnNavigatedTo(NavigationEventArgs e) { base.OnNavigatedTo(e); + Parameter = e.Parameter; if ((string)e.Parameter == null) loading.Error("NullReferenceException", "Unable to initialize search. Search term is not stated."); else @@ -124,6 +126,8 @@ namespace FoxTube.Pages { "Channel ID", channelId } }); } + + ScrollViewer_ViewChanged(this, null); } async void LoadPlaylist() @@ -167,6 +171,11 @@ namespace FoxTube.Pages { if (content.SelectedIndex == 1 && !playlistLoaded) LoadPlaylist(); + + if (content.SelectedIndex == 0) + ScrollViewer_ViewChanged(this, null); + else + ColapsedHeader.Opacity = 1; } private async void ShowMorePlaylists_Click() diff --git a/FoxTube/Pages/Downloads.xaml.cs b/FoxTube/Pages/Downloads.xaml.cs index df471e9..ba941f5 100644 --- a/FoxTube/Pages/Downloads.xaml.cs +++ b/FoxTube/Pages/Downloads.xaml.cs @@ -9,8 +9,9 @@ namespace FoxTube.Pages /// /// Downloads page /// - public sealed partial class Downloads : Page + public sealed partial class Downloads : Page, NavigationPage { + public object Parameter { get; set; } = null; public Downloads() { InitializeComponent(); diff --git a/FoxTube/Pages/History.xaml.cs b/FoxTube/Pages/History.xaml.cs index b592405..a777e99 100644 --- a/FoxTube/Pages/History.xaml.cs +++ b/FoxTube/Pages/History.xaml.cs @@ -12,8 +12,9 @@ namespace FoxTube.Pages /// /// YouTube history page /// - public sealed partial class History : Page + public sealed partial class History : Page, NavigationPage { + public object Parameter { get; set; } = null; List entries; int page = 1; public string id = "HL"; @@ -26,6 +27,7 @@ namespace FoxTube.Pages protected override void OnNavigatedTo(NavigationEventArgs e) { base.OnNavigatedTo(e); + Parameter = e.Parameter; loading.RefreshPage += Refresh_Click; diff --git a/FoxTube/Pages/Home.xaml.cs b/FoxTube/Pages/Home.xaml.cs index 78aa63a..85bbcc3 100644 --- a/FoxTube/Pages/Home.xaml.cs +++ b/FoxTube/Pages/Home.xaml.cs @@ -14,8 +14,9 @@ namespace FoxTube /// /// Home page /// - public sealed partial class Home : Page + public sealed partial class Home : Page, NavigationPage { + public object Parameter { get; set; } = null; private bool trendLoaded = false, recLoaded = false, subsLoaded = false; List homeList = new List(); diff --git a/FoxTube/Pages/MainPage.xaml b/FoxTube/Pages/MainPage.xaml index f8a71c4..a4f8f47 100644 --- a/FoxTube/Pages/MainPage.xaml +++ b/FoxTube/Pages/MainPage.xaml @@ -40,7 +40,7 @@ - + @@ -81,7 +81,7 @@ - + @@ -93,18 +93,10 @@ - - - - - - - - - - - - + + + + diff --git a/FoxTube/Pages/MainPage.xaml.cs b/FoxTube/Pages/MainPage.xaml.cs index a9548ff..6759767 100644 --- a/FoxTube/Pages/MainPage.xaml.cs +++ b/FoxTube/Pages/MainPage.xaml.cs @@ -18,31 +18,39 @@ using FoxTube.Pages; using Windows.UI.Popups; using Windows.Networking.Connectivity; using Windows.ApplicationModel.Resources; +using Microsoft.Services.Store.Engagement; +using System.Linq; namespace FoxTube { - public enum Sender { Menu, Frame, None } - /// /// Main app's layout /// public sealed partial class MainPage : Page { - Sender s = Sender.None; + bool wasInvoked = false; readonly ResourceLoader resources = ResourceLoader.GetForCurrentView("Main"); Dictionary headers; 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 += (sender, e) => + SecretsVault.Purchased += async (sender, e) => { + //TODO: Localize strings removeAds.Visibility = (e[0] as bool?).Value ? Visibility.Collapsed : Visibility.Visible; - content.Navigate(typeof(Home)); + MessageDialog dialog = new MessageDialog("Thanks for purchasing full version of the app (^∇^) In order to complete changes we need to reopen it. But you can do it later"); + dialog.Commands.Add(new UICommand("Close the app", (command) => Methods.CloseApp())); + dialog.Commands.Add(new UICommand("Later")); + dialog.CancelCommandIndex = 1; + dialog.DefaultCommandIndex = 0; + await dialog.ShowAsync(); }; SecretsVault.Initialize(); @@ -63,6 +71,55 @@ namespace FoxTube { typeof(Home), () => Title.Text = resources.GetString("/Main/home/Content") }, { typeof(Downloads), () => Title.Text = resources.GetString("/Main/downloads/Content") } }; + + if(StoreServicesFeedbackLauncher.IsSupported()) + feedback.Visibility = Visibility.Visible; + + PromptFeedback(); + } + + async void PromptFeedback() + { + //TODO: Localize strings + if (SettingsStorage.Uptime.TotalHours >= 12 && SettingsStorage.PromptFeedback) + { + MessageDialog dialog = new MessageDialog("Have some thoughts to share about the app or any suggestions? Leave feedback!"); + dialog.Commands.Add(new UICommand("Don't ask me anymore", (command) => SettingsStorage.PromptFeedback = false)); + dialog.Commands.Add(new UICommand("Maybe later")); + dialog.Commands.Add(new UICommand("Sure!", async (command) => + { + SettingsStorage.PromptFeedback = false; + if (StoreServicesFeedbackLauncher.IsSupported()) + await StoreServicesFeedbackLauncher.GetDefault().LaunchAsync(); + else + { + MessageDialog message = new MessageDialog("Oops. Seems like you don't have a Feedback Hub app. But you can stil send your feedback to michael.xfox@outlook.com"); + message.Commands.Add(new UICommand("Send an E-mail", async (c) => await Launcher.LaunchUriAsync("mailto:michael.xfox@outlook.com".ToUri()))); + message.Commands.Add(new UICommand("Nevermind. Get me back")); + message.CancelCommandIndex = 1; + message.DefaultCommandIndex = 0; + await message.ShowAsync(); + } + })); + dialog.DefaultCommandIndex = 2; + dialog.CancelCommandIndex = 1; + await dialog.ShowAsync(); + } + + if (SettingsStorage.Uptime.TotalHours >= 24 && SettingsStorage.PromptReview) + { + MessageDialog dialog = new MessageDialog("Like our app? Review it on Microsoft Store!"); + dialog.Commands.Add(new UICommand("Don't ask me anymore", (command) => SettingsStorage.PromptReview = false)); + dialog.Commands.Add(new UICommand("Maybe later")); + dialog.Commands.Add(new UICommand("Sure!", async (command) => + { + SettingsStorage.PromptReview = false; + await Launcher.LaunchUriAsync("ms-windows-store://review/?ProductId=9NCQQXJTDLFH".ToUri()); + })); + dialog.DefaultCommandIndex = 2; + dialog.CancelCommandIndex = 1; + await dialog.ShowAsync(); + } } public string GetPlaylist() @@ -73,7 +130,7 @@ namespace FoxTube public void SetTitleBar(CoreApplicationViewTitleBar coreTitleBar = null) { - if(coreTitleBar != null) + if (coreTitleBar != null) { bool full = ApplicationView.GetForCurrentView().IsFullScreenMode; double left = 12 + (full ? 0 : coreTitleBar.SystemOverlayLeftInset); @@ -89,10 +146,10 @@ namespace FoxTube titleBar.ButtonInactiveBackgroundColor = Colors.Transparent; titleBar.ButtonInactiveForegroundColor = Colors.Gray; - if(Application.Current.RequestedTheme == ApplicationTheme.Dark) - titleBar.ForegroundColor = Colors.White; + if(RequestedTheme == ElementTheme.Dark || (RequestedTheme == ElementTheme.Default && Application.Current.RequestedTheme == ApplicationTheme.Dark)) + titleBar.ButtonForegroundColor = Colors.White; else - titleBar.ForegroundColor = Colors.Black; + titleBar.ButtonForegroundColor = Colors.Black; } private void SecretsVault_SubscriptionsChanged(object sender, params object[] args) @@ -100,7 +157,7 @@ namespace FoxTube switch(args[0] as string) { case "add": - if (nav.MenuItems.Count >= 19) + if (nav.MenuItems.Count < 19) nav.MenuItems.Add(args[1] as Subscription); break; @@ -113,7 +170,6 @@ namespace FoxTube if (SecretsVault.Subscriptions.Count >= 10) nav.MenuItems.Add(SecretsVault.Subscriptions[9]); - break; } } @@ -124,22 +180,16 @@ namespace FoxTube { case true: account.Visibility = Visibility.Collapsed; - try - { - Userinfoplus info = await new Oauth2Service(SecretsVault.Initializer).Userinfo.Get().ExecuteAsync(); - myName.Text = myNameFlyout.Text = info.Name; - if (string.IsNullOrWhiteSpace(info.Email)) - myEmail.Visibility = Visibility.Collapsed; - else - myEmail.Text = info.Email; - avatarFlyout.ProfilePicture = new BitmapImage(info.Picture.ToUri()); - ((avatar.Content as StackPanel).Children[0] as PersonPicture).ProfilePicture = avatarFlyout.ProfilePicture; - } - catch { } + myName.Text = myNameFlyout.Text = SecretsVault.UserInfo.Name; + myEmail.Text = SecretsVault.UserInfo.Email; + avatarFlyout.ProfilePicture = new BitmapImage(SecretsVault.UserInfo.Picture.ToUri()); + ((avatar.Content as StackPanel).Children[0] as PersonPicture).ProfilePicture = avatarFlyout.ProfilePicture; + avatar.Visibility = Visibility.Visible; - toChannel.Visibility = Visibility.Visible; + if(SecretsVault.UserChannel != null) + toChannel.Visibility = Visibility.Visible; toSubscriptions.Visibility = Visibility.Visible; libHeader.Visibility = Visibility.Visible; toHistory.Visibility = Visibility.Visible; @@ -152,9 +202,8 @@ namespace FoxTube for (int k = 0; k < SecretsVault.Subscriptions.Count && k < 10; k++) nav.MenuItems.Add(SecretsVault.Subscriptions[k]); } - if (SecretsVault.UserChannel == null) - toChannel.Visibility = Visibility.Collapsed; break; + case false: for (int k = nav.MenuItems.Count - 1; k > 8; k--) nav.MenuItems.RemoveAt(k); @@ -172,6 +221,7 @@ namespace FoxTube subsHeader.Visibility = Visibility.Collapsed; break; + default: MessageDialog dialog = new MessageDialog(resources.GetString("/Main/connectErrContent"), resources.GetString("/Main/connectErrHeader")); @@ -191,12 +241,12 @@ namespace FoxTube break; } - if(e[0] as bool? != null) - DownloadAgent.Initialize(); + await Dispatcher.RunIdleAsync((command) => DownloadAgent.Initialize()); + + wasInvoked = false; - s = Sender.None; if (content.Content != null) - content.Navigate(content.SourcePageType); + content.Navigate(content.CurrentSourcePageType, (content.Content as NavigationPage).Parameter); else content.Navigate(typeof(Home)); @@ -206,15 +256,10 @@ namespace FoxTube private async void Feedback_Click(object sender, TappedRoutedEventArgs e) { - await Launcher.LaunchUriAsync(new Uri("feedback-hub:")); + await StoreServicesFeedbackLauncher.GetDefault().LaunchAsync(); } - private async void CreateAccount_Click(object sender, RoutedEventArgs e) - { - await Launcher.LaunchUriAsync(new Uri("https://accounts.google.com/signup/v2/webcreateaccount?ManageAccount&flowName=GlifWebSignIn&flowEntry=SignUp")); - } - - private void SignIn_Click(object sender, RoutedEventArgs e) + private void SignIn_Click(object sender, TappedRoutedEventArgs e) { SecretsVault.Authorize(); } @@ -318,13 +363,13 @@ namespace FoxTube public void MinimizeAsInitializer() { - if (videoPlaceholder.Content != null) + if (videoPlaceholder.Content == null) return; if ((videoPlaceholder.Content as VideoPage).LoadingPage.State != LoadingState.Loaded) CloseVideo(); else - (videoPlaceholder.Content as VideoPage).Player.Controls_MiniModeChanged(this, true); + (videoPlaceholder.Content as VideoPage).Player.Minimize(); try { headers[content.SourcePageType](); } catch { } @@ -390,6 +435,8 @@ namespace FoxTube nav.IsBackEnabled = true; else nav.IsBackEnabled = false; + + SetNavigationMenu(); } private void Search_QuerySubmitted(AutoSuggestBox sender, AutoSuggestBoxQuerySubmittedEventArgs args) @@ -400,6 +447,7 @@ namespace FoxTube private void Search_TextChanged(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args) { + //TODO: Make it run async if (search.Text.Length > 2 && args.Reason == AutoSuggestionBoxTextChangeReason.UserInput) { try @@ -425,7 +473,7 @@ namespace FoxTube if (nav.SelectedItem != item) nav.SelectedItem = item; else - s = Sender.None; + wasInvoked = false; } catch { } } @@ -435,9 +483,9 @@ namespace FoxTube try { headers[e.SourcePageType](); } catch { } - if (s == Sender.None) + if (!wasInvoked) { - s = Sender.Frame; + wasInvoked = true; if (e.SourcePageType == typeof(Settings)) SetNavigationItem(nav.SettingsItem); @@ -472,7 +520,7 @@ namespace FoxTube } } else - s = Sender.None; + wasInvoked = false; if(e.SourcePageType == typeof(History)) { @@ -512,9 +560,9 @@ namespace FoxTube { try { - if (s == Sender.None) + if (!wasInvoked) { - s = Sender.Menu; + wasInvoked = true; if (args.IsSettingsSelected) content.Navigate(typeof(Settings)); else @@ -538,7 +586,7 @@ namespace FoxTube } } else - s = Sender.None; + wasInvoked = false; } catch { } } diff --git a/FoxTube/Pages/PlaylistPage.xaml.cs b/FoxTube/Pages/PlaylistPage.xaml.cs index 831368a..c6f6b84 100644 --- a/FoxTube/Pages/PlaylistPage.xaml.cs +++ b/FoxTube/Pages/PlaylistPage.xaml.cs @@ -18,8 +18,9 @@ namespace FoxTube.Pages /// /// Playlist page /// - public sealed partial class PlaylistPage : Page + public sealed partial class PlaylistPage : Page, NavigationPage { + public object Parameter { get; set; } = null; public string playlistId; Playlist item; @@ -36,6 +37,7 @@ namespace FoxTube.Pages 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 diff --git a/FoxTube/Pages/Search.xaml.cs b/FoxTube/Pages/Search.xaml.cs index 3248be5..1981774 100644 --- a/FoxTube/Pages/Search.xaml.cs +++ b/FoxTube/Pages/Search.xaml.cs @@ -16,8 +16,9 @@ namespace FoxTube /// /// Search page /// - public sealed partial class Search : Page + public sealed partial class Search : Page, NavigationPage { + public object Parameter { get; set; } = null; readonly ResourceLoader resources = ResourceLoader.GetForCurrentView("Search"); public SearchParameters Parameters; @@ -63,6 +64,7 @@ namespace FoxTube protected override void OnNavigatedTo(NavigationEventArgs e) { base.OnNavigatedTo(e); + Parameter = e.Parameter; if (e.Parameter == null) loading.Error("NullReferenceException", "Unable to initialize search. Search term is not stated."); else diff --git a/FoxTube/Pages/Settings.xaml.cs b/FoxTube/Pages/Settings.xaml.cs index 5ab67d9..fcb9fab 100644 --- a/FoxTube/Pages/Settings.xaml.cs +++ b/FoxTube/Pages/Settings.xaml.cs @@ -7,8 +7,9 @@ namespace FoxTube /// /// Settings tabs placeholder /// - public sealed partial class Settings : Page + public sealed partial class Settings : Page, NavigationPage { + public object Parameter { get; set; } = null; bool inboxLoaded = false; string inboxId = null; public Settings() @@ -19,7 +20,8 @@ namespace FoxTube protected override void OnNavigatedTo(NavigationEventArgs e) { base.OnNavigatedTo(e); - if(!string.IsNullOrWhiteSpace(e.Parameter as string)) + Parameter = e.Parameter; + if (!string.IsNullOrWhiteSpace(e.Parameter as string)) { inboxId = e.Parameter as string; pivot.SelectedIndex = 2; diff --git a/FoxTube/Pages/SettingsPages/About.xaml b/FoxTube/Pages/SettingsPages/About.xaml index 5864874..761ec62 100644 --- a/FoxTube/Pages/SettingsPages/About.xaml +++ b/FoxTube/Pages/SettingsPages/About.xaml @@ -47,7 +47,7 @@ - public sealed partial class VideoGrid : Page { - public int Count => list.Items.Count; - public ItemCollection Children => list.Items; + public int Columns + { + get { return cols; } + set + { + cols = value; + UpdateGrid(); + } + } + private int cols = 1; + public int Count => Children.Count; + public List Children { get; } = new List(); public VideoGrid() { @@ -21,7 +29,8 @@ namespace FoxTube.Pages public void Add(UIElement card) { - list.Items.Add(card); + (grid.Children[Count % cols + 1] as StackPanel).Children.Add(card); + Children.Add(card); /*if (list.Items.Count % 10 == 0) list.Items.Add(new CardAdvert());*/ empty.Visibility = Visibility.Collapsed; @@ -29,8 +38,39 @@ namespace FoxTube.Pages public void Clear() { - list.Items.Clear(); + for (int k = 1; k <= 5; k++) + (grid.Children[k] as StackPanel).Children.Clear(); + empty.Visibility = Visibility.Visible; } + + 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 2a8e33c..f711e8b 100644 --- a/FoxTube/Pages/VideoPage.xaml +++ b/FoxTube/Pages/VideoPage.xaml @@ -9,7 +9,6 @@ xmlns:controls1="using:FoxTube.Controls" mc:Ignorable="d"> - @@ -61,6 +60,7 @@ + diff --git a/FoxTube/Pages/VideoPage.xaml.cs b/FoxTube/Pages/VideoPage.xaml.cs index d3152ed..4fa4ada 100644 --- a/FoxTube/Pages/VideoPage.xaml.cs +++ b/FoxTube/Pages/VideoPage.xaml.cs @@ -53,7 +53,6 @@ namespace FoxTube.Pages public Video item; bool isExtended = false; - bool playlistLoaded = false; Rating userRating = Rating.None; @@ -229,6 +228,7 @@ namespace FoxTube.Pages { //Setting meta title.Text = item.Snippet.Title; + date.Text = $"{resources.GetString("/VideoPage/publishedAt")}: {item.Snippet.PublishedAt} ({Methods.GetAgo(item.Snippet.PublishedAt.Value)})"; Methods.FormatText(ref description, item.Snippet.Description); //Setting channel button @@ -366,7 +366,7 @@ namespace FoxTube.Pages SearchListResponse response = await request.ExecuteAsync(); foreach (SearchResult video in response.Items) - relatedVideos.Children.Add(new VideoCard(video.Id.VideoId)); + relatedVideos.Add(new VideoCard(video.Id.VideoId)); } private void Player_Minimize(object sender, params object[] e) diff --git a/FoxTube/Strings/en-US/Main.resw b/FoxTube/Strings/en-US/Main.resw index 4df84a7..f82db5d 100644 --- a/FoxTube/Strings/en-US/Main.resw +++ b/FoxTube/Strings/en-US/Main.resw @@ -180,7 +180,7 @@ Sign in with existing account - + Add account diff --git a/FoxTube/Strings/en-US/VideoPage.resw b/FoxTube/Strings/en-US/VideoPage.resw index ea092e2..fc4cf51 100644 --- a/FoxTube/Strings/en-US/VideoPage.resw +++ b/FoxTube/Strings/en-US/VideoPage.resw @@ -261,4 +261,7 @@ Yes + + Published at + \ No newline at end of file diff --git a/FoxTube/Strings/ru-RU/Main.resw b/FoxTube/Strings/ru-RU/Main.resw index b05c24a..34aad54 100644 --- a/FoxTube/Strings/ru-RU/Main.resw +++ b/FoxTube/Strings/ru-RU/Main.resw @@ -180,7 +180,7 @@ Войти с помощью существующего аккаунта Google - + Войти в аккаунт diff --git a/FoxTube/Strings/ru-RU/VideoPage.resw b/FoxTube/Strings/ru-RU/VideoPage.resw index 9844b15..228d6e3 100644 --- a/FoxTube/Strings/ru-RU/VideoPage.resw +++ b/FoxTube/Strings/ru-RU/VideoPage.resw @@ -261,4 +261,7 @@ Да + + Опубликовано + \ No newline at end of file diff --git a/FoxTube/Themes/Generic.xaml b/FoxTube/Themes/Generic.xaml index 0d39e84..f95a712 100644 --- a/FoxTube/Themes/Generic.xaml +++ b/FoxTube/Themes/Generic.xaml @@ -533,6 +533,7 @@ +