using System; using System.Collections.Generic; using Windows.UI; using Windows.UI.ViewManagement; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Navigation; using Windows.UI.Xaml.Media.Imaging; using System.Xml; using Google.Apis.YouTube.v3.Data; using Windows.ApplicationModel.Core; using Windows.System; using FoxTube.Pages; using Windows.UI.Popups; using Windows.ApplicationModel.Resources; using Microsoft.Services.Store.Engagement; using Windows.UI.Xaml.Shapes; using Windows.UI.Xaml.Media; using FoxTube.Controls; namespace FoxTube { /// /// Main app's layout /// public sealed partial class MainPage : Page { bool wasInvoked = false; readonly ResourceLoader resources = ResourceLoader.GetForCurrentView("Main"); Dictionary headers; public ContentFrame PageContent => content; public ContentFrame VideoContent => videoPlaceholder; public MainPage() { headers = new Dictionary() { { typeof(Settings), resources.GetString("/Main/settings/Content") }, { typeof(ChannelPage), resources.GetString("/Main/channel") }, { typeof(PlaylistPage), resources.GetString("/Main/playlist") }, { typeof(Search), resources.GetString("/Main/searchPlaceholder/PlaceholderText") }, { typeof(Subscriptions), resources.GetString("/Main/subscriptions/Content") }, { typeof(History), resources.GetString("/Main/history/Content") }, { typeof(Home), resources.GetString("/Main/home/Content") }, { typeof(UploadPage), "Uploading a video" }, { 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; PromptFeedback(); } async void PromptFeedback() { if (SettingsStorage.Uptime.TotalHours >= 12 && SettingsStorage.PromptFeedback) { MessageDialog dialog = new MessageDialog(resources.GetString("/Main/feedbackMessage")); dialog.Commands.Add(new UICommand(resources.GetString("/Main/dontAsk"), (command) => SettingsStorage.PromptFeedback = false)); dialog.Commands.Add(new UICommand(resources.GetString("/Main/promptLater"))); dialog.Commands.Add(new UICommand(resources.GetString("/Main/sure"), async (command) => { SettingsStorage.PromptFeedback = false; if (StoreServicesFeedbackLauncher.IsSupported()) await StoreServicesFeedbackLauncher.GetDefault().LaunchAsync(); else { MessageDialog message = new MessageDialog(resources.GetString("/Main/feedbackFail")); message.Commands.Add(new UICommand(resources.GetString("/Main/sendEmail"), async (c) => await Launcher.LaunchUriAsync("mailto:michael.xfox@outlook.com".ToUri()))); message.Commands.Add(new UICommand(resources.GetString("/Main/goBack"))); message.CancelCommandIndex = 1; message.DefaultCommandIndex = 0; await message.ShowAsync(); } })); dialog.DefaultCommandIndex = 2; dialog.CancelCommandIndex = 1; await dialog.ShowAsync(); } if (SettingsStorage.Uptime.TotalHours >= 24 && SettingsStorage.PromptReview) { MessageDialog dialog = new MessageDialog(resources.GetString("/Main/rate")); dialog.Commands.Add(new UICommand(resources.GetString("/Main/dontAsk"), (command) => SettingsStorage.PromptReview = false)); dialog.Commands.Add(new UICommand(resources.GetString("/Main/promptLater"))); dialog.Commands.Add(new UICommand(resources.GetString("/Main/sure"), async (command) => { SettingsStorage.PromptReview = false; await Launcher.LaunchUriAsync("ms-windows-store://review/?ProductId=9NCQQXJTDLFH".ToUri()); })); dialog.DefaultCommandIndex = 2; dialog.CancelCommandIndex = 1; await dialog.ShowAsync(); } } public void SetTitleBar(CoreApplicationViewTitleBar coreTitleBar = null) { 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; titleBar.ButtonBackgroundColor = Colors.Transparent; titleBar.ButtonHoverBackgroundColor = Colors.IndianRed; titleBar.ButtonPressedBackgroundColor = Colors.DarkRed; titleBar.ButtonInactiveBackgroundColor = Colors.Transparent; titleBar.ButtonInactiveForegroundColor = Colors.Gray; if(RequestedTheme == ElementTheme.Dark || (RequestedTheme == ElementTheme.Default && Application.Current.RequestedTheme == ApplicationTheme.Dark)) titleBar.ButtonForegroundColor = Colors.White; else titleBar.ButtonForegroundColor = Colors.Black; } private void SecretsVault_SubscriptionsChanged(object sender, params object[] args) { switch((string)args[0]) { case "add": if (nav.MenuItems.Count < 19) nav.MenuItems.Add(args[1] as Subscription); break; case "remove": 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]); } break; } } private async void AuthorizationStateChanged(object sender, params object[] e) { wasInvoked = false; switch (e[0] as bool?) { case true: account.Visibility = Visibility.Collapsed; ToolTipService.SetToolTip(avatar, $"{SecretsVault.UserInfo.Name} ({SecretsVault.UserInfo.Email})"); myNameFlyout.Text = SecretsVault.UserInfo.Name; myEmail.Text = SecretsVault.UserInfo.Email; avatarFlyout.ProfilePicture = new BitmapImage(SecretsVault.UserInfo.Picture.ToUri()) { DecodePixelHeight = 65, DecodePixelWidth = 65 }; ((avatar.Content as Ellipse).Fill as ImageBrush).ImageSource = new BitmapImage(SecretsVault.UserInfo.Picture.ToUri()) { DecodePixelHeight = 25, DecodePixelWidth = 25 }; avatar.Visibility = Visibility.Visible; toChannel.Visibility = Visibility.Visible; toSubscriptions.Visibility = Visibility.Visible; libHeader.Visibility = Visibility.Visible; toHistory.Visibility = Visibility.Visible; toLiked.Visibility = Visibility.Visible; toLater.Visibility = Visibility.Visible; if (SecretsVault.Subscriptions.Count > 0) { subsHeader.Visibility = Visibility.Visible; for (int k = 0; k < SecretsVault.Subscriptions.Count && k < 10; k++) nav.MenuItems.Add(SecretsVault.Subscriptions[k]); } HistorySet.Load(); if (content.Frame.Content != null) content.Refresh(); else content.Frame.Navigate(typeof(Home)); break; case false: content.Frame.Navigate(typeof(Home)); for (int k = nav.MenuItems.Count - 1; k > 8; k--) nav.MenuItems.RemoveAt(k); account.Visibility = Visibility.Visible; avatar.Visibility = Visibility.Collapsed; toChannel.Visibility = Visibility.Collapsed; toSubscriptions.Visibility = Visibility.Collapsed; libHeader.Visibility = Visibility.Collapsed; toHistory.Visibility = Visibility.Collapsed; toLiked.Visibility = Visibility.Collapsed; toLater.Visibility = Visibility.Collapsed; subsHeader.Visibility = Visibility.Collapsed; subsHeader.Visibility = Visibility.Collapsed; content.Frame.BackStack.Clear(); content.Frame.ForwardStack.Clear(); break; default: MessageDialog dialog = new MessageDialog(resources.GetString("/Main/connectErrContent"), resources.GetString("/Main/connectErrHeader")); dialog.Commands.Add(new UICommand(resources.GetString("/Main/tryAgain"), (command) => { SecretsVault.Authorize(); })); dialog.Commands.Add(new UICommand(resources.GetString("/Main/quit"), (command) => { Methods.CloseApp(); })); dialog.CancelCommandIndex = 1; dialog.DefaultCommandIndex = 0; await dialog.ShowAsync(); break; } if (videoPlaceholder.Frame.Content != null) { MaximizeVideo(); videoPlaceholder.Refresh(); } DownloadAgent.Initialize(); } private async void Feedback_Click(object sender, RoutedEventArgs e) { await StoreServicesFeedbackLauncher.GetDefault().LaunchAsync(); } private void SignIn_Click(object sender, RoutedEventArgs e) { SecretsVault.Authorize(); } private void Logout_Click(object sender, RoutedEventArgs e) { avatar.Flyout.Hide(); SecretsVault.Deauthenticate(); } public void GoToSearch(SearchParameters args) { content.Frame.Navigate(typeof(Search), new object[] { args, content }); } public void GoToChannel(string id) { content.Frame.Navigate(typeof(ChannelPage), id); } public void GoToHome() { content.Frame.Navigate(typeof(Home)); } public void GoToVideo(string id, string playlistId = null, bool incognito = false) { MaximizeVideo(); nav.IsBackEnabled = true; nav.ExpandedModeThresholdWidth = short.MaxValue; nav.IsPaneOpen = false; videoPlaceholder.Frame.Navigate(typeof(VideoPage), new object[3] { id, playlistId, incognito }); Title.Text = resources.GetString("/Main/video"); } public void GoToDeveloper(string id) { content.Frame.Navigate(typeof(Settings), id); } public void GoToPlaylist(string id) { content.Frame.Navigate(typeof(PlaylistPage), id); } public void GoToHistory() { content.Frame.Navigate(typeof(History)); } public void GoToDownloads() { content.Frame.Navigate(typeof(Downloads)); } public void MinimizeAsInitializer() { if (videoPlaceholder.Frame.Content == null) return; if (videoPlaceholder.LoadingPage.State != LoadingState.Loaded) CloseVideo(); else (videoPlaceholder.Frame.Content as VideoPage).Player.Minimize(); Title.Text = headers[content.Frame.SourcePageType]; } public void MinimizeVideo() { videoPlaceholder.Width = 432; videoPlaceholder.Height = 243; videoPlaceholder.VerticalAlignment = VerticalAlignment.Bottom; videoPlaceholder.HorizontalAlignment = HorizontalAlignment.Right; videoPlaceholder.Margin = new Thickness(0, 0, 25, 50); if (content.Frame.CanGoBack) nav.IsBackEnabled = true; else nav.IsBackEnabled = false; SetNavigationMenu(); Title.Text = headers[content.Frame.SourcePageType]; } void SetNavigationMenu() { if (content.Frame.SourcePageType == typeof(Home) || content.Frame.SourcePageType == typeof(Settings) || content.Frame.SourcePageType == typeof(Subscriptions)) { nav.ExpandedModeThresholdWidth = 1008; nav.IsPaneOpen = nav.DisplayMode == Microsoft.UI.Xaml.Controls.NavigationViewDisplayMode.Expanded ? true : false; } else { nav.ExpandedModeThresholdWidth = short.MaxValue; nav.IsPaneOpen = false; } } public void MaximizeVideo() { videoPlaceholder.Width = double.NaN; videoPlaceholder.Height = double.NaN; videoPlaceholder.VerticalAlignment = VerticalAlignment.Stretch; videoPlaceholder.HorizontalAlignment = HorizontalAlignment.Stretch; videoPlaceholder.Margin = new Thickness(0); if (videoPlaceholder.Frame.Content == null) return; nav.IsBackEnabled = true; Title.Text = resources.GetString("/Main/video"); nav.ExpandedModeThresholdWidth = short.MaxValue; nav.IsPaneOpen = false; } public void CloseVideo() { if (ApplicationView.GetForCurrentView().IsFullScreenMode) ApplicationView.GetForCurrentView().ExitFullScreenMode(); videoPlaceholder.Frame.Content = null; GC.Collect(); MaximizeVideo(); nav.IsBackEnabled = content.Frame.CanGoBack; SetNavigationMenu(); Title.Text = headers[content.Frame.SourcePageType]; } private void Search_QuerySubmitted(AutoSuggestBox sender, AutoSuggestBoxQuerySubmittedEventArgs args) { if(!string.IsNullOrWhiteSpace(search.Text)) GoToSearch(new SearchParameters(search.Text)); } private async void Search_TextChanged(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args) { await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => { if (search.Text.Length > 2 && args.Reason == AutoSuggestionBoxTextChangeReason.UserInput) { try { XmlDocument doc = new XmlDocument(); doc.Load($"http://suggestqueries.google.com/complete/search?ds=yt&client=toolbar&q={search.Text}&hl={SettingsStorage.RelevanceLanguage}"); List suggestions = new List(); for (int i = 0; i < doc["toplevel"].ChildNodes.Count && i < 5; i++) suggestions.Add(doc["toplevel"].ChildNodes[i]["suggestion"].GetAttribute("data")); search.ItemsSource = suggestions; } catch { search.ItemsSource = new List(); } } }); } void SetNavigationItem(object item) { try { if (nav.SelectedItem != item) nav.SelectedItem = item; else wasInvoked = false; } catch { } } public void Content_Navigated(object sender, NavigationEventArgs e) { Title.Text = headers[content.Frame.SourcePageType]; if (!wasInvoked) { wasInvoked = true; if (e.SourcePageType == typeof(Settings)) SetNavigationItem(nav.SettingsItem); else if (e.SourcePageType == typeof(Subscriptions)) SetNavigationItem(toSubscriptions); else if (e.SourcePageType == typeof(Downloads)) SetNavigationItem(toDownloads); else if (e.SourcePageType == typeof(Home)) SetNavigationItem(toHome); else if (e.SourcePageType == typeof(Search)) SetNavigationItem(null); else if(e.SourcePageType == typeof(ChannelPage)) { if (SecretsVault.IsAuthorized) { if (e.Parameter.ToString() == SecretsVault.AccountId) SetNavigationItem(toChannel); else if (nav.MenuItems.Contains(SecretsVault.Subscriptions.Find(i => i.Snippet.ResourceId.ChannelId == e.Parameter.ToString()))) SetNavigationItem(SecretsVault.Subscriptions.Find(i => i.Snippet.ResourceId.ChannelId == e.Parameter.ToString())); else SetNavigationItem(null); } else SetNavigationItem(null); } else if(e.SourcePageType == typeof(History)) SetNavigationItem(toHistory); else if(e.SourcePageType == typeof(PlaylistPage)) { if (SecretsVault.IsAuthorized) { if (e.Parameter.ToString() == SecretsVault.UserChannel.ContentDetails.RelatedPlaylists.Likes) SetNavigationItem(toLiked); else if (e.Parameter.Equals("WL")) SetNavigationItem(toLater); } else SetNavigationItem(null); } } else wasInvoked = false; nav.IsBackEnabled = content.Frame.CanGoBack; SetNavigationMenu(); if (videoPlaceholder.Frame.Content != null && videoPlaceholder.HorizontalAlignment == HorizontalAlignment.Stretch) MinimizeAsInitializer(); } private void RemoveAds_Tapped(object sender, TappedRoutedEventArgs e) { SecretsVault.GetAdblock(); } private void Nav_SelectionChanged(Microsoft.UI.Xaml.Controls.NavigationView sender, Microsoft.UI.Xaml.Controls.NavigationViewSelectionChangedEventArgs args) { if (!wasInvoked) { if (content == null) return; wasInvoked = true; if (args.IsSettingsSelected) content.Frame.Navigate(typeof(Settings)); else { if (args.SelectedItem == toHome) content.Frame.Navigate(typeof(Home)); else if (args.SelectedItem == toHistory) content.Frame.Navigate(typeof(History)); else if (args.SelectedItem == toLiked) content.Frame.Navigate(typeof(PlaylistPage), SecretsVault.UserChannel.ContentDetails.RelatedPlaylists.Likes); else if (args.SelectedItem == toLater) content.Frame.Navigate(typeof(PlaylistPage), "WL"); else if (args.SelectedItem == toSubscriptions) content.Frame.Navigate(typeof(Subscriptions)); else if (args.SelectedItem == toDownloads) content.Frame.Navigate(typeof(Downloads)); else if (args.SelectedItem == toChannel) content.Frame.Navigate(typeof(ChannelPage), SecretsVault.UserChannel.Id); else content.Frame.Navigate(typeof(ChannelPage), (args.SelectedItem as Subscription).Snippet.ResourceId.ChannelId); } } else wasInvoked = false; } private void Nav_BackRequested(Microsoft.UI.Xaml.Controls.NavigationView sender, Microsoft.UI.Xaml.Controls.NavigationViewBackRequestedEventArgs args) { if (videoPlaceholder.Frame.Content != null && double.IsNaN(videoPlaceholder.Width)) { if (videoPlaceholder.Frame.CanGoBack) videoPlaceholder.Frame.GoBack(); else if (videoPlaceholder.LoadingPage.State != LoadingState.Loaded) CloseVideo(); else MinimizeAsInitializer(); } else content.Frame.GoBack(); } private void Nav_PaneClosing(Microsoft.UI.Xaml.Controls.NavigationView sender, Microsoft.UI.Xaml.Controls.NavigationViewPaneClosingEventArgs args) { AppTitle.Visibility = Visibility.Collapsed; } private void Nav_PaneOpened(Microsoft.UI.Xaml.Controls.NavigationView sender, object args) { AppTitle.Visibility = Visibility.Visible; } private void NavigationViewItem_Tapped(object sender, TappedRoutedEventArgs e) { content.Frame.Navigate(typeof(UploadPage)); } } }