Archived
1
0

App UI development

Updated and enchanced MainPage
Updated Core
This commit is contained in:
Michael Gordeev
2020-05-12 01:32:41 +03:00
parent f89bf80018
commit a792132428
54 changed files with 2684 additions and 1479 deletions
+16
View File
@@ -6,7 +6,9 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Xml; using System.Xml;
using Windows.Devices.PointOfService;
using Windows.UI; using Windows.UI;
using Windows.UI.Xaml.Media.Imaging;
namespace FoxTube namespace FoxTube
{ {
@@ -39,6 +41,9 @@ namespace FoxTube
public static bool Belongs<T>(this T obj, params T[] args) => public static bool Belongs<T>(this T obj, params T[] args) =>
args.Contains(obj); args.Contains(obj);
public static bool Belongs(this int number, int lowerLimit, int upperLimit) =>
number >= lowerLimit && number <= upperLimit;
public static string ToHex(this Color color) => public static string ToHex(this Color color) =>
$"#{color.R:X}{color.G:X}{color.B:X}"; $"#{color.R:X}{color.G:X}{color.B:X}";
@@ -57,6 +62,17 @@ namespace FoxTube
}; };
} }
public static BitmapImage LoadImage (this BitmapImage image, string source, int? height = null, int? width = null)
{
image.UriSource = source.ToUri();
if (height.HasValue)
image.DecodePixelHeight = height.Value;
if (width.HasValue)
image.DecodePixelWidth = width.Value;
return image;
}
public static TimeSpan GetDuration(this string rawDuration) public static TimeSpan GetDuration(this string rawDuration)
{ {
try try
+1 -10
View File
@@ -167,9 +167,6 @@
<PackageReference Include="Google.Apis.YouTube.v3"> <PackageReference Include="Google.Apis.YouTube.v3">
<Version>1.45.0.1929</Version> <Version>1.45.0.1929</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.Advertising.XAML">
<Version>10.1811.22001</Version>
</PackageReference>
<PackageReference Include="Microsoft.AppCenter.Analytics"> <PackageReference Include="Microsoft.AppCenter.Analytics">
<Version>3.2.1</Version> <Version>3.2.1</Version>
</PackageReference> </PackageReference>
@@ -186,22 +183,16 @@
<Version>2.4.0</Version> <Version>2.4.0</Version>
</PackageReference> </PackageReference>
<PackageReference Include="YoutubeExplode"> <PackageReference Include="YoutubeExplode">
<Version>5.0.3</Version> <Version>5.0.4</Version>
</PackageReference> </PackageReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<WCFMetadata Include="Connected Services\" /> <WCFMetadata Include="Connected Services\" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<SDKReference Include="Microsoft.Advertising.Xaml, Version=10.0">
<Name>Microsoft Advertising SDK for XAML</Name>
</SDKReference>
<SDKReference Include="Microsoft.Services.Store.Engagement, Version=10.0"> <SDKReference Include="Microsoft.Services.Store.Engagement, Version=10.0">
<Name>Microsoft Engagement Framework</Name> <Name>Microsoft Engagement Framework</Name>
</SDKReference> </SDKReference>
<SDKReference Include="Microsoft.VCLibs, Version=14.0">
<Name>Visual C++ 2015 Runtime for Universal Windows Platform Apps</Name>
</SDKReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="ValueConverters\" /> <Folder Include="ValueConverters\" />
+4 -1
View File
@@ -133,7 +133,10 @@ namespace FoxTube
return "en-US"; return "en-US";
} }
public static void ResetSettings() => public static void ResetSettings()
{
settings.Values.Clear(); settings.Values.Clear();
ApplicationData.Current.LocalSettings.Values.Clear();
}
} }
} }
+32 -23
View File
@@ -22,7 +22,7 @@ namespace FoxTube
{ {
public static class UserManagement public static class UserManagement
{ {
public const int MaxUsersCount = 2; public const int MaxUsersCount = 1;
#region Private members #region Private members
private static readonly ApplicationDataContainer storage = ApplicationData.Current.LocalSettings; private static readonly ApplicationDataContainer storage = ApplicationData.Current.LocalSettings;
@@ -48,16 +48,13 @@ namespace FoxTube
{ {
ClientId = "349735264870-2ekqlm0a4mkg3mmrfcv90s3qp3o15dq0.apps.googleusercontent.com", ClientId = "349735264870-2ekqlm0a4mkg3mmrfcv90s3qp3o15dq0.apps.googleusercontent.com",
ClientSecret = "BkVZOAaCU2Zclf0Zlicg6y2_" ClientSecret = "BkVZOAaCU2Zclf0Zlicg6y2_"
},
new ClientSecrets // DISABLED
{
ClientId = "1096685398208-u95rcpkqb4e1ijfmb8jdq3jsg37l8igv.apps.googleusercontent.com",
ClientSecret = "IU5bbdjwvmx8ttJoXQ7e6JWd"
} }
}; };
#endregion #endregion
public static Userinfoplus[] Users { get; private set; } = new Userinfoplus[MaxUsersCount]; public static Userinfoplus[] Users { get; private set; } = new Userinfoplus[MaxUsersCount];
public static bool CanAddAccounts => Users.Any(i => i == null);
public static User CurrentUser { get; set; } public static User CurrentUser { get; set; }
public static bool Authorized => CurrentUser != null; public static bool Authorized => CurrentUser != null;
public static ExtendedYouTubeService Service => CurrentUser?.Service ?? _defaultService; public static ExtendedYouTubeService Service => CurrentUser?.Service ?? _defaultService;
@@ -108,7 +105,7 @@ namespace FoxTube
public static async Task Initialize() public static async Task Initialize()
{ {
Users = JsonConvert.DeserializeObject<Userinfoplus[]>(storage.Values["UserManagement.Users"] as string); Users = JsonConvert.DeserializeObject<Userinfoplus[]>(storage.Values["UserManagement.Users"] as string ?? "") ?? new Userinfoplus[MaxUsersCount];
int? lastUserIndex = storage.Values["UserManagement.LastUser"] as int?; int? lastUserIndex = storage.Values["UserManagement.LastUser"] as int?;
if (lastUserIndex.HasValue && Users[lastUserIndex.Value] != null || if (lastUserIndex.HasValue && Users[lastUserIndex.Value] != null ||
@@ -126,8 +123,12 @@ namespace FoxTube
string userId = CurrentUser.UserInfo.Id; string userId = CurrentUser.UserInfo.Id;
PasswordVault passwordVault = new PasswordVault(); PasswordVault passwordVault = new PasswordVault();
PasswordCredential credential = passwordVault.Retrieve("foxtube", userId); try
passwordVault.Remove(credential); {
PasswordCredential credential = passwordVault.Retrieve("foxtube", userId);
passwordVault.Remove(credential);
}
catch { }
await CurrentUser.Credential.RevokeTokenAsync(CancellationToken.None); await CurrentUser.Credential.RevokeTokenAsync(CancellationToken.None);
@@ -159,20 +160,27 @@ namespace FoxTube
} }
} }
public static async Task SwitchUser(int userIndex) public static async Task<bool> SwitchUser(int userIndex)
{ {
Userinfoplus userInfo = Users[userIndex]; Userinfoplus userInfo = Users[userIndex];
PasswordVault valut = new PasswordVault(); PasswordVault valut = new PasswordVault();
PasswordCredential vaultCredential = valut.Retrieve("foxtube", userInfo.Id); try
if (vaultCredential == null) {
throw new NullReferenceException("No user found to switch on"); PasswordCredential vaultCredential = valut.Retrieve("foxtube", userInfo.Id);
vaultCredential.RetrievePassword(); vaultCredential.RetrievePassword();
string token = vaultCredential.Password; string token = vaultCredential.Password;
YouTube.Authorization.UserCredential credential = await AuthorizationHelpers.RestoreUser(ClientSecrets[userIndex], token); YouTube.Authorization.UserCredential credential = await AuthorizationHelpers.RestoreUser(ClientSecrets[userIndex], token);
await LoadUser(credential, userIndex); await LoadUser(credential, userIndex);
return true;
}
catch
{
return false;
}
} }
private static async Task LoadUser(YouTube.Authorization.UserCredential credential, int userIndex) private static async Task LoadUser(YouTube.Authorization.UserCredential credential, int userIndex)
@@ -192,15 +200,16 @@ namespace FoxTube
private static void UpdateToken(string id, string refreshToken) private static void UpdateToken(string id, string refreshToken)
{ {
PasswordVault passwordVault = new PasswordVault(); PasswordVault passwordVault = new PasswordVault();
PasswordCredential vaultCredential = passwordVault.Retrieve("foxtube", id); try
if (vaultCredential == null)
{ {
vaultCredential = new PasswordCredential("foxtube", CurrentUser.UserInfo.Id, refreshToken); PasswordCredential vaultCredential = passwordVault.Retrieve("foxtube", id);
vaultCredential.Password = refreshToken;
}
catch
{
PasswordCredential vaultCredential = new PasswordCredential("foxtube", CurrentUser.UserInfo.Id, refreshToken);
passwordVault.Add(vaultCredential); passwordVault.Add(vaultCredential);
} }
else
vaultCredential.Password = refreshToken;
} }
internal static void SubscriptionsChangedInvoker(User sender, Subscription subscription) => internal static void SubscriptionsChangedInvoker(User sender, Subscription subscription) =>
+3 -6
View File
@@ -1,5 +1,4 @@
using Microsoft.Advertising.WinRT.UI; using Microsoft.AppCenter.Crashes;
using Microsoft.AppCenter.Crashes;
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using Windows.Services.Store; using Windows.Services.Store;
@@ -14,12 +13,10 @@ namespace FoxTube.Utils
private static bool UseTestAds => true; private static bool UseTestAds => true;
private static string ApplicationId => UseTestAds ? "d25517cb-12d4-4699-8bdc-52040c712cab" : "9ncqqxjtdlfh"; public static string ApplicationId => UseTestAds ? "d25517cb-12d4-4699-8bdc-52040c712cab" : "9ncqqxjtdlfh";
private static string AdsId => UseTestAds ? "test" : "1100044398"; public static string AdsId => UseTestAds ? "test" : "1100044398";
private static string ProProductId => "9NP1QK556625"; private static string ProProductId => "9NP1QK556625";
public static NativeAdsManagerV2 AdsManager => new NativeAdsManagerV2(ApplicationId, AdsId);
public static async Task UpdateStoreState() public static async Task UpdateStoreState()
{ {
StoreProductQueryResult requset = await StoreContext.GetDefault().GetAssociatedStoreProductsAsync(new[] { "Durable" }); StoreProductQueryResult requset = await StoreContext.GetDefault().GetAssociatedStoreProductsAsync(new[] { "Durable" });
+55 -35
View File
@@ -3,44 +3,64 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Application.Resources> <Application.Resources>
<ResourceDictionary> <ResourceDictionary>
<ResourceDictionary.MergedDictionaries> <ResourceDictionary.MergedDictionaries>
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls"/> <XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls"/>
</ResourceDictionary.MergedDictionaries> </ResourceDictionary.MergedDictionaries>
<Color x:Key="SystemAccentColor">Red</Color> <Color x:Key="SystemAccentColor">Red</Color>
<Color x:Key="RadioButtonOuterEllipseCheckedStrokePointerOver">Gray</Color> <Color x:Key="RadioButtonOuterEllipseCheckedStrokePointerOver">Gray</Color>
<Color x:Key="RadioButtonOuterEllipseCheckedFillPointerOver">Gray</Color> <Color x:Key="RadioButtonOuterEllipseCheckedFillPointerOver">Gray</Color>
<Color x:Key="RadioButtonOuterEllipseCheckedStrokePressed">DarkRed</Color> <Color x:Key="RadioButtonOuterEllipseCheckedStrokePressed">DarkRed</Color>
<Color x:Key="RadioButtonOuterEllipseCheckedFillPressed">DarkRed</Color> <Color x:Key="RadioButtonOuterEllipseCheckedFillPressed">DarkRed</Color>
<Color x:Key="ComboBoxItemRevealBackgroundSelected">Red</Color> <Color x:Key="ComboBoxItemRevealBackgroundSelected">Red</Color>
<Color x:Key="ComboBoxItemRevealBackgroundSelectedPointerOver">Gray</Color> <Color x:Key="ComboBoxItemRevealBackgroundSelectedPointerOver">Gray</Color>
<Color x:Key="ComboBoxItemRevealBackgroundSelectedPressed">DarkRed</Color> <Color x:Key="ComboBoxItemRevealBackgroundSelectedPressed">DarkRed</Color>
<Color x:Key="ToggleSwitchFillOnPointerOver">Gray</Color> <Color x:Key="ToggleSwitchFillOnPointerOver">Gray</Color>
<Style x:Key="HeaderButton" TargetType="Button" BasedOn="{StaticResource ButtonRevealStyle}"> <Style x:Key="HeaderButton" TargetType="Button" BasedOn="{StaticResource ButtonRevealStyle}">
<Setter Property="FontFamily" Value="Segoe MDL2 Assets"/> <Setter Property="FontFamily" Value="Segoe MDL2 Assets"/>
<Setter Property="Background" Value="Transparent"/> <Setter Property="Background" Value="Transparent"/>
<Setter Property="Height" Value="32"/> <Setter Property="Height" Value="32"/>
<Setter Property="Width" Value="32"/> <Setter Property="Width" Value="32"/>
</Style> </Style>
<Style TargetType="StackPanel"> <Style TargetType="StackPanel">
<Setter Property="ChildrenTransitions"> <Setter Property="ChildrenTransitions">
<Setter.Value> <Setter.Value>
<TransitionCollection> <TransitionCollection>
<EntranceThemeTransition/> <EntranceThemeTransition/>
</TransitionCollection> </TransitionCollection>
</Setter.Value> </Setter.Value>
</Setter> </Setter>
</Style> </Style>
<Style TargetType="Button" BasedOn="{StaticResource ButtonRevealStyle}"/> <Style TargetType="Button" BasedOn="{StaticResource ButtonRevealStyle}">
<Style TargetType="PivotItem"> <Setter Property="Height" Value="32"/>
<Setter Property="Margin" Value="0"/> </Style>
</Style> <Style TargetType="PivotItem">
</ResourceDictionary> <Setter Property="Margin" Value="0"/>
</Application.Resources> </Style>
<Style x:Key="HeaderActionButton" TargetType="Button" BasedOn="{StaticResource ButtonRevealStyle}">
<Setter Property="Background" Value="Transparent" />
<Setter Property="CornerRadius" Value="0" />
<Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="Height" Value="32" />
<Setter Property="Width" Value="40" />
<Setter Property="Padding" Value="0" />
<Setter Property="FontFamily" Value="Segoe MDL2 Assets" />
<Setter Property="FontSize" Value="15" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="VerticalContentAlignment" Value="Center" />
</Style>
<Style TargetType="TextBlock">
<Setter Property="TextTrimming" Value="CharacterEllipsis"/>
<Setter Property="TextWrapping" Value="WrapWholeWords"/>
</Style>
</ResourceDictionary>
</Application.Resources>
</Application> </Application>
+97 -57
View File
@@ -1,74 +1,114 @@
using System; using System;
using FoxTube.Core.Helpers; using FoxTube.Services;
using FoxTube.Utils;
using Windows.ApplicationModel; using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation; using Windows.ApplicationModel.Activation;
using Windows.UI.Popups; using Windows.UI;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml; using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
namespace FoxTube namespace FoxTube
{ {
sealed partial class App : Application sealed partial class App : Application
{ {
public App() public App()
{ {
InitializeComponent(); InitializeComponent();
Suspending += OnSuspending;
UnhandledException += ErrorOccured;
Metrics.StartSession();
}
protected override async void OnLaunched(LaunchActivatedEventArgs e) Suspending += OnSuspending;
{ UnhandledException += ErrorOccured;
await UsersControl.Initialize(); }
await StoreInterop.UpdateStoreState();
if (Settings.LastReviewedVersion != Metrics.CurrentVersion)
Inbox.PushChangelog();
if (!e.PrelaunchActivated && Window.Current.Content == null) protected override async void OnLaunched(LaunchActivatedEventArgs e)
Window.Current.Content = new MainPage(); {
Window.Current.Activate(); await UserManagement.Initialize();
} await StoreInterop.UpdateStoreState();
if (Settings.LastReviewedVersion != Metrics.CurrentVersion)
Inbox.PushChangelog();
protected override void OnBackgroundActivated(BackgroundActivatedEventArgs args) if (!e.PrelaunchActivated && Window.Current.Content == null)
{ Window.Current.Content = new MainPage();
var deferral = args.TaskInstance.GetDeferral(); Window.Current.Activate();
base.OnBackgroundActivated(args); }
deferral.Complete(); protected override void OnBackgroundActivated(BackgroundActivatedEventArgs args)
} {
var deferral = args.TaskInstance.GetDeferral();
base.OnBackgroundActivated(args);
protected override void OnActivated(IActivatedEventArgs e) deferral.Complete();
{ }
base.OnActivated(e);
if (Window.Current.Content == null) protected override void OnActivated(IActivatedEventArgs e)
Window.Current.Content = new MainPage(); {
Window.Current.Activate(); base.OnActivated(e);
}
void OnSuspending(object sender, SuspendingEventArgs e) if (Window.Current.Content == null)
{ Window.Current.Content = new MainPage();
Metrics.EndSession(); Window.Current.Activate();
} }
async void ErrorOccured(object sender, Windows.UI.Xaml.UnhandledExceptionEventArgs e) void OnSuspending(object sender, SuspendingEventArgs e)
{ {
Metrics.AddEvent("Application chrashed", Metrics.EndSession();
("Exception", e.Exception.GetType().ToString()), }
("Message", e.Message),
("StackTrace", e.Exception.StackTrace));
e.Handled = true;
MessageDialog alert = new MessageDialog($"Exception: {e.Exception.GetType().ToString()}\nMessage: {e.Message}\n\nIf this happens again try to reset your app settings or report the problem", async void ErrorOccured(object sender, Windows.UI.Xaml.UnhandledExceptionEventArgs e)
"Unhandled error occured"); {
alert.Commands.Add(new UICommand("Reset application", (command) => Utils.InitializeFailsafeProtocol())); Metrics.AddEvent("Application chrashed",
if(Feedback.HasFeedbackHub) ("Exception", e.Exception.GetType().ToString()),
alert.Commands.Add(new UICommand("Report the problem", (command) => Feedback.OpenFeedbackHub())); ("Message", e.Message),
alert.Commands.Add(new UICommand("Close")); ("StackTrace", e.Exception.StackTrace));
e.Handled = true;
alert.DefaultCommandIndex = 0;
alert.CancelCommandIndex = 2; ContentDialogResult result = await new ContentDialog
await alert.ShowAsync(); {
} Title = "Something went wrong...",
} Content = "It may be a bug or temporary server issues. Please, try again later\n\nIf this happens again try to reset your app settings or report the problem",
} PrimaryButtonText = "Report the problem",
SecondaryButtonText = "Reset application",
CloseButtonText = "Close",
DefaultButton = ContentDialogButton.Primary
}.ShowAsync();
switch (result)
{
case ContentDialogResult.Primary:
Feedback.OpenFeedbackHub();
break;
case ContentDialogResult.Secondary:
Utils.Utils.InitializeFailsafeProtocol();
break;
default:
break;
}
}
public static void UpdateTitleBar(bool isDark)
{
ApplicationViewTitleBar titleBar = ApplicationView.GetForCurrentView().TitleBar;
titleBar.ButtonBackgroundColor = Colors.Transparent;
titleBar.ButtonInactiveBackgroundColor = Colors.Transparent;
titleBar.ButtonInactiveForegroundColor = Colors.Gray;
if (isDark)
{
titleBar.ButtonForegroundColor =
titleBar.ButtonHoverForegroundColor =
titleBar.ButtonPressedForegroundColor = Colors.White;
titleBar.ButtonHoverBackgroundColor = Color.FromArgb(50, 255, 255, 255);
titleBar.ButtonPressedBackgroundColor = Color.FromArgb(30, 255, 255, 255);
}
else
{
titleBar.ButtonForegroundColor =
titleBar.ButtonHoverForegroundColor =
titleBar.ButtonPressedForegroundColor = Colors.Black;
titleBar.ButtonHoverBackgroundColor = Color.FromArgb(50, 0, 0, 0);
titleBar.ButtonPressedBackgroundColor = Color.FromArgb(70, 0, 0, 0);
}
}
}
}
+84
View File
@@ -0,0 +1,84 @@
using Google.Apis.YouTube.v3.Data;
using System.Collections.Generic;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Media.Imaging;
namespace FoxTube.Utils
{
public static class MenuItemsList
{
public static List<Microsoft.UI.Xaml.Controls.NavigationViewItemBase> GetMenuItems(bool authorized)
{
List<Microsoft.UI.Xaml.Controls.NavigationViewItemBase> list = new List<Microsoft.UI.Xaml.Controls.NavigationViewItemBase>
{
GetItem("Home", new SymbolIcon(Symbol.Home), "home")
};
if (authorized)
list.AddRange(new Microsoft.UI.Xaml.Controls.NavigationViewItemBase[]
{
GetItem("Subscriptions", new SymbolIcon(Symbol.People), "subscriptions"),
new Microsoft.UI.Xaml.Controls.NavigationViewItemHeader { Content = "Library" },
GetItem("History", new FontIcon { Glyph = "\xE81C" }, "history"),
GetItem("Liked videos", new SymbolIcon(Symbol.Like), "liked"),
GetItem("Watch later", new SymbolIcon(Symbol.Clock), "watchLater"),
GetItem("Downloads", new SymbolIcon(Symbol.Download), "downloads")
});
else
list.AddRange(new Microsoft.UI.Xaml.Controls.NavigationViewItemBase[]
{
GetItem("Downloads", new SymbolIcon(Symbol.Download), "downloads"),
new Microsoft.UI.Xaml.Controls.NavigationViewItemHeader { Content = "Best of YouTube" },
GetItem("Music", new FontIcon { Glyph = "\xE189" }, "UC-9-kyTW8ZkZNDHQJ6FgpwQ"),
GetItem("Sports", new FontIcon { Glyph = "\xE95E" }, "UCEgdi0XIXXZ-qJOFPf4JSKw"),
GetItem("Movies", new FontIcon { Glyph = "\xE8B2" }, "UClgRkhTL3_hImCAmdLfDE4g"),
GetItem("News", new FontIcon { Glyph = "\xE12A" }, "UCYfdidRxbB8Qhf0Nx7ioOYw"),
GetItem("Live", new FontIcon { Glyph = "\xE93E" }, "UC4R8DWoMoI7CAwX8_LjQHig"),
GetItem("Spotlight", new FontIcon { Glyph = "\xECAD" }, "UC8iNz9uwDGfomRnnKKbOhOQ"),
GetItem("360° videos", new FontIcon { Glyph = "\xF131" }, "UCzuqhhs6NWbgTzMuM09WKDQ"),
});
return list;
}
private static Microsoft.UI.Xaml.Controls.NavigationViewItem GetItem(string content, IconElement icon, string tag) =>
new Microsoft.UI.Xaml.Controls.NavigationViewItem
{
Content = content,
Icon = icon,
Tag = tag
};
public static Microsoft.UI.Xaml.Controls.NavigationViewItem GenerateItemFromSubscription(Subscription subscription)
{
StackPanel stack = new StackPanel
{
Orientation = Orientation.Horizontal,
Padding = new Thickness(5),
Margin = new Thickness(-5, 0, 0, 0)
};
stack.Children.Add(new Microsoft.UI.Xaml.Controls.PersonPicture
{
Height = 20,
Margin = new Thickness(-5, 0, 15, 0),
ProfilePicture = new BitmapImage().LoadImage(subscription.Snippet.Thumbnails.Default__.Url, 20, 20)
});
stack.Children.Add(new TextBlock
{
FontSize = 14,
Text = subscription.Snippet.Title
});
return new Microsoft.UI.Xaml.Controls.NavigationViewItem
{
Content = stack,
Tag = subscription.Snippet.ChannelId
};
}
}
}
+35
View File
@@ -0,0 +1,35 @@
namespace FoxTube
{
public enum NavigationTarget
{
Home,
Settings,
Downloads
}
public static class Navigation
{
public static NavigationTarget CurrentPage { get; private set; }
public static object CurrentParameter { get; private set; }
public static void NavigateTo(NavigationTarget destination) =>
NavigateTo(destination, null);
public static void NavigateTo(NavigationTarget destination, object parameters)
{
MainPage.Current.Navigate(destination switch
{
NavigationTarget.Settings => typeof(Views.Settings),
NavigationTarget.Downloads => typeof(Views.Downloads),
_ => UserManagement.Authorized ? typeof(Views.Home) : typeof(Views.HomeSections.Trending),
},
parameters);
CurrentPage = destination;
CurrentParameter = parameters;
}
public static void RefreshCurrentPage() =>
MainPage.Current.Refresh();
}
}
+55
View File
@@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.UI.Core;
using Windows.UI.Xaml.Data;
namespace FoxTube.Models
{
public class ViewItemsCollection : ObservableCollection<object>, ISupportIncrementalLoading
{
public event EventHandler ItemsUpdated;
public bool HasMoreItems
{
get => _hasMoreItems;
private set
{
_hasMoreItems = value;
ItemsUpdated?.Invoke(this, null);
}
}
private bool _hasMoreItems = true;
private IIncrementalLoadingHost Host { get; set; }
public ViewItemsCollection(IIncrementalLoadingHost host) =>
Host = host;
public IAsyncOperation<LoadMoreItemsResult> LoadMoreItemsAsync(uint count) =>
AsyncInfo.Run((c) => LoadItems());
private async Task<LoadMoreItemsResult> LoadItems()
{
(List<object> items, bool hasMore) = await Host.LoadMoreItems();
HasMoreItems = hasMore;
await Host.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
items.ForEach(i =>
Add(i));
});
return new LoadMoreItemsResult { Count = (uint)items.Count };
}
}
public interface IIncrementalLoadingHost
{
Task<(List<object>, bool)> LoadMoreItems();
CoreDispatcher Dispatcher { get; }
}
}
+82 -54
View File
@@ -1,64 +1,92 @@
<AppBarButton <Button
x:Class="FoxTube.Controls.AccountManager" x:Class="FoxTube.Controls.AccountManager"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" mc:Ignorable="d"
Label="Sign in"
xmlns:ui="using:Microsoft.UI.Xaml.Controls" xmlns:ui="using:Microsoft.UI.Xaml.Controls"
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls" xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls" xmlns:data="using:Google.Apis.Oauth2.v2.Data"
Style="{StaticResource AppBarButtonRevealStyle}" Loaded="AppBarButton_Loaded"
Loaded="AppBarButton_Loaded"> Style="{StaticResource ButtonRevealStyle}"
CornerRadius="0"
Padding="10,0"
Height="32"
Background="Transparent">
<AppBarButton.Icon> <StackPanel Orientation="Horizontal">
<FontIcon Glyph="&#xE1E2;"/> <FontIcon Glyph="&#xE1E2;" x:Name="icon" FontSize="15" Visibility="Visible"/>
</AppBarButton.Icon> <PersonPicture Width="20" x:Name="profileIcon" Visibility="Collapsed"/>
<TextBlock x:Name="buttonLabel" Text="Sign in" Margin="10,0,0,0" Style="{StaticResource CaptionTextBlockStyle}" VerticalAlignment="Center"/>
<AppBarButton.Flyout> </StackPanel>
<Flyout Opening="Flyout_Opening">
<StackPanel Margin="-12" Width="300"> <Button.Flyout>
<Grid Height="60"> <Flyout Opening="Flyout_Opening">
<controls:ImageEx x:Name="banner" Stretch="UniformToFill" <StackPanel Margin="-12" Width="300">
<Grid Height="60">
<controls:ImageEx x:Name="bannerImage" Stretch="UniformToFill"
PlaceholderSource="/Assets/DefaultChannelBanner.png" PlaceholderSource="/Assets/DefaultChannelBanner.png"
PlaceholderStretch="UniformToFill"/> PlaceholderStretch="UniformToFill"/>
<Grid Padding="10" ColumnSpacing="20"> <Grid Padding="10" ColumnSpacing="20" RequestedTheme="Dark">
<Grid.Background> <Grid.Background>
<AcrylicBrush TintColor="Black" TintOpacity=".2"/> <AcrylicBrush FallbackColor="Transparent" TintColor="Black" TintOpacity="0" TintLuminosityOpacity=".5" Opacity=".9"/>
</Grid.Background> </Grid.Background>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/>
<ColumnDefinition/> <ColumnDefinition/>
</Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/>
<PersonPicture Height="40" x:Name="avatar"/> </Grid.ColumnDefinitions>
<StackPanel Grid.Column="1"> <PersonPicture Height="40" x:Name="avatar"/>
<TextBlock x:Name="name" Text="█████████"/> <StackPanel Grid.Column="1">
<TextBlock x:Name="email" Text="██████████████████"/> <TextBlock x:Name="name" Text="[Name]"/>
</StackPanel> <TextBlock x:Name="email" Text="[email]" FontStyle="Italic"/>
</Grid> </StackPanel>
</Grid> <Button FontFamily="Segoe MDL2 Assets" Content="&#xE115;" ToolTipService.ToolTip="Account settings" Grid.Column="2" Background="Transparent"/>
<ui:NavigationViewList> </Grid>
<ui:NavigationViewItem Icon="Contact" Content="My channel"/> </Grid>
<ui:NavigationViewItem Icon="Upload" Content="Upload a video"/> <NavigationViewList>
<ui:NavigationViewItem Content="Start a broadcast"> <NavigationViewItem Tapped="NavigationViewItem_Tapped" Icon="Contact" Content="My channel" Tag="channel"/>
<ui:NavigationViewItem.Icon> <NavigationViewItem Tapped="NavigationViewItem_Tapped" Icon="Upload" Content="Upload a video" Tag="upload"/>
<FontIcon Glyph="&#xE93E;"/> <NavigationViewItem Tapped="NavigationViewItem_Tapped" Content="Start a broadcast" Tag="broadcast">
</ui:NavigationViewItem.Icon> <NavigationViewItem.Icon>
</ui:NavigationViewItem> <FontIcon Glyph="&#xE93E;"/>
<ui:NavigationViewItem Content="Creator Stuido"> </NavigationViewItem.Icon>
<ui:NavigationViewItem.Icon> </NavigationViewItem>
<FontIcon Glyph="&#xE2B1;"/> <NavigationViewItem Tapped="NavigationViewItem_Tapped" Content="Creator Stuido" Tag="creatorStudio">
</ui:NavigationViewItem.Icon> <NavigationViewItem.Icon>
</ui:NavigationViewItem> <FontIcon Glyph="&#xE2B1;"/>
<ui:NavigationViewItemSeparator/> </NavigationViewItem.Icon>
<ui:NavigationViewItem Content="Sign out" Foreground="Red"> </NavigationViewItem>
<ui:NavigationViewItem.Icon> </NavigationViewList>
<FontIcon Glyph="&#xE1E0;"/> <NavigationViewList ItemClick="SwitchUser" IsItemClickEnabled="True" x:Name="usersList">
</ui:NavigationViewItem.Icon> <NavigationViewList.ItemTemplate>
</ui:NavigationViewItem> <DataTemplate x:DataType="data:Userinfoplus">
</ui:NavigationViewList> <StackPanel Orientation="Horizontal" Padding="5" Margin="-5,0,0,0">
</StackPanel> <ui:PersonPicture Height="20" Margin="-5,0,15,0">
</Flyout> <ui:PersonPicture.ProfilePicture>
</AppBarButton.Flyout> <BitmapImage UriSource="{Binding Picture}" DecodePixelHeight="20" DecodePixelWidth="20"/>
</AppBarButton> </ui:PersonPicture.ProfilePicture>
</ui:PersonPicture>
<StackPanel>
<TextBlock FontSize="14" Text="{Binding Name, TargetNullValue='[name]'}"/>
<TextBlock Style="{StaticResource CaptionTextBlockStyle}" Text="{Binding Email}" Margin="0,-6,0,0"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</NavigationViewList.ItemTemplate>
<NavigationViewItemHeader Content="Switch account"/>
</NavigationViewList>
<NavigationViewList>
<NavigationViewItemSeparator/>
<NavigationViewItem Tapped="NavigationViewItem_Tapped" x:Name="addAccountButton" Content="Add account" Tag="addUser" Icon="Add"/>
<NavigationViewItem Tapped="NavigationViewItem_Tapped" Content="Sign out" Foreground="Red" Tag="logout">
<NavigationViewItem.Icon>
<FontIcon Glyph="&#xE1E0;"/>
</NavigationViewItem.Icon>
</NavigationViewItem>
</NavigationViewList>
</StackPanel>
</Flyout>
</Button.Flyout>
</Button>
+81 -32
View File
@@ -1,43 +1,92 @@
using Windows.UI.Xaml.Controls; using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using FoxTube.Models;
using System.Linq;
using Google.Apis.Oauth2.v2.Data;
using Windows.UI.Xaml.Media.Imaging; using Windows.UI.Xaml.Media.Imaging;
namespace FoxTube.Controls namespace FoxTube.Controls
{ {
public sealed partial class AccountManager : AppBarButton public sealed partial class AccountManager : Button
{ {
public AccountManager() => private User CurrentUser { get; set; }
InitializeComponent();
async void Flyout_Opening(object sender, object e) public AccountManager() =>
{ InitializeComponent();
if (UsersControl.Authorized)
return;
(sender as Flyout).Hide(); private async void Flyout_Opening(object sender, object e)
{
if (UserManagement.Authorized)
return;
if (await UsersControl.AddUser()) (sender as Flyout).Hide();
UpdateData();
}
void AppBarButton_Loaded(object sender, Windows.UI.Xaml.RoutedEventArgs e) await UserManagement.AddUser();
{ }
if (UsersControl.Authorized)
UpdateData();
else
MainPage.Current.Update();
}
void UpdateData() private void AppBarButton_Loaded(object sender, RoutedEventArgs e)
{ {
Label = UsersControl.CurrentUser.UserInfo.Name; if (UserManagement.Authorized)
Icon = new SymbolIcon(Symbol.Contact); UpdateData(true);
banner.Source = new BitmapImage(UsersControl.CurrentUser.Channel.BrandingSettings.Image.BannerMobileLowImageUrl.ToUri()) { DecodePixelWidth = 300, DecodePixelHeight = 60 }; UserManagement.UserStateUpdated += (s, e) => UpdateData(e);
avatar.ProfilePicture = new BitmapImage(UsersControl.CurrentUser.Channel.Snippet.Thumbnails.Default__.Url.ToUri()) { DecodePixelHeight = 40, DecodePixelWidth = 40 }; }
name.Text = UsersControl.CurrentUser.UserInfo.Name;
email.Text = UsersControl.CurrentUser.UserInfo.Email;
MainPage.Current.Update(); private void UpdateData(bool authorized)
} {
} CurrentUser = UserManagement.CurrentUser;
} if (authorized)
{
buttonLabel.Text = name.Text = CurrentUser.Channel.Snippet.Title;
email.Text = CurrentUser.UserInfo.Email;
profileIcon.ProfilePicture = new BitmapImage().LoadImage(CurrentUser.Channel.Snippet.Thumbnails.Default__.Url, 20, 20);
avatar.ProfilePicture = new BitmapImage().LoadImage(CurrentUser.Channel.Snippet.Thumbnails.Default__.Url, 40, 40);
bannerImage.Source = new BitmapImage().LoadImage(CurrentUser.Channel.BrandingSettings.Image.BannerMobileLowImageUrl, 60);
ToolTipService.SetToolTip(this, $"{CurrentUser.UserInfo.Name} ({CurrentUser.UserInfo.Email})");
icon.Visibility = Visibility.Collapsed;
profileIcon.Visibility = Visibility.Visible;
var users = UserManagement.Users.Where(i => i.Id != CurrentUser.UserInfo.Id).ToList();
usersList.ItemsSource = users;
usersList.Visibility = users.Count > 0 ? Visibility.Visible : Visibility.Visible;
addAccountButton.Visibility = UserManagement.CanAddAccounts ? Visibility.Visible : Visibility.Collapsed;
}
else
{
buttonLabel.Text = name.Text = "Sign in";
ToolTipService.SetToolTip(this, null);
icon.Visibility = Visibility.Visible;
profileIcon.Visibility = Visibility.Collapsed;
}
}
private async void SwitchUser(object sender, ItemClickEventArgs e)
{
Userinfoplus user = (Userinfoplus)e.ClickedItem;
await UserManagement.SwitchUser(UserManagement.Users.ToList().IndexOf(user));
}
private async void NavigationViewItem_Tapped(object sender, Windows.UI.Xaml.Input.TappedRoutedEventArgs e)
{
switch ((sender as NavigationViewItem).Tag as string)
{
case "channel":
case "upload":
case "broadcast":
case "creatorStudio":
break;
case "addUser":
await UserManagement.AddUser();
break;
case "logout":
await UserManagement.Logout();
break;
}
}
}
}
+30 -42
View File
@@ -5,60 +5,48 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls" xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
xmlns:Windows10version1809="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractPresent(Windows.Foundation.UniversalApiContract, 7)"
mc:Ignorable="d" mc:Ignorable="d"
d:DesignHeight="300" d:DesignHeight="300"
d:DesignWidth="400" d:DesignWidth="400"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
Margin="3" Margin="3"
SizeChanged="UserControl_SizeChanged" SizeChanged="UserControl_SizeChanged"
Visibility="Collapsed"
Opacity="0"> Opacity="0">
<UserControl.OpacityTransition> <UserControl.OpacityTransition>
<ScalarTransition/> <ScalarTransition/>
</UserControl.OpacityTransition> </UserControl.OpacityTransition>
<controls:DropShadowPanel BlurRadius="10" ShadowOpacity=".5" <Button Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}" Style="{StaticResource ButtonRevealStyle}" CornerRadius="5" Padding="0" VerticalAlignment="Stretch" VerticalContentAlignment="Stretch">
OffsetX="2" OffsetY="2" <Grid RowSpacing="5" x:Name="grid">
Color="Black" <Grid.RowDefinitions>
HorizontalContentAlignment="Stretch" <RowDefinition Height="Auto"/>
VerticalContentAlignment="Stretch"> <RowDefinition Height="20"/>
<Button Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}" Style="{StaticResource ButtonRevealStyle}" Windows10version1809:CornerRadius="5" Padding="0" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> <RowDefinition/>
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" RowSpacing="5" x:Name="grid"> </Grid.RowDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="20"/>
<RowDefinition/>
</Grid.RowDefinitions>
<controls:ImageEx PlaceholderStretch="UniformToFill" CornerRadius="5,5,0,0" PlaceholderSource="/Assets/DefaultVideoThumbnail.png" Source="{Binding advert.MainImages[0].Url}"/> <controls:ImageEx PlaceholderStretch="UniformToFill" CornerRadius="5,5,0,0" PlaceholderSource="/Assets/DefaultVideoThumbnail.png" Source="{Binding advert.MainImages[0].Url}"/>
<controls:DropShadowPanel VerticalAlignment="Top" HorizontalAlignment="Left" Margin="5" OffsetX="2" OffsetY="2"> <StackPanel Padding="5,2,5,3" Background="Orange" CornerRadius="5" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="5">
<StackPanel Padding="5,2,5,3" Background="Orange" CornerRadius="5"> <TextBlock Text="Sponsored content" Foreground="Black" Style="{StaticResource CaptionTextBlockStyle}"/>
<TextBlock Text="Sponsored content" Foreground="Black" FontSize="12"/> </StackPanel>
</StackPanel>
</controls:DropShadowPanel>
<controls:DropShadowPanel VerticalAlignment="Bottom" HorizontalAlignment="Right" Margin="5,10" OffsetX="2" OffsetY="2" x:Name="cta"> <StackPanel Padding="5,2,5,3" Background="Yellow" CornerRadius="5" VerticalAlignment="Bottom" HorizontalAlignment="Right" Margin="5" x:Name="cta">
<StackPanel Padding="5,2,5,3" Background="Yellow" CornerRadius="5"> <TextBlock Text="{x:Bind advert.CallToActionText}" MaxLines="1" Foreground="Black" Style="{StaticResource CaptionTextBlockStyle}"/>
<TextBlock Text="{x:Bind advert.CallToActionText}" Foreground="Black" FontSize="12"/> </StackPanel>
</StackPanel>
</controls:DropShadowPanel>
<Grid Grid.Row="1" ColumnSpacing="10" Margin="10,0"> <Grid Grid.Row="1" ColumnSpacing="10" Margin="10,0">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/>
<ColumnDefinition/> <ColumnDefinition/>
<ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<controls:ImageEx CornerRadius="999" BorderThickness="3" BorderBrush="{ThemeResource SystemControlBackgroundChromeMediumBrush}" Background="Red" <controls:ImageEx CornerRadius="999" BorderThickness="3" BorderBrush="{ThemeResource SystemControlBackgroundChromeMediumBrush}" Background="Red"
Width="50" Height="50" VerticalAlignment="Bottom" Margin="0,-30,0,0" PlaceholderSource="/Assets/Icons/Contact.png" PlaceholderStretch="UniformToFill" Source="{x:Bind advert.AdIcon}"/> Width="50" Height="50" VerticalAlignment="Bottom" Margin="0,-30,0,0" PlaceholderSource="/Assets/Icons/Contact.png" PlaceholderStretch="UniformToFill" Source="{x:Bind advert.AdIcon}"/>
<TextBlock Text="{x:Bind advert.SponsoredBy}" Grid.Column="1"/> <TextBlock Text="{x:Bind advert.SponsoredBy}" Grid.Column="1" MaxLines="1"/>
<TextBlock x:Name="description" Text="" Grid.Column="2"/> <TextBlock x:Name="description" Grid.Column="2" MaxLines="1" Foreground="Gray"/>
</Grid> </Grid>
<TextBlock Margin="10,0" Grid.Row="2" MaxLines="2" TextTrimming="CharacterEllipsis" TextWrapping="WrapWholeWords" Text="{x:Bind advert.Title}"/> <TextBlock Margin="10,0" Grid.Row="2" MaxLines="2" Text="{x:Bind advert.Title}"/>
</Grid> </Grid>
</Button> </Button>
</controls:DropShadowPanel>
</UserControl> </UserControl>
+42 -39
View File
@@ -1,51 +1,54 @@
using FoxTube.Core.Helpers; using FoxTube.Utils;
using Microsoft.Advertising.WinRT.UI; using Microsoft.Advertising.WinRT.UI;
using Microsoft.Toolkit.Uwp.UI.Controls;
using Windows.UI.Xaml; using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls;
namespace FoxTube.Controls.Cards namespace FoxTube.Controls.Cards
{ {
/// <summary> /// <summary>
/// Advert which is looks similar to video cards /// Advert which is looks similar to video cards
/// </summary> /// </summary>
public sealed partial class AdvertCard : UserControl public sealed partial class AdvertCard : UserControl
{ {
NativeAdsManagerV2 manager = new NativeAdsManagerV2(Constants.ApplicationId, Constants.AdsId); readonly NativeAdsManagerV2 manager = new NativeAdsManagerV2(StoreInterop.ApplicationId, StoreInterop.AdsId);
NativeAdV2 advert; NativeAdV2 advert;
public AdvertCard()
{
InitializeComponent();
manager.AdReady += AdReady;
manager.ErrorOccurred += ErrorOccurred;
manager.RequestAd();
}
void ErrorOccurred(object sender, NativeAdErrorEventArgs e) public AdvertCard()
{ {
(Parent as StaggeredPanel)?.Children.Remove(this); InitializeComponent();
Metrics.AddEvent("Error has occured while loading ad", manager.AdReady += AdReady;
("Code", e.ErrorCode.ToString()), manager.ErrorOccurred += ErrorOccurred;
("Message", e.ErrorMessage), manager.RequestAd();
("Request ID", e.RequestId)); }
}
void AdReady(object sender, NativeAdReadyEventArgs e) void ErrorOccurred(object sender, NativeAdErrorEventArgs e)
{ {
advert = e.NativeAd; (Parent as Panel)?.Children.Remove(this);
Metrics.AddEvent("Error has occured while loading ad",
if (string.IsNullOrWhiteSpace(advert.CallToActionText)) ("Code", e.ErrorCode.ToString()),
cta.Visibility = Visibility.Collapsed; ("Message", e.ErrorMessage),
("Request ID", e.RequestId));
}
description.Text += $"{advert.Price} {advert.Rating}"; void AdReady(object sender, NativeAdReadyEventArgs e)
{
advert = e.NativeAd;
e.NativeAd.RegisterAdContainer(grid); if (string.IsNullOrWhiteSpace(advert.CallToActionText))
cta.Visibility = Visibility.Collapsed;
Metrics.AddEvent("Advert loaded", description.Text = $"{advert.Price} {advert.Rating}";
("Region", Settings.Region),
("Version", Metrics.CurrentVersion)); e.NativeAd.RegisterAdContainer(grid);
}
void UserControl_SizeChanged(object sender, SizeChangedEventArgs e) => Opacity = 1;
Height = .75 * ActualWidth;
} Metrics.AddEvent("Advert loaded",
("Region", Settings.Region),
("Version", Metrics.CurrentVersion));
}
void UserControl_SizeChanged(object sender, SizeChangedEventArgs e) =>
Height = .75 * ActualWidth;
}
} }
+71 -69
View File
@@ -5,86 +5,88 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls" xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
xmlns:Windows10version1809="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractPresent(Windows.Foundation.UniversalApiContract, 7)"
mc:Ignorable="d" mc:Ignorable="d"
d:DesignHeight="300" d:DesignHeight="300"
d:DesignWidth="400" d:DesignWidth="400"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
Margin="3" Margin="3"
SizeChanged="UserControl_SizeChanged"> Opacity="0">
<UserControl.OpacityTransition>
<ScalarTransition/>
</UserControl.OpacityTransition>
<Button Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}" Style="{StaticResource ButtonRevealStyle}" Windows10version1809:CornerRadius="5" Padding="0" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> <Button Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}" Style="{StaticResource ButtonRevealStyle}" CornerRadius="5" Padding="0" VerticalContentAlignment="Stretch" VerticalAlignment="Stretch">
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" RowSpacing="5"> <Grid RowSpacing="5">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/>
<RowDefinition Height="20"/> <RowDefinition Height="20"/>
<RowDefinition/> <RowDefinition/>
</Grid.RowDefinitions> </Grid.RowDefinitions>
<controls:ImageEx PlaceholderStretch="UniformToFill" CornerRadius="5,5,0,0" PlaceholderSource="/Assets/DefaultVideoThumbnail.png"/> <controls:ImageEx PlaceholderStretch="UniformToFill" CornerRadius="5,5,0,0" PlaceholderSource="/Assets/DefaultVideoThumbnail.png" Source="{x:Bind VideoData.Snippet.Thumbnails.Maxres.Url}"/>
<Grid> <Grid x:Name="watched" Visibility="Collapsed">
<Grid.Background> <Grid.Background>
<SolidColorBrush Color="Black" Opacity=".5"/> <SolidColorBrush Color="Black" Opacity=".5"/>
</Grid.Background> </Grid.Background>
<controls:DropShadowPanel VerticalAlignment="Top" HorizontalAlignment="Left" Margin="10" OffsetX="2" OffsetY="2">
<StackPanel Padding="5,2,5,3" Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}" CornerRadius="5"> <StackPanel Padding="5,2,5,3" Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}" CornerRadius="5" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="5">
<TextBlock Text="Watched" Foreground="Gray" FontSize="12"/> <TextBlock Text="Watched" Foreground="Gray" Style="{StaticResource CaptionTextBlockStyle}"/>
</StackPanel> </StackPanel>
</controls:DropShadowPanel> <ProgressBar VerticalAlignment="Bottom" Margin="59,0,0,0" Value="50"/>
<ProgressBar VerticalAlignment="Bottom" Margin="59,0,0,0" Foreground="Red" Value="50"/> </Grid>
</Grid>
<controls:DropShadowPanel VerticalAlignment="Bottom" HorizontalAlignment="Right" Margin="5,10" OffsetX="2" OffsetY="2"> <StackPanel Padding="5,2,5,3" Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}" CornerRadius="5" VerticalAlignment="Bottom" HorizontalAlignment="Right" Margin="5,10">
<StackPanel Padding="5,2,5,3" Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}" CornerRadius="5"> <TextBlock Text="[Duration] • [Timestamp]" Foreground="Gray" Style="{StaticResource CaptionTextBlockStyle}"/>
<TextBlock Text="██████ • ██████" Foreground="Gray" FontSize="12"/> </StackPanel>
</StackPanel>
</controls:DropShadowPanel>
<controls:DropShadowPanel VerticalAlignment="Bottom" HorizontalAlignment="Right" Margin="5,35" OffsetX="2" OffsetY="2"> <StackPanel Padding="5,2,5,3" Background="Red" BorderThickness="1" BorderBrush="White" CornerRadius="5" Orientation="Horizontal" VerticalAlignment="Bottom" HorizontalAlignment="Right" Margin="5,35" Visibility="Collapsed">
<StackPanel Padding="5,2,5,3" Background="Red" BorderThickness="1" BorderBrush="White" CornerRadius="5" Orientation="Horizontal"> <FontIcon Glyph="&#xEC44;" VerticalAlignment="Center" Foreground="White" FontSize="12" Margin="0,0,5,0"/>
<FontIcon Glyph="&#xEC44;" VerticalAlignment="Center" Foreground="White" FontSize="12" Margin="0,0,5,0"/> <TextBlock Text="LIVE" VerticalAlignment="Center" Foreground="White" Style="{StaticResource CaptionTextBlockStyle}" FontWeight="Bold"/>
<TextBlock Text="LIVE" VerticalAlignment="Center" Foreground="White" FontSize="12" FontWeight="Bold"/> </StackPanel>
</StackPanel>
</controls:DropShadowPanel>
<Grid Grid.Row="1" ColumnSpacing="10" Margin="10,0"> <Grid Grid.Row="1" ColumnSpacing="10" Margin="10,0">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/>
<ColumnDefinition/> <ColumnDefinition/>
<ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<controls:ImageEx CornerRadius="999" BorderThickness="3" BorderBrush="{ThemeResource SystemControlBackgroundChromeMediumBrush}" Background="Red" <controls:ImageEx CornerRadius="999" BorderThickness="3" BorderBrush="{ThemeResource SystemControlBackgroundChromeMediumBrush}" Background="Red"
Width="50" Height="50" VerticalAlignment="Bottom" Margin="0,-30,0,0" PlaceholderSource="/Assets/Icons/Contact.png" PlaceholderStretch="UniformToFill"/> Width="50" Height="50" VerticalAlignment="Bottom" Margin="0,-30,0,0" PlaceholderSource="/Assets/Icons/Contact.png" PlaceholderStretch="UniformToFill"/>
<TextBlock Text="██████████" Grid.Column="1" TextTrimming="CharacterEllipsis"/> <TextBlock Text="{x:Bind VideoData.Snippet.ChannelTitle}" Grid.Column="1" MaxLines="1"/>
<TextBlock Text="██████████" Grid.Column="2" Foreground="Gray"/> <TextBlock Text="[Views]" Grid.Column="2" MaxLines="1" Foreground="Gray"/>
</Grid> </Grid>
<TextBlock Margin="10,0" Grid.Row="2" MaxLines="2" TextTrimming="CharacterEllipsis" TextWrapping="WrapWholeWords" Text="██████████"/> <TextBlock Margin="10,0" Grid.Row="2" MaxLines="2" Text="{x:Bind VideoData.Snippet.Title}"/>
</Grid> </Grid>
<Button.ContextFlyout> <Button.ContextFlyout>
<MenuFlyout> <MenuFlyout>
<MenuFlyoutItem Icon="Play" Text="Play"/> <MenuFlyoutItem Icon="Play" Text="Play"/>
<MenuFlyoutItem Text="Play incognito"> <MenuFlyoutItem Text="Play incognito">
<MenuFlyoutItem.Icon> <MenuFlyoutItem.Icon>
<FontIcon Glyph="&#xE727;"/> <FontIcon Glyph="&#xE727;"/>
</MenuFlyoutItem.Icon> </MenuFlyoutItem.Icon>
</MenuFlyoutItem> </MenuFlyoutItem>
<MenuFlyoutItem Icon="Contact" Text="View channel"/> <MenuFlyoutItem Text="Open in picture-in-picture mode">
<MenuFlyoutSeparator/> <MenuFlyoutItem.Icon>
<MenuFlyoutItem Icon="Link" Text="Copy link"/> <FontIcon Glyph="&#xE2B3;"/>
<MenuFlyoutItem Icon="Globe" Text="Open in browser"/> </MenuFlyoutItem.Icon>
<MenuFlyoutItem Icon="Share" Text="Share"/> </MenuFlyoutItem>
<MenuFlyoutSeparator/> <MenuFlyoutItem Icon="Contact" Text="View channel"/>
<MenuFlyoutSubItem Icon="Download" Text="Download"/> <MenuFlyoutSeparator/>
<MenuFlyoutSubItem Icon="Add" Text="Add to"> <MenuFlyoutItem Icon="Link" Text="Copy link"/>
<MenuFlyoutItem Text="New playlist" Icon="Add"/> <MenuFlyoutItem Icon="Globe" Text="Open in browser"/>
<ToggleMenuFlyoutItem Text="Watch later" Icon="Clock"/> <MenuFlyoutItem Icon="Share" Text="Share"/>
<MenuFlyoutSeparator/> <MenuFlyoutSeparator/>
</MenuFlyoutSubItem> <MenuFlyoutSubItem Icon="Download" Text="Download"/>
<MenuFlyoutItem Text="Remove from playlist" Icon="Delete" Visibility="Visible" Foreground="Red"/> <MenuFlyoutSubItem Icon="Add" Text="Add to">
</MenuFlyout> <MenuFlyoutItem Text="New playlist" Icon="Add"/>
</Button.ContextFlyout> <ToggleMenuFlyoutItem Text="Watch later" Icon="Clock"/>
</Button> <MenuFlyoutSeparator/>
</UserControl> </MenuFlyoutSubItem>
<MenuFlyoutItem Text="Remove from playlist" Icon="Delete" Visibility="Visible" Foreground="Red"/>
</MenuFlyout>
</Button.ContextFlyout>
</Button>
</UserControl>
+22 -9
View File
@@ -1,14 +1,27 @@
using Windows.UI.Xaml; using Google.Apis.YouTube.v3.Data;
using System.Collections.Generic;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls;
namespace FoxTube.Controls.Cards namespace FoxTube.Controls.Cards
{ {
public sealed partial class VideoCard : UserControl public sealed partial class VideoCard : UserControl
{ {
public VideoCard() => Video VideoData { get; set; }
InitializeComponent();
void UserControl_SizeChanged(object sender, SizeChangedEventArgs e) => public VideoCard(Video meta)
Height = .75 * ActualWidth; {
} InitializeComponent();
}
VideoData = meta;
Opacity = 1;
}
public VideoCard(Video meta, Playlist playlist, IEnumerable<PlaylistItem> playlistItems) =>
InitializeComponent();
//void UserControl_SizeChanged(object sender, SizeChangedEventArgs e) =>
// Height = .75 * ActualWidth;
}
}
@@ -0,0 +1,40 @@
<ContentDialog
x:Class="FoxTube.Controls.Dialogs.DownloadVideoDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
mc:Ignorable="d"
Title="Download video"
Loading="ContentDialog_Loading"
IsPrimaryButtonEnabled="False"
PrimaryButtonClick="ContentDialog_PrimaryButtonClick"
PrimaryButtonText="Download"
CloseButtonText="Cancel"
DefaultButton="Primary">
<StackPanel>
<Grid Height="60" ColumnSpacing="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<controls:ImageEx PlaceholderSource="/Assets/DefaultVideoThumbnail.png" Stretch="UniformToFill" Source="{x:Bind Meta.Thumbnails.LowResUrl}" PlaceholderStretch="UniformToFill"/>
<StackPanel Grid.Column="1">
<TextBlock Text="{x:Bind Meta.Title}"/>
<TextBlock Text="{x:Bind Meta.Author}" Style="{StaticResource CaptionTextBlockStyle}" FontStyle="Italic"/>
<TextBlock Text="{x:Bind Meta.Duration}" Style="{StaticResource CaptionTextBlockStyle}" Foreground="Gray"/>
</StackPanel>
</Grid>
<ComboBox Header="Select download quality" HorizontalAlignment="Stretch" PlaceholderText="No qualities available to download" SelectedIndex="0" Margin="0,5" x:Name="qualitiesList" SelectionChanged="SelectionChanged"/>
<TextBox IsReadOnly="True" Header="Location" PlaceholderText="Folder/FileName" x:Name="location"/>
<Button Content="Change" HorizontalAlignment="Right" Margin="0,5" Click="SelectSaveLocation"/>
</StackPanel>
</ContentDialog>
@@ -0,0 +1,72 @@
using System;
using System.Linq;
using Windows.Storage;
using Windows.Storage.Pickers;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using YoutubeExplode.Videos;
using YoutubeExplode.Videos.Streams;
namespace FoxTube.Controls.Dialogs
{
public sealed partial class DownloadVideoDialog : ContentDialog
{
public Video Meta { get; set; }
public StreamManifest Manifest { get; set; }
public StorageFile File { get; set; }
public DownloadVideoDialog(Video meta, StreamManifest manifest)
{
InitializeComponent();
Meta = meta;
Manifest = manifest;
foreach (MuxedStreamInfo i in manifest.GetMuxed())
qualitiesList.Items.Add(new ComboBoxItem
{
Content = i.VideoQualityLabel,
Tag = i
});
AudioOnlyStreamInfo audioStream = manifest.GetAudioOnly().FirstOrDefault();
if (audioStream != null)
qualitiesList.Items.Add(new ComboBoxItem
{
Content = "Audio track only",
Tag = audioStream
});
}
private async void ContentDialog_Loading(FrameworkElement sender, object args)
{
StorageFolder defaultFolder = await Services.DownloadsCenter.GetDefaultDownloadsFolder();
location.Text = $"{defaultFolder.Name}\\{Meta.Title.ReplaceInvalidChars('_')}.mp4";
}
private async void SelectSaveLocation(object sender, RoutedEventArgs e)
{
FileSavePicker picker = new FileSavePicker
{
SuggestedFileName = Meta.Title.ReplaceInvalidChars('_'),
DefaultFileExtension = ".mp4",
SuggestedStartLocation = PickerLocationId.VideosLibrary
};
picker.FileTypeChoices.Add("Video file", new[] { ".mp4" });
File = await picker.PickSaveFileAsync();
location.Text = $"{(await File.GetParentAsync()).Name}\\{File.Name}";
}
private void SelectionChanged(object sender, SelectionChangedEventArgs e) =>
IsPrimaryButtonEnabled = true;
private void ContentDialog_PrimaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args)
{
}
}
}
@@ -0,0 +1,22 @@
<ContentDialog
x:Class="FoxTube.Controls.Dialogs.ProOfferDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="What's you get in PRO version"
PrimaryButtonText="Purchase"
CloseButtonText="Close"
DefaultButton="Primary"
PrimaryButtonClick="ContentDialog_PrimaryButtonClick">
<StackPanel>
<TextBlock>
- Several downloads at time
<LineBreak/>- No ads
<LineBreak/>- Custom theme accent color
<LineBreak/>- Multiple accounts management
</TextBlock>
</StackPanel>
</ContentDialog>
@@ -0,0 +1,31 @@
using FoxTube.Utils;
using System;
using Windows.UI.Xaml.Controls;
namespace FoxTube.Controls.Dialogs
{
public sealed partial class ProOfferDialog : ContentDialog
{
public ProOfferDialog() =>
InitializeComponent();
private async void ContentDialog_PrimaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args)
{
if (!await StoreInterop.PurchaseApp())
return;
ContentDialog dialog = new ContentDialog
{
Title = "Thank you for your purchase!",
Content = "Thanks for purchasing full version of the app (^∇^)\n" +
"In order to complete changes we need to reopen it. Or you can do it later (but some elements may be broken)",
PrimaryButtonText = "Restart",
CloseButtonText = "Later",
DefaultButton = ContentDialogButton.Primary
};
dialog.PrimaryButtonClick += (s, e) => Utils.Utils.RestartApp();
await dialog.ShowAsync();
}
}
}
+76
View File
@@ -0,0 +1,76 @@
<ListViewItem
x:Class="FoxTube.Controls.DownloadListItem"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
mc:Ignorable="d"
d:DesignHeight="100"
HorizontalContentAlignment="Stretch"
Padding="5">
<ListViewItem.ContextFlyout>
<MenuFlyout>
<MenuFlyoutItem Text="Delete" Icon="Delete"/>
<MenuFlyoutItem Text="Select">
<MenuFlyoutItem.Icon>
<FontIcon Glyph="&#xE762;"/>
</MenuFlyoutItem.Icon>
</MenuFlyoutItem>
</MenuFlyout>
</ListViewItem.ContextFlyout>
<controls:DropShadowPanel HorizontalContentAlignment="Stretch">
<Grid Padding="10" ColumnSpacing="10" Background="{ThemeResource SystemChromeLowColor}" CornerRadius="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<controls:ImageEx PlaceholderStretch="UniformToFill" CornerRadius="2" Height="75" PlaceholderSource="/Assets/DefaultVideoThumbnail.png"/>
<Border CornerRadius="5,0,0,0" Background="{StaticResource SystemChromeMediumColor}" VerticalAlignment="Bottom" HorizontalAlignment="Right" Padding="10,2">
<TextBlock Text="2:13:45" Style="{StaticResource CaptionTextBlockStyle}"/>
</Border>
<StackPanel Grid.Column="1">
<TextBlock Text="[Quality] Video title" Style="{StaticResource TitleTextBlockStyle}" MaxLines="1"/>
<TextBlock Text="Author" MaxLines="1"/>
<TextBlock Text="video_file_path.mp4" Style="{StaticResource CaptionTextBlockStyle}" MaxLines="1"/>
</StackPanel>
<StackPanel Grid.Column="2" Orientation="Horizontal" Visibility="Collapsed">
<Button Width="75" Height="75" Padding="0" Background="Transparent">
<StackPanel>
<TextBlock Text="&#xED25;" FontFamily="Segoe MDL2 Assets" FontSize="30" HorizontalAlignment="Center"/>
<TextBlock Text="Open" TextWrapping="WrapWholeWords" HorizontalTextAlignment="Center"/>
</StackPanel>
</Button>
<Button Width="75" Height="75" Padding="0" Background="Transparent" Margin="10,0,0,0">
<StackPanel>
<TextBlock Text="&#xE2B4;" FontFamily="Segoe MDL2 Assets" FontSize="30" HorizontalAlignment="Center"/>
<TextBlock Text="Go to original" TextWrapping="WrapWholeWords" HorizontalTextAlignment="Center" HorizontalAlignment="Center"/>
</StackPanel>
</Button>
</StackPanel>
<Grid Grid.Column="2" RowSpacing="5" VerticalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Text="Downloading..." RelativePanel.Above="progressBar"/>
<TextBlock Text="50%" RelativePanel.AlignRightWithPanel="True" RelativePanel.Above="progressBar" Grid.Column="1" HorizontalAlignment="Right"/>
<ProgressBar Value="50" Width="200" Grid.Row="1" Grid.ColumnSpan="2"/>
<Button Content="&#xE106;" ToolTipService.ToolTip="Cancel" RelativePanel.Below="progressBar" RelativePanel.AlignRightWithPanel="True" Background="Transparent" FontFamily="Segoe MDL2 Assets" Grid.Column="1" Grid.Row="2" HorizontalAlignment="Right"/>
</Grid>
</Grid>
</controls:DropShadowPanel>
</ListViewItem>
+14
View File
@@ -0,0 +1,14 @@
using Windows.UI.Xaml.Controls;
// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236
namespace FoxTube.Controls
{
public sealed partial class DownloadListItem : ListViewItem
{
public DownloadListItem()
{
this.InitializeComponent();
}
}
}
+87 -12
View File
@@ -1,21 +1,96 @@
<UserControl <Grid
x:Class="FoxTube.Controls.ItemsGrid" x:Class="FoxTube.Controls.ItemsGrid"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls" xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
mc:Ignorable="d" xmlns:models="using:FoxTube.Models"
xmlns:controls1="using:FoxTube.Controls"
mc:Ignorable="d"
d:DesignHeight="1080" d:DesignHeight="1080"
d:DesignWidth="1920"> d:DesignWidth="1920">
<Grid> <TextBlock Text="&#xD8;" FontSize="100" Foreground="Gray" Opacity="0" x:Name="empty" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<controls:StaggeredPanel x:Name="grid" DesiredColumnWidth="350"/>
<controls:AdaptiveGridView x:Name="grid" DesiredWidth="400" Padding="5">
<controls:AdaptiveGridView.ItemContainerTransitions>
<TransitionCollection>
<EntranceThemeTransition IsStaggeringEnabled="True"/>
<AddDeleteThemeTransition/>
</TransitionCollection>
</controls:AdaptiveGridView.ItemContainerTransitions>
<controls:DropShadowPanel x:Name="empty" HorizontalAlignment="Center" VerticalAlignment="Center" <controls:AdaptiveGridView.ItemTemplate>
BlurRadius="10" ShadowOpacity=".5" <DataTemplate x:DataType="models:VideoItem">
OffsetX="2" OffsetY="2"> <Grid RowSpacing="5" CornerRadius="5" Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}" Padding="0,0,0,10">
<TextBlock Text="&#xD8;" FontSize="100" Foreground="Gray"/> <Grid.RowDefinitions>
</controls:DropShadowPanel> <RowDefinition Height="Auto"/>
</Grid> <RowDefinition Height="20"/>
</UserControl> <RowDefinition Height="38"/>
</Grid.RowDefinitions>
<controls:ImageEx PlaceholderStretch="UniformToFill" CornerRadius="5,5,0,0" PlaceholderSource="/Assets/DefaultVideoThumbnail.png" Source="{x:Bind Meta.Snippet.Thumbnails.Maxres.Url}"/>
<StackPanel Padding="5,2,5,3" Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}" CornerRadius="5" VerticalAlignment="Bottom" HorizontalAlignment="Right" Margin="5,10">
<TextBlock Text="{x:Bind TimeLabel}" Foreground="Gray" Style="{StaticResource CaptionTextBlockStyle}"/>
</StackPanel>
<StackPanel Padding="5,2,5,3" Background="Red" BorderThickness="1" BorderBrush="White" CornerRadius="5" Orientation="Horizontal" VerticalAlignment="Bottom" HorizontalAlignment="Right" Margin="5,35" Opacity="{x:Bind LiveLabelOpacity}">
<FontIcon Glyph="&#xEC44;" VerticalAlignment="Center" Foreground="White" FontSize="12" Margin="0,0,5,0"/>
<TextBlock Text="{x:Bind LiveLabel}" VerticalAlignment="Center" Foreground="White" Style="{StaticResource CaptionTextBlockStyle}" FontWeight="Bold"/>
</StackPanel>
<Grid Grid.Row="1" ColumnSpacing="10" Margin="10,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<controls:ImageEx CornerRadius="999" BorderThickness="3" BorderBrush="{ThemeResource SystemControlBackgroundChromeMediumBrush}" Background="Red"
Width="50" Height="50" VerticalAlignment="Bottom" Margin="0,-30,0,0" PlaceholderSource="/Assets/Icons/Contact.png" Source="{x:Bind ChannelMeta.LogoUrl}" PlaceholderStretch="UniformToFill"/>
<TextBlock Text="{x:Bind Meta.Snippet.ChannelTitle}" Grid.Column="1" MaxLines="1"/>
<TextBlock Text="{x:Bind ViewsLabel}" Grid.Column="2" MaxLines="1" Foreground="Gray"/>
</Grid>
<TextBlock Margin="10,0" Grid.Row="2" MaxLines="2" Text="{x:Bind Meta.Snippet.Title}" TextWrapping="WrapWholeWords" TextTrimming="CharacterEllipsis"/>
<Grid.ContextFlyout>
<MenuFlyout>
<MenuFlyoutItem Icon="Play" Text="Play"/>
<MenuFlyoutItem Text="Play incognito">
<MenuFlyoutItem.Icon>
<FontIcon Glyph="&#xE727;"/>
</MenuFlyoutItem.Icon>
</MenuFlyoutItem>
<MenuFlyoutItem Text="Open in picture-in-picture mode">
<MenuFlyoutItem.Icon>
<FontIcon Glyph="&#xE2B3;"/>
</MenuFlyoutItem.Icon>
</MenuFlyoutItem>
<MenuFlyoutItem Icon="Contact" Text="View channel"/>
<MenuFlyoutSeparator/>
<MenuFlyoutItem Icon="Link" Text="Copy link"/>
<MenuFlyoutItem Icon="Globe" Text="Open in browser"/>
<MenuFlyoutItem Icon="Share" Text="Share"/>
<MenuFlyoutSeparator/>
<MenuFlyoutSubItem Icon="Download" Text="Download"/>
<MenuFlyoutSubItem Icon="Add" Text="Add to">
<MenuFlyoutItem Text="New playlist" Icon="Add"/>
<ToggleMenuFlyoutItem Text="Watch later" Icon="Clock"/>
<MenuFlyoutSeparator/>
</MenuFlyoutSubItem>
<MenuFlyoutItem Text="Remove from playlist" Icon="Delete" Visibility="Visible" Foreground="Red"/>
</MenuFlyout>
</Grid.ContextFlyout>
</Grid>
</DataTemplate>
</controls:AdaptiveGridView.ItemTemplate>
<controls:AdaptiveGridView.Footer>
<ProgressBar IsIndeterminate="True" x:Name="progressBar" Background="Transparent" VerticalAlignment="Bottom"/>
</controls:AdaptiveGridView.Footer>
</controls:AdaptiveGridView>
<controls1:LoadingScreen x:Name="loadingScreen"/>
</Grid>
+24 -25
View File
@@ -1,31 +1,30 @@
using FoxTube.Controls.Cards; using Windows.UI.Xaml.Controls;
using FoxTube.Core.Helpers; using FoxTube.Models;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
namespace FoxTube.Controls namespace FoxTube.Controls
{ {
public sealed partial class ItemsGrid : UserControl public sealed partial class ItemsGrid : Grid
{ {
UIElementCollection Items => grid.Children; private ViewItemsCollection ItemsSource
public int ItemsCount => Items.Count; {
get => grid.ItemsSource as ViewItemsCollection;
set => grid.ItemsSource = value;
}
public ItemsGrid() => public LoadingScreen LoadingScreen => loadingScreen;
InitializeComponent();
public void Add(UIElement item) public ItemsGrid() =>
{ InitializeComponent();
empty.Opacity = 0;
if (!StoreInterop.AdsDisabled && ItemsCount % 5 == 0 && ItemsCount > 0) public void Initialize(IIncrementalLoadingHost host)
Items.Add(new AdvertCard()); {
Items.Add(item); ItemsSource = new ViewItemsCollection(host);
} ItemsSource.ItemsUpdated += (s, e) =>
{
public void Clear() empty.Opacity = ItemsSource.Count > 0 ? 0 : 1;
{ progressBar.IsIndeterminate = ItemsSource.HasMoreItems;
Items.Clear(); loadingScreen.Hide();
empty.Opacity = 1; };
} }
} }
} }
+50
View File
@@ -0,0 +1,50 @@
<UserControl
x:Class="FoxTube.Controls.LoadingScreen"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
mc:Ignorable="d"
Opacity="1"
Visibility="Visible"
Loaded="UserControl_Loaded">
<UserControl.OpacityTransition>
<ScalarTransition/>
</UserControl.OpacityTransition>
<Grid Background="{ThemeResource AppBarBackgroundThemeBrush}">
<controls:AdaptiveGridView DesiredWidth="400" Padding="5" SelectionMode="None" ScrollViewer.VerticalScrollMode="Disabled" ScrollViewer.VerticalScrollBarVisibility="Hidden" x:Name="grid">
<controls:AdaptiveGridView.OpacityTransition>
<ScalarTransition Duration="0:0:2"/>
</controls:AdaptiveGridView.OpacityTransition>
<controls:AdaptiveGridView.ItemContainerTransitions>
<TransitionCollection>
<EntranceThemeTransition IsStaggeringEnabled="True"/>
<AddDeleteThemeTransition/>
</TransitionCollection>
</controls:AdaptiveGridView.ItemContainerTransitions>
</controls:AdaptiveGridView>
<StackPanel VerticalAlignment="Center" x:Name="errorPanel" Visibility="Collapsed">
<StackPanel.OpacityTransition>
<ScalarTransition/>
</StackPanel.OpacityTransition>
<FontIcon Glyph="&#xE7BA;" HorizontalAlignment="Center" FontSize="100" x:Name="icon"/>
<TextBlock Text="Hmm... We can't load this page right now" HorizontalAlignment="Center" Style="{StaticResource SubheaderTextBlockStyle}" x:Name="title"/>
<TextBlock Text="There's must be a bug or templorary server issue. Please, try again later" HorizontalAlignment="Center" Style="{StaticResource TitleTextBlockStyle}" x:Name="subtitle"/>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Margin="0,20" x:Name="commonErrorActions">
<Button Content="Refresh page" Background="Red" Foreground="White" Click="RefreshPage"/>
<Button Content="Leave feedback" Margin="10,0,0,0" x:Name="feedbackButton" Click="LeaveFeedback"/>
</StackPanel>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Margin="0,20" x:Name="networkErrorActions">
<Button Content="Open network settings" Click="OpenNetworkSettings"/>
<Button Content="Open troubleshooter" Background="Red" Foreground="White" Margin="10,0" Click="OpenTroubleshooter"/>
<Button Content="Refresh page" Click="RefreshPage"/>
</StackPanel>
</StackPanel>
</Grid>
</UserControl>
+116
View File
@@ -0,0 +1,116 @@
using FoxTube.Utils;
using System;
using System.Threading;
using System.Threading.Tasks;
using Windows.System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media.Imaging;
namespace FoxTube.Controls
{
public sealed partial class LoadingScreen : UserControl
{
CancellationTokenSource cts = new CancellationTokenSource();
public LoadingScreen() =>
InitializeComponent();
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
feedbackButton.Visibility = Feedback.HasFeedbackHub ? Visibility.Visible : Visibility.Collapsed;
for (int i = 0; i < 25; i++)
grid.Items.Add(new Image
{
Source = new SvgImageSource("ms-appx:///Assets/Templates/CardTemplate.svg".ToUri())
});
}
private async void Shimmering(CancellationToken token)
{
while (true)
{
grid.Opacity = .75;
await Task.Delay(2000);
if (token.IsCancellationRequested)
break;
grid.Opacity = 1;
await Task.Delay(2000);
if (token.IsCancellationRequested)
break;
}
}
public async void Activate()
{
Visibility = Visibility.Visible;
Opacity = 1;
errorPanel.Opacity = 0;
await Task.Delay(500);
errorPanel.Visibility = Visibility.Collapsed;
cts = new CancellationTokenSource();
Shimmering(cts.Token);
}
public async void Hide()
{
Opacity = 0;
await Task.Delay(500);
Visibility = Visibility.Collapsed;
cts.Cancel();
}
public async void ShowError(bool isInternetError)
{
if (isInternetError)
{
icon.Glyph = "\xEB63";
title.Text = "Hmm... We can't load this page right now";
subtitle.Text = "We can't connect to Internet services. Please, check your connection or try again later";
networkErrorActions.Visibility = Visibility.Visible;
commonErrorActions.Visibility = Visibility.Collapsed;
}
else
{
icon.Glyph = "\xE7BA";
title.Text = "Hmm... Something went wrong";
subtitle.Text = "There's must be a bug or templorary server issue. Please, try again later";
networkErrorActions.Visibility = Visibility.Collapsed;
commonErrorActions.Visibility = Visibility.Visible;
}
cts.Cancel();
Visibility = Visibility.Visible;
Opacity = 1;
grid.Opacity = 0;
await Task.Delay(500);
errorPanel.Visibility = Visibility.Visible;
errorPanel.Opacity = 1;
}
private void LeaveFeedback(object sender, RoutedEventArgs e) =>
Feedback.OpenFeedbackHub();
private async void OpenNetworkSettings(object sender, RoutedEventArgs e) =>
await Launcher.LaunchUriAsync("ms-settings:network".ToUri());
private void RefreshPage(object sender, RoutedEventArgs e) =>
Navigation.RefreshCurrentPage();
private async void OpenTroubleshooter(object sender, RoutedEventArgs e) =>
await Launcher.LaunchUriAsync("ms-settings:troubleshoot".ToUri());
}
}
+68 -14
View File
@@ -13,7 +13,7 @@
<DefaultLanguage>en-US</DefaultLanguage> <DefaultLanguage>en-US</DefaultLanguage>
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier> <TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
<TargetPlatformVersion Condition=" '$(TargetPlatformVersion)' == '' ">10.0.18362.0</TargetPlatformVersion> <TargetPlatformVersion Condition=" '$(TargetPlatformVersion)' == '' ">10.0.18362.0</TargetPlatformVersion>
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion> <TargetPlatformMinVersion>10.0.18362.0</TargetPlatformMinVersion>
<MinimumVisualStudioVersion>14</MinimumVisualStudioVersion> <MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
<FileAlignment>512</FileAlignment> <FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> <ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
@@ -105,6 +105,21 @@
<Compile Include="App.xaml.cs"> <Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon> <DependentUpon>App.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Classes\MenuItemsList.cs" />
<Compile Include="Classes\Navigation.cs" />
<Compile Include="Classes\ViewItemsCollection.cs" />
<Compile Include="Controls\Dialogs\DownloadVideoDialog.xaml.cs">
<DependentUpon>DownloadVideoDialog.xaml</DependentUpon>
</Compile>
<Compile Include="Controls\Dialogs\ProOfferDialog.xaml.cs">
<DependentUpon>ProOfferDialog.xaml</DependentUpon>
</Compile>
<Compile Include="Controls\DownloadListItem.xaml.cs">
<DependentUpon>DownloadListItem.xaml</DependentUpon>
</Compile>
<Compile Include="Controls\LoadingScreen.xaml.cs">
<DependentUpon>LoadingScreen.xaml</DependentUpon>
</Compile>
<Compile Include="Controls\AccountManager.xaml.cs"> <Compile Include="Controls\AccountManager.xaml.cs">
<DependentUpon>AccountManager.xaml</DependentUpon> <DependentUpon>AccountManager.xaml</DependentUpon>
</Compile> </Compile>
@@ -127,9 +142,21 @@
<DependentUpon>MainPage.xaml</DependentUpon> <DependentUpon>MainPage.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Views\Downloads.xaml.cs">
<DependentUpon>Downloads.xaml</DependentUpon>
</Compile>
<Compile Include="Views\Home.xaml.cs"> <Compile Include="Views\Home.xaml.cs">
<DependentUpon>Home.xaml</DependentUpon> <DependentUpon>Home.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Views\HomeSections\Recommended.xaml.cs">
<DependentUpon>Recommended.xaml</DependentUpon>
</Compile>
<Compile Include="Views\HomeSections\Subscriptions.xaml.cs">
<DependentUpon>Subscriptions.xaml</DependentUpon>
</Compile>
<Compile Include="Views\HomeSections\Trending.xaml.cs">
<DependentUpon>Trending.xaml</DependentUpon>
</Compile>
<Compile Include="Views\Search.xaml.cs"> <Compile Include="Views\Search.xaml.cs">
<DependentUpon>Search.xaml</DependentUpon> <DependentUpon>Search.xaml</DependentUpon>
</Compile> </Compile>
@@ -145,9 +172,6 @@
<Compile Include="Views\SettingsSections\Inbox.xaml.cs"> <Compile Include="Views\SettingsSections\Inbox.xaml.cs">
<DependentUpon>Inbox.xaml</DependentUpon> <DependentUpon>Inbox.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Views\SettingsSections\Translate.xaml.cs">
<DependentUpon>Translate.xaml</DependentUpon>
</Compile>
<Compile Include="Views\Subscriptions.xaml.cs"> <Compile Include="Views\Subscriptions.xaml.cs">
<DependentUpon>Subscriptions.xaml</DependentUpon> <DependentUpon>Subscriptions.xaml</DependentUpon>
</Compile> </Compile>
@@ -184,6 +208,11 @@
<Content Include="Assets\Square150x150Logo.scale-125.png" /> <Content Include="Assets\Square150x150Logo.scale-125.png" />
<Content Include="Assets\Square150x150Logo.scale-150.png" /> <Content Include="Assets\Square150x150Logo.scale-150.png" />
<Content Include="Assets\Square150x150Logo.scale-400.png" /> <Content Include="Assets\Square150x150Logo.scale-400.png" />
<Content Include="Assets\Square44x44Logo.altform-lightunplated_targetsize-16.png" />
<Content Include="Assets\Square44x44Logo.altform-lightunplated_targetsize-24.png" />
<Content Include="Assets\Square44x44Logo.altform-lightunplated_targetsize-256.png" />
<Content Include="Assets\Square44x44Logo.altform-lightunplated_targetsize-32.png" />
<Content Include="Assets\Square44x44Logo.altform-lightunplated_targetsize-48.png" />
<Content Include="Assets\Square44x44Logo.altform-unplated_targetsize-16.png" /> <Content Include="Assets\Square44x44Logo.altform-unplated_targetsize-16.png" />
<Content Include="Assets\Square44x44Logo.altform-unplated_targetsize-256.png" /> <Content Include="Assets\Square44x44Logo.altform-unplated_targetsize-256.png" />
<Content Include="Assets\Square44x44Logo.altform-unplated_targetsize-32.png" /> <Content Include="Assets\Square44x44Logo.altform-unplated_targetsize-32.png" />
@@ -202,6 +231,7 @@
<Content Include="Assets\StoreLogo.scale-150.png" /> <Content Include="Assets\StoreLogo.scale-150.png" />
<Content Include="Assets\StoreLogo.scale-200.png" /> <Content Include="Assets\StoreLogo.scale-200.png" />
<Content Include="Assets\StoreLogo.scale-400.png" /> <Content Include="Assets\StoreLogo.scale-400.png" />
<Content Include="Assets\Templates\CardTemplate.svg" />
<Content Include="Assets\Wide310x150Logo.scale-100.png" /> <Content Include="Assets\Wide310x150Logo.scale-100.png" />
<Content Include="Assets\Wide310x150Logo.scale-125.png" /> <Content Include="Assets\Wide310x150Logo.scale-125.png" />
<Content Include="Assets\Wide310x150Logo.scale-150.png" /> <Content Include="Assets\Wide310x150Logo.scale-150.png" />
@@ -240,18 +270,50 @@
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
<Page Include="Controls\Dialogs\DownloadVideoDialog.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Controls\Dialogs\ProOfferDialog.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Controls\DownloadListItem.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Controls\ItemsGrid.xaml"> <Page Include="Controls\ItemsGrid.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
<Page Include="Controls\LoadingScreen.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="MainPage.xaml"> <Page Include="MainPage.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
<Page Include="Views\Downloads.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\Home.xaml"> <Page Include="Views\Home.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
<Page Include="Views\HomeSections\Recommended.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\HomeSections\Subscriptions.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\HomeSections\Trending.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\Search.xaml"> <Page Include="Views\Search.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
@@ -272,10 +334,6 @@
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
<Page Include="Views\SettingsSections\Translate.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\Subscriptions.xaml"> <Page Include="Views\Subscriptions.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
@@ -286,20 +344,16 @@
<Version>10.1811.22001</Version> <Version>10.1811.22001</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform"> <PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform">
<Version>6.2.9</Version> <Version>6.2.10</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.Toolkit.Uwp.UI.Controls"> <PackageReference Include="Microsoft.Toolkit.Uwp.UI.Controls">
<Version>6.0.0</Version> <Version>6.0.0</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.UI.Xaml"> <PackageReference Include="Microsoft.UI.Xaml">
<Version>2.3.191129002</Version> <Version>2.4.0</Version>
</PackageReference> </PackageReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\FoxTube.Background\FoxTube.Background.csproj">
<Project>{fc9128d7-e3aa-48ed-8641-629794b88b28}</Project>
<Name>FoxTube.Background</Name>
</ProjectReference>
<ProjectReference Include="..\FoxTube.Core\FoxTube.Core.csproj"> <ProjectReference Include="..\FoxTube.Core\FoxTube.Core.csproj">
<Project>{29c01e10-76e7-4527-984f-b0eef7e1ac64}</Project> <Project>{29c01e10-76e7-4527-984f-b0eef7e1ac64}</Project>
<Name>FoxTube.Core</Name> <Name>FoxTube.Core</Name>
+57 -150
View File
@@ -6,170 +6,77 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" mc:Ignorable="d"
xmlns:ui="using:Microsoft.UI.Xaml.Controls" xmlns:ui="using:Microsoft.UI.Xaml.Controls"
xmlns:controls="using:FoxTube.Controls" xmlns:controls="using:FoxTube.Controls" xmlns:models="using:FoxTube.Models"
xmlns:toolkit="using:Microsoft.Toolkit.Uwp.UI.Controls" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
xmlns:models="using:FoxTube.Core.Models"
xmlns:data="using:Google.Apis.YouTube.v3.Data">
<Page.Background>
<AcrylicBrush BackgroundSource="HostBackdrop" TintColor="{ThemeResource SystemAltHighColor}" FallbackColor="{ThemeResource SystemAltHighColor}" TintOpacity=".5"/>
</Page.Background>
<Grid> <Grid>
<Border x:Name="AppTitleBar" <Border x:Name="AppTitleBar"
VerticalAlignment="Top" VerticalAlignment="Top"
Background="Transparent" Background="Transparent"
Height="{Binding ElementName=NavigationViewControl, Path=CompactPaneLength}" Height="{Binding ElementName=NavigationViewControl, Path=CompactPaneLength}"
Canvas.ZIndex="1"> Canvas.ZIndex="1">
<TextBlock x:Name="AppTitle" <TextBlock Text="FoxTube"
Text="FoxTube" VerticalAlignment="Center" Margin="12,0"
VerticalAlignment="Center"
Style="{StaticResource CaptionTextBlockStyle}" /> Style="{StaticResource CaptionTextBlockStyle}" />
</Border> </Border>
<ui:NavigationView x:Name="NavigationViewControl"
IsTitleBarAutoPaddingEnabled="False"
<ui:NavigationView x:Name="NavigationViewControl"
IsTitleBarAutoPaddingEnabled="False"
DisplayModeChanged="NavigationView_DisplayModeChanged" DisplayModeChanged="NavigationView_DisplayModeChanged"
PaneClosing="NavigationView_PaneClosing"
PaneOpening="NavigationView_PaneOpening"
BackRequested="NavigationViewControl_BackRequested" BackRequested="NavigationViewControl_BackRequested"
ItemInvoked="NavigationViewControl_ItemInvoked"> ItemInvoked="NavigationViewControl_ItemInvoked"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<ui:NavigationView.AutoSuggestBox> <ui:NavigationView.PaneHeader>
<AutoSuggestBox QueryIcon="Find" PlaceholderText="Search YouTube..." TextChanged="AutoSuggestBox_TextChanged" QuerySubmitted="AutoSuggestBox_QuerySubmitted" TextMemberPath="Text"> <TextBlock Style="{StaticResource TitleTextBlockStyle}" Text="Menu" VerticalAlignment="Center" Margin="10,0" Name="title"/>
<AutoSuggestBox.ItemTemplate> </ui:NavigationView.PaneHeader>
<DataTemplate x:DataType="models:SearchSuggestion">
<Grid ColumnSpacing="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<FontIcon Glyph="{Binding Icon}"/> <ui:NavigationView.AutoSuggestBox>
<TextBlock Grid.Column="1" TextTrimming="CharacterEllipsis" Text="{Binding Text}"/> <AutoSuggestBox QueryIcon="Find" PlaceholderText="Search YouTube..." TextChanged="AutoSuggestBox_TextChanged" QuerySubmitted="AutoSuggestBox_QuerySubmitted" TextMemberPath="Text" >
</Grid> <AutoSuggestBox.ItemTemplate>
</DataTemplate> <DataTemplate x:DataType="models:SearchSuggestion">
</AutoSuggestBox.ItemTemplate> <Grid ColumnSpacing="10">
</AutoSuggestBox> <Grid.ColumnDefinitions>
</ui:NavigationView.AutoSuggestBox> <ColumnDefinition Width="auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<ui:NavigationView.PaneFooter> <FontIcon Glyph="{Binding Icon}"/>
<ui:NavigationViewList> <TextBlock Grid.Column="1" TextTrimming="CharacterEllipsis" Text="{Binding Text}"/>
<ui:NavigationViewItemSeparator/> </Grid>
<ui:NavigationViewItem Icon="Shop" Content="Get Pro" x:Name="RemoveAds" Tapped="RemoveAds_Tapped"/> </DataTemplate>
</ui:NavigationViewList> </AutoSuggestBox.ItemTemplate>
</ui:NavigationView.PaneFooter> </AutoSuggestBox>
</ui:NavigationView.AutoSuggestBox>
<ui:NavigationView.MenuItemTemplate> <ui:NavigationView.PaneFooter>
<DataTemplate x:DataType="data:Subscription"> <NavigationViewList>
<StackPanel Orientation="Horizontal" Padding="5" Margin="-5,0,0,0" Tag="{Binding Snippet.ResourceId.ChannelId}"> <NavigationViewItemSeparator/>
<PersonPicture Height="20" Margin="-5,0,15,0"> <NavigationViewItem Icon="Shop" Content="Get Pro" x:Name="removeAds" Tapped="RemoveAds_Tapped"/>
<PersonPicture.ProfilePicture> </NavigationViewList>
<BitmapImage UriSource="{Binding Snippet.Thumbnails.Medium.Url}" DecodePixelHeight="20" DecodePixelWidth="20"/> </ui:NavigationView.PaneFooter>
</PersonPicture.ProfilePicture>
</PersonPicture>
<TextBlock FontSize="14" Text="{Binding Snippet.Title}"/>
</StackPanel>
</DataTemplate>
</ui:NavigationView.MenuItemTemplate>
<ui:NavigationView.MenuItems> <Grid Margin="0,32,0,0">
<ui:NavigationViewItem Icon="Home" Content="Home" x:Name="home"/> <Frame x:Name="content" Navigated="Content_Navigated"/>
<ui:NavigationViewItem Content="Subscriptions" x:Name="subscriptions"> </Grid>
<ui:NavigationViewItem.Icon> </ui:NavigationView>
<FontIcon Glyph="&#xE125;"/>
</ui:NavigationViewItem.Icon>
</ui:NavigationViewItem>
<ui:NavigationViewItemHeader Content="Library" x:Name="libraryHeader"/> <StackPanel Orientation="Horizontal" Margin="0,0,0,0" HorizontalAlignment="Right" VerticalAlignment="Top" x:Name="toolbar">
<controls:AccountManager/>
<Button x:Name="leaveFeedback" Click="LeaveFeedback_Click" ToolTipService.ToolTip="Leave feedback"
Content="&#xED15;" Style="{StaticResource HeaderActionButton}"/>
<Button x:Name="refresh" Click="Refresh_Click" Content="&#xE149;" Style="{StaticResource HeaderActionButton}" ToolTipService.ToolTip="Refresh page" Opacity="0">
<Button.OpacityTransition>
<ScalarTransition/>
</Button.OpacityTransition>
</Button>
<ui:NavigationViewItem Content="History" x:Name="history"> <Button Height="32" Width="46" Style="{StaticResource HeaderActionButton}" Margin="52,0,0,0" IsTabStop="False"/>
<ui:NavigationViewItem.Icon> <Button Height="32" Width="46" Style="{StaticResource HeaderActionButton}" IsTabStop="False"/>
<FontIcon Glyph="&#xE81C;"/> <Button Height="32" Width="46" Style="{StaticResource HeaderActionButton}" IsTabStop="False"/>
</ui:NavigationViewItem.Icon> </StackPanel>
</ui:NavigationViewItem> </Grid>
<ui:NavigationViewItem Content="Liked videos" x:Name="liked"> </Page>
<ui:NavigationViewItem.Icon>
<FontIcon Glyph="&#xE19F;"/>
</ui:NavigationViewItem.Icon>
</ui:NavigationViewItem>
<ui:NavigationViewItem Icon="Clock" Content="Watch later" x:Name="wl"/>
<ui:NavigationViewItem Icon="Download" Content="Downloads" x:Name="download"/>
<ui:NavigationViewItemHeader Content="Subscriptions" x:Name="subscriptionsHeader"/>
<ui:NavigationViewItemHeader Content="Best of YouTube" x:Name="categoriesHeader"/>
<ui:NavigationViewItem Content="Music" x:Name="music">
<ui:NavigationViewItem.Icon>
<FontIcon Glyph="&#xE189;"/>
</ui:NavigationViewItem.Icon>
</ui:NavigationViewItem>
<ui:NavigationViewItem Content="Sports" x:Name="sports">
<ui:NavigationViewItem.Icon>
<FontIcon Glyph="&#xE95E;"/>
</ui:NavigationViewItem.Icon>
</ui:NavigationViewItem>
<ui:NavigationViewItem Content="Movies" x:Name="movies">
<ui:NavigationViewItem.Icon>
<FontIcon Glyph="&#xE8B2;"/>
</ui:NavigationViewItem.Icon>
</ui:NavigationViewItem>
<ui:NavigationViewItem Content="News" x:Name="news">
<ui:NavigationViewItem.Icon>
<FontIcon Glyph="&#xE12A;"/>
</ui:NavigationViewItem.Icon>
</ui:NavigationViewItem>
<ui:NavigationViewItem Content="Live" x:Name="live">
<ui:NavigationViewItem.Icon>
<FontIcon Glyph="&#xE93E;"/>
</ui:NavigationViewItem.Icon>
</ui:NavigationViewItem>
<ui:NavigationViewItem Content="Spotlight" x:Name="spotlight">
<ui:NavigationViewItem.Icon>
<FontIcon Glyph="&#xECAD;"/>
</ui:NavigationViewItem.Icon>
</ui:NavigationViewItem>
<ui:NavigationViewItem Content="360&#xB0; video" x:Name="vr">
<ui:NavigationViewItem.Icon>
<FontIcon Glyph="&#xF131;"/>
</ui:NavigationViewItem.Icon>
</ui:NavigationViewItem>
</ui:NavigationView.MenuItems>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid Margin="0,40,0,0" Padding="13,0" x:Name="headerGrid">
<TextBlock Style="{StaticResource TitleTextBlockStyle}" Text="Home" VerticalAlignment="Center" Name="title"/>
<CommandBar HorizontalAlignment="Right" Background="Transparent" DefaultLabelPosition="Right">
<AppBarButton x:Name="LeaveFeedback" Click="LeaveFeedback_Click">
<AppBarButton.Icon>
<FontIcon Glyph="&#xED15;" Margin="0,0,-10,0"/>
</AppBarButton.Icon>
</AppBarButton>
<AppBarButton x:Name="refresh" Click="Refresh_Click" Visibility="Collapsed">
<AppBarButton.Icon>
<SymbolIcon Symbol="Refresh" Margin="0,0,-10,0"/>
</AppBarButton.Icon>
</AppBarButton>
<controls:AccountManager x:Name="AccountsSelector"/>
</CommandBar>
</Grid>
<Frame x:Name="content" Grid.Row="1" Navigated="Content_Navigated"/>
<Frame x:Name="video" Grid.Row="1" Visibility="Collapsed"/>
<toolkit:Loading IsLoading="False" x:Name="loading" VerticalContentAlignment="Center" Grid.RowSpan="2">
<toolkit:Loading.Background>
<AcrylicBrush BackgroundSource="HostBackdrop" TintColor="{ThemeResource SystemColorBackgroundColor}" TintOpacity=".5"/>
</toolkit:Loading.Background>
<ProgressRing Height="100" Width="100" IsActive="True"/>
</toolkit:Loading>
</Grid>
</ui:NavigationView>
</Grid>
</Page>
+167 -228
View File
@@ -1,270 +1,209 @@
using FoxTube.Core.Helpers; using FoxTube.Attributes;
using FoxTube.Core.Models; using FoxTube.Controls.Dialogs;
using FoxTube.Utils;
using FoxTube.Services;
using Google.Apis.YouTube.v3.Data; using Google.Apis.YouTube.v3.Data;
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using Windows.ApplicationModel.Core; using Windows.ApplicationModel.Core;
using Windows.Foundation.Metadata;
using Windows.UI;
using Windows.UI.Popups;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml; using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls; using Microsoft.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
// TODO: Fix header (UI)
namespace FoxTube namespace FoxTube
{ {
public sealed partial class MainPage : Page public sealed partial class MainPage : Windows.UI.Xaml.Controls.Page
{ {
public static MainPage Current { get; set; } public static MainPage Current { get; set; }
public MainPage()
{
Current = this;
InitializeComponent();
if (Settings.Theme == 0) public MainPage()
RequestedTheme = ElementTheme.Light; {
else if (Settings.Theme == 1) Current = this;
RequestedTheme = ElementTheme.Dark; InitializeComponent();
Navigate(typeof(Views.Home)); #region Setup theme
if (Settings.Theme == 0)
RequestedTheme = ElementTheme.Light;
else if (Settings.Theme == 1)
RequestedTheme = ElementTheme.Dark;
Window.Current.SetTitleBar(AppTitleBar); if (RequestedTheme == ElementTheme.Default)
App.UpdateTitleBar(Application.Current.RequestedTheme == ApplicationTheme.Dark);
else
App.UpdateTitleBar(RequestedTheme == ElementTheme.Dark);
CoreApplication.GetCurrentView().TitleBar.ExtendViewIntoTitleBar = true; Window.Current.SetTitleBar(AppTitleBar);
ApplicationViewTitleBar titleBar = ApplicationView.GetForCurrentView().TitleBar; CoreApplication.GetCurrentView().TitleBar.ExtendViewIntoTitleBar = true;
titleBar.ButtonBackgroundColor = Colors.Transparent; #endregion
titleBar.ButtonHoverBackgroundColor = Color.FromArgb(50, 255, 255, 255);
titleBar.ButtonPressedBackgroundColor = Color.FromArgb(20, 255, 255, 255);
if (RequestedTheme == ElementTheme.Default) removeAds.Visibility = StoreInterop.AdsDisabled ? Visibility.Collapsed : Visibility.Visible;
titleBar.ButtonForegroundColor = if (!StoreInterop.AdsDisabled)
titleBar.ButtonHoverForegroundColor = removeAds.Content += $" ({StoreInterop.Price})";
titleBar.ButtonPressedForegroundColor = Application.Current.RequestedTheme == ApplicationTheme.Dark ? Colors.White : Colors.Black;
else
titleBar.ButtonForegroundColor =
titleBar.ButtonHoverForegroundColor =
titleBar.ButtonPressedForegroundColor = RequestedTheme == ElementTheme.Dark ? Colors.White : Colors.Black;
LeaveFeedback.Visibility = Feedback.HasFeedbackHub ? Visibility.Visible : Visibility.Collapsed; leaveFeedback.Visibility = Feedback.HasFeedbackHub ?
RemoveAds.Visibility = StoreInterop.AdsDisabled ? Visibility.Collapsed : Visibility.Visible; Visibility.Visible : Visibility.Collapsed;
if (!StoreInterop.AdsDisabled)
RemoveAds.Content += $" ({StoreInterop.Price})";
if (Settings.PromptReview) UserManagement.SubscriptionsChanged += UsersControl_SubscriptionsChanged;
Feedback.PromptReview(); UserManagement.UserStateUpdated += UsersControl_UserStateUpdated;
if (Settings.PromptFeedback) UsersControl_UserStateUpdated(this, UserManagement.Authorized);
Feedback.PromptFeedback();
}
void NavigationView_DisplayModeChanged(Microsoft.UI.Xaml.Controls.NavigationView sender, Microsoft.UI.Xaml.Controls.NavigationViewDisplayModeChangedEventArgs args) if (Settings.PromptReview)
{ Feedback.PromptReview();
Thickness currMargin = AppTitleBar.Margin; if (Settings.PromptFeedback)
AppTitleBar.Margin = new Thickness( Feedback.PromptFeedback();
sender.CompactPaneLength * (sender.DisplayMode == Microsoft.UI.Xaml.Controls.NavigationViewDisplayMode.Minimal ? 2 : 1), }
currMargin.Top,
currMargin.Right,
currMargin.Bottom);
UpdateAppTitleMargin(sender); #region Navigation
} private void Content_Navigated(object sender, Windows.UI.Xaml.Navigation.NavigationEventArgs args)
void NavigationView_PaneClosing(Microsoft.UI.Xaml.Controls.NavigationView sender, Microsoft.UI.Xaml.Controls.NavigationViewPaneClosingEventArgs args) => {
UpdateAppTitleMargin(sender); NavigationViewControl.IsBackEnabled = content.CanGoBack;
void NavigationView_PaneOpening(Microsoft.UI.Xaml.Controls.NavigationView sender, object args) => refresh.Opacity = Attribute.IsDefined(args.SourcePageType, typeof(RefreshableAttribute)) ? 1 : 0;
UpdateAppTitleMargin(sender);
void UpdateAppTitleMargin(Microsoft.UI.Xaml.Controls.NavigationView sender) switch (args.SourcePageType.Name)
{ {
const int smallLeftIndent = 4, largeLeftIndent = 12; case "Settings":
NavigationViewControl.SelectedItem = NavigationViewControl.SettingsItem;
break;
case "Downloads":
NavigationViewControl.SelectedItem = NavigationViewControl.MenuItems.FirstOrDefault(i => ((FrameworkElement)i).Tag as string == "downloads");
break;
case "Home":
case "Trending":
NavigationViewControl.SelectedItem = NavigationViewControl.MenuItems.FirstOrDefault(i => ((FrameworkElement)i).Tag as string == "home");
break;
case "Channel":
NavigationViewControl.SelectedItem = NavigationViewControl.MenuItems.FirstOrDefault(i => ((FrameworkElement)i).Tag == args.Parameter);
break;
default:
NavigationViewControl.SelectedItem = null;
break;
if (ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 7)) // TODO: Update menu selector
{ }
AppTitle.TranslationTransition = new Vector3Transition(); }
if (sender.DisplayMode == Microsoft.UI.Xaml.Controls.NavigationViewDisplayMode.Expanded && sender.IsPaneOpen) private void NavigationViewControl_ItemInvoked(NavigationView sender, NavigationViewItemInvokedEventArgs args)
AppTitle.Translation = new System.Numerics.Vector3(smallLeftIndent, 0, 0); {
else (NavigationTarget target, object parameters) suggestedTransition = (NavigationTarget.Home, null);
AppTitle.Translation = new System.Numerics.Vector3(largeLeftIndent, 0, 0);
}
else
{
Thickness currMargin = AppTitle.Margin;
if (sender.DisplayMode == Microsoft.UI.Xaml.Controls.NavigationViewDisplayMode.Expanded && sender.IsPaneOpen) if (args.IsSettingsInvoked)
AppTitle.Margin = new Thickness(smallLeftIndent, currMargin.Top, currMargin.Right, currMargin.Bottom); suggestedTransition = (NavigationTarget.Settings, null);
else else
AppTitle.Margin = new Thickness(largeLeftIndent, currMargin.Top, currMargin.Right, currMargin.Bottom); suggestedTransition = args.InvokedItemContainer.Tag as string switch
} {
} "home" => (NavigationTarget.Home, null),
"downloads" => (NavigationTarget.Downloads, null),
_ => (NavigationTarget.Home, null) // TODO: Navigate to channel
};
void LeaveFeedback_Click(object sender, RoutedEventArgs e) => if (Navigation.CurrentPage == suggestedTransition.target && Navigation.CurrentParameter == suggestedTransition.parameters)
Feedback.OpenFeedbackHub(); return;
async void RemoveAds_Tapped(object sender, Windows.UI.Xaml.Input.TappedRoutedEventArgs e) Navigation.NavigateTo(suggestedTransition.target, suggestedTransition.parameters);
{ }
bool success = await StoreInterop.PurchaseApp(); #endregion
if (success)
{
MessageDialog dialog = new MessageDialog("Thanks for purchasing full version of the app (^∇^) In order to complete changes we need to reopen it. Or you can do it later (but some elements may be broken)", "Thank you for your purchase!");
dialog.Commands.Add(new UICommand("Restart", (command) => Utils.RestartApp()));
dialog.Commands.Add(new UICommand("Later"));
dialog.CancelCommandIndex = 1;
dialog.DefaultCommandIndex = 0;
await dialog.ShowAsync();
}
}
public static void Navigate(Type pageType) => #region Search
Navigate(pageType, null); private async void AutoSuggestBox_TextChanged(Windows.UI.Xaml.Controls.AutoSuggestBox sender, Windows.UI.Xaml.Controls.AutoSuggestBoxTextChangedEventArgs args)
{
if (sender.Text.Length >= 3 && args.Reason == Windows.UI.Xaml.Controls.AutoSuggestionBoxTextChangeReason.UserInput)
sender.ItemsSource = await Search.GetSuggestions(sender.Text);
}
public static void Navigate(Type pageType, object param) private void AutoSuggestBox_QuerySubmitted(Windows.UI.Xaml.Controls.AutoSuggestBox sender, Windows.UI.Xaml.Controls.AutoSuggestBoxQuerySubmittedEventArgs args)
{ {
if (pageType == Current.content.CurrentSourcePageType && param == (Current.content.Content as PageView).Parameter) if (args.QueryText.Length < 3)
return; return;
// TODO: Add navigation logic for videos
Current.content.Navigate(pageType, param);
}
public static void SetHeader(string title) => History.AddSearchHistoryEntry(args.QueryText);
Current.title.Text = title;
void Content_Navigated(object sender, NavigationEventArgs e) // TODO: Go to search
{ }
refresh.Visibility = (e.Content is IRefreshable) ? Visibility.Visible : Visibility.Collapsed; #endregion
NavigationViewControl.IsBackEnabled = content.CanGoBack;
title.Text = (e.Content as PageView).Header ?? "FoxTube";
switch(e.SourcePageType.Name)
{
case "Home":
NavigationViewControl.SelectedItem = home;
break;
case "Settings":
NavigationViewControl.SelectedItem = NavigationViewControl.SettingsItem;
break;
case "Subscriptions":
NavigationViewControl.SelectedItem = subscriptions;
break;
default:
NavigationViewControl.SelectedItem = null;
break;
}
}
void Refresh_Click(object sender, RoutedEventArgs e) #region Users management
{ private void UsersControl_UserStateUpdated(object sender, bool authorized)
if (video.Content != null) {
(video.Content as IRefreshable)?.RefreshPage(); // Add general menu items
else NavigationViewControl.MenuItems.Clear();
(content.Content as IRefreshable)?.RefreshPage(); MenuItemsList.GetMenuItems(authorized).ForEach(i =>
} NavigationViewControl.MenuItems.Add(i));
void AutoSuggestBox_TextChanged(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args) // Add subscriptions list to the menu
{ if (authorized && UserManagement.CurrentUser.Subscriptions.Count > 0)
if (sender.Text.Length < 3 || args.Reason != AutoSuggestionBoxTextChangeReason.UserInput) {
return; NavigationViewControl.MenuItems.Add(new NavigationViewItemHeader { Content = "Subscriptions" });
UserManagement.CurrentUser.Subscriptions.GetRange(0, Math.Min(UserManagement.CurrentUser.Subscriptions.Count, 10)).ForEach(i =>
NavigationViewControl.MenuItems.Add(MenuItemsList.GenerateItemFromSubscription(i)));
}
// TODO: Load suggestions // TODO: Menu selector resets after menu update
// TODO: Remove // Refresh page
sender.ItemsSource = new List<SearchSuggestion> if (content.CurrentSourcePageType == null || content.CurrentSourcePageType.Name.Belongs("Home", "Trending"))
{ Navigation.NavigateTo(NavigationTarget.Home);
new SearchSuggestion("Suggestion 0"), else
new SearchSuggestion("Suggestion 1"), Refresh();
new SearchSuggestion("Suggestion 2"), }
new SearchSuggestion("Suggestion 3"),
new SearchSuggestion("Suggestion 4"),
new SearchSuggestion("History entry 0", true),
new SearchSuggestion("History entry 1", true),
new SearchSuggestion("History entry 2", true)
};
}
void AutoSuggestBox_QuerySubmitted(AutoSuggestBox sender, AutoSuggestBoxQuerySubmittedEventArgs args) private void UsersControl_SubscriptionsChanged(object sender, Subscription subscription)
{ {
if (args.QueryText.Length < 3) if (NavigationViewControl.MenuItems.FirstOrDefault(i => ((NavigationViewItemBase)i).Tag as string == subscription.Snippet.ChannelId) is NavigationViewItem container)
return; {
// TODO: Go to search NavigationViewControl.MenuItems.Remove(container);
Navigate(typeof(Views.Search));
}
void NavigationViewControl_BackRequested(Microsoft.UI.Xaml.Controls.NavigationView sender, Microsoft.UI.Xaml.Controls.NavigationViewBackRequestedEventArgs args) if (UserManagement.CurrentUser.Subscriptions.Count < 1)
{ NavigationViewControl.MenuItems.RemoveAt(NavigationViewControl.MenuItems.Count - 1);
// TODO: Add backward navigation logic for videos }
if (content.CanGoBack) else
content.GoBack(); {
} if (UserManagement.CurrentUser.Subscriptions.Count == 1)
NavigationViewControl.MenuItems.Add(new NavigationViewItemHeader { Content = "Subscriptions" });
void NavigationViewControl_ItemInvoked(Microsoft.UI.Xaml.Controls.NavigationView sender, Microsoft.UI.Xaml.Controls.NavigationViewItemInvokedEventArgs args) if (UserManagement.CurrentUser.Subscriptions.Count.Belongs(1, 10))
{ NavigationViewControl.MenuItems.Add(MenuItemsList.GenerateItemFromSubscription(subscription));
if (args.IsSettingsInvoked) }
Navigate(typeof(Views.Settings)); }
else #endregion
switch((args.InvokedItemContainer as Microsoft.UI.Xaml.Controls.NavigationViewItem).Name)
{
case "home":
Navigate(typeof(Views.Home));
break;
case "subscriptions":
Navigate(typeof(Views.Subscriptions));
break;
case "history":
break;
case "liked":
break;
case "wl":
break;
case "download":
break;
case "music":
break;
case "sports":
break;
case "movies":
break;
case "news":
break;
case "live":
break;
case "spotlight":
break;
case "vr":
break;
default:
break;
}
}
public void Update() #region Navigation actions
{ public void Refresh()
if(UsersControl.Authorized) {
{ if (!Attribute.IsDefined(content.CurrentSourcePageType, typeof(RefreshableAttribute)))
for (int i = NavigationViewControl.MenuItems.IndexOf(subscriptions); i < NavigationViewControl.MenuItems.IndexOf(categoriesHeader); i++) return;
(NavigationViewControl.MenuItems[i] as FrameworkElement).Visibility = Visibility.Visible;
for (int i = NavigationViewControl.MenuItems.IndexOf(categoriesHeader); i < NavigationViewControl.MenuItems.Count; i++) content.Navigate(content.CurrentSourcePageType ?? typeof(Views.Home), Navigation.CurrentParameter);
(NavigationViewControl.MenuItems[i] as FrameworkElement).Visibility = Visibility.Collapsed; content.BackStack.RemoveAt(content.BackStack.Count - 1);
}
foreach (Subscription i in UsersControl.CurrentUser.Subscriptions) public void Navigate(Type target, object parameter) =>
NavigationViewControl.MenuItems.Insert(NavigationViewControl.MenuItems.IndexOf(categoriesHeader), i); content.Navigate(target, parameter);
} #endregion
else
{
IEnumerable<object> subs = from i in NavigationViewControl.MenuItems
where string.IsNullOrWhiteSpace((i as FrameworkElement).Name)
select i;
foreach (object i in subs) #region Simple button actions
NavigationViewControl.MenuItems.Remove(i); private void NavigationViewControl_BackRequested(NavigationView sender, NavigationViewBackRequestedEventArgs args)
{
if (content.CanGoBack)
content.GoBack();
}
for (int i = NavigationViewControl.MenuItems.IndexOf(subscriptions); i < NavigationViewControl.MenuItems.IndexOf(categoriesHeader); i++) private void Refresh_Click(object sender, RoutedEventArgs e) =>
(NavigationViewControl.MenuItems[i] as FrameworkElement).Visibility = Visibility.Collapsed; Refresh();
for (int i = NavigationViewControl.MenuItems.IndexOf(categoriesHeader); i < NavigationViewControl.MenuItems.Count; i++) private async void RemoveAds_Tapped(object sender, Windows.UI.Xaml.Input.TappedRoutedEventArgs e) =>
(NavigationViewControl.MenuItems[i] as FrameworkElement).Visibility = Visibility.Visible; await new ProOfferDialog().ShowAsync();
}
} private void LeaveFeedback_Click(object sender, RoutedEventArgs e) =>
} Feedback.OpenFeedbackHub();
}
private void NavigationView_DisplayModeChanged(NavigationView sender, NavigationViewDisplayModeChangedEventArgs args) =>
AppTitleBar.Margin = new Thickness()
{
Left = sender.CompactPaneLength * (sender.DisplayMode == NavigationViewDisplayMode.Minimal ? 2 : 1),
Right = toolbar.ActualWidth + 190
};
#endregion
}
}
+2 -12
View File
@@ -15,7 +15,7 @@
</Resources> </Resources>
<Applications> <Applications>
<Application Id="App" Executable="$targetnametoken$.exe" EntryPoint="FoxTube.App" ResourceGroup="foxtube"> <Application Id="App" Executable="$targetnametoken$.exe" EntryPoint="FoxTube.App" ResourceGroup="foxtube">
<uap:VisualElements DisplayName="FoxTube" Square150x150Logo="Assets\Square150x150Logo.png" Square44x44Logo="Assets\Square44x44Logo.png" Description="YouTube Client for Windows 10" BackgroundColor="#282828"> <uap:VisualElements DisplayName="FoxTube" Square150x150Logo="Assets\Square150x150Logo.png" Square44x44Logo="Assets\Square44x44Logo.png" Description="YouTube Client for Windows 10" BackgroundColor="#404040">
<uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png" ShortName="FoxTube" Square310x310Logo="Assets\LargeTile.png" Square71x71Logo="Assets\SmallTile.png"> <uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png" ShortName="FoxTube" Square310x310Logo="Assets\LargeTile.png" Square71x71Logo="Assets\SmallTile.png">
<uap:ShowNameOnTiles> <uap:ShowNameOnTiles>
<uap:ShowOn Tile="square150x150Logo" /> <uap:ShowOn Tile="square150x150Logo" />
@@ -23,7 +23,7 @@
<uap:ShowOn Tile="square310x310Logo" /> <uap:ShowOn Tile="square310x310Logo" />
</uap:ShowNameOnTiles> </uap:ShowNameOnTiles>
</uap:DefaultTile> </uap:DefaultTile>
<uap:SplashScreen Image="Assets\SplashScreen.png" BackgroundColor="#282828" /> <uap:SplashScreen Image="Assets\SplashScreen.png" BackgroundColor="#404040" />
<uap:LockScreen Notification="badgeAndTileText" BadgeLogo="Assets\BadgeLogo.png"/> <uap:LockScreen Notification="badgeAndTileText" BadgeLogo="Assets\BadgeLogo.png"/>
</uap:VisualElements> </uap:VisualElements>
<Extensions> <Extensions>
@@ -32,16 +32,6 @@
<uap:DisplayName>FoxTube</uap:DisplayName> <uap:DisplayName>FoxTube</uap:DisplayName>
</uap:Protocol > </uap:Protocol >
</uap:Extension> </uap:Extension>
<Extension Category="windows.backgroundTasks" EntryPoint="FoxTube.Background.BackgroundProcessor">
<BackgroundTasks>
<Task Type="general" />
<Task Type="systemEvent" />
<Task Type="timer" />
<Task Type="pushNotification" />
<uap:Task Type="chatMessageNotification" />
<uap:Task Type="mediaProcessing" />
</BackgroundTasks>
</Extension>
</Extensions> </Extensions>
</Application> </Application>
</Applications> </Applications>
+365
View File
@@ -0,0 +1,365 @@
<Page
x:Class="FoxTube.Views.Downloads"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
xmlns:models="using:FoxTube.Models"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Pivot>
<Pivot.RightHeader>
<StackPanel Orientation="Horizontal">
<StackPanel Orientation="Horizontal">
<StackPanel.Resources>
<Style TargetType="Button" BasedOn="{StaticResource ButtonRevealStyle}">
<Setter Property="FontFamily" Value="Segoe MDL2 Assets"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Width" Value="32"/>
<Setter Property="Height" Value="32"/>
</Style>
<Style TargetType="ToggleButton" BasedOn="{StaticResource ToggleButtonRevealStyle}">
<Setter Property="FontFamily" Value="Segoe MDL2 Assets"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Width" Value="32"/>
<Setter Property="Height" Value="32"/>
</Style>
</StackPanel.Resources>
<Button Content="&#xE107;" ToolTipService.ToolTip="Delete" Name="deleteItemsButton" IsEnabled="False" Visibility="Collapsed">
<Button.Flyout>
<Flyout>
<StackPanel>
<TextBlock Text="Are you sure? This action cannot be undone"/>
<CheckBox Content="Also delete downloaded files" x:Name="deleteFilesCheckbox"/>
<Button Content="Delete" Background="Red" FontFamily="White" Click="DeleteSelectedItems"/>
</StackPanel>
</Flyout>
</Button.Flyout>
</Button>
<ToggleButton Content="&#xE762;" ToolTipService.ToolTip="Selecttion mode" Margin="10,0" Checked="ToggleButton_Checked" Unchecked="ToggleButton_Unchecked"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<Button Content="Open folder" Margin="10,0" Click="OpenDefaultFolder"/>
<Button Content="&#xE115;" Width="32" ToolTipService.ToolTip="Downloads settings" FontFamily="Segoe MDL2 Assets" Click="OpenDownloadSettings"/>
<AutoSuggestBox QueryIcon="Add" PlaceholderText="Download video by URL or ID" Width="300" Margin="10" QuerySubmitted="AutoSuggestBox_QuerySubmitted" TextChanged="AutoSuggestBox_TextChanged"/>
</StackPanel>
</StackPanel>
</Pivot.RightHeader>
<PivotItem Header="Downloads">
<Grid>
<StackPanel VerticalAlignment="Center" x:Name="empty" Margin="10">
<StackPanel.OpacityTransition>
<ScalarTransition/>
</StackPanel.OpacityTransition>
<TextBlock TextAlignment="Center" Text="You haven't downloaded anything yet" Style="{StaticResource SubheaderTextBlockStyle}"/>
<TextBlock TextAlignment="Center" Text="To download video press &quot;Download&quot; button from video page or a video card context menu and select download quality" Style="{StaticResource SubtitleTextBlockStyle}"/>
</StackPanel>
<ScrollViewer>
<StackPanel>
<ListView x:Name="downloadHistoryList" SelectionChanged="List_SelectionChanged" SelectionMode="None">
<ListView.ItemContainerTransitions>
<TransitionCollection>
<EntranceThemeTransition IsStaggeringEnabled="True"/>
<AddDeleteThemeTransition/>
</TransitionCollection>
</ListView.ItemContainerTransitions>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="Padding" Value="5"/>
<Setter Property="ContextFlyout">
<Setter.Value>
<MenuFlyout>
<MenuFlyoutItem Text="Delete" Icon="Delete" Click="DeleteOneItem"/>
<MenuFlyoutItem Text="Select" Click="SelectOneItem">
<MenuFlyoutItem.Icon>
<FontIcon Glyph="&#xE762;"/>
</MenuFlyoutItem.Icon>
</MenuFlyoutItem>
<MenuFlyoutItem Text="Show in folder" Click="ShowInFolder">
<MenuFlyoutItem.Icon>
<FontIcon Glyph="&#xE19C;"/>
</MenuFlyoutItem.Icon>
</MenuFlyoutItem>
</MenuFlyout>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate x:DataType="models:SavedVideo">
<controls:DropShadowPanel HorizontalContentAlignment="Stretch">
<Grid Padding="10" ColumnSpacing="10" Background="{ThemeResource SystemChromeLowColor}" CornerRadius="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<controls:ImageEx PlaceholderStretch="UniformToFill" CornerRadius="2" Height="75" PlaceholderSource="/Assets/DefaultVideoThumbnail.png" Source="{x:Bind Thumbnail}"/>
<Border CornerRadius="5,0,0,0" Background="{StaticResource SystemChromeMediumColor}" VerticalAlignment="Bottom" HorizontalAlignment="Right" Padding="10,2">
<TextBlock Text="{x:Bind Duration}" Style="{StaticResource CaptionTextBlockStyle}"/>
</Border>
<StackPanel Grid.Column="1">
<TextBlock Text="{x:Bind Title}" Style="{StaticResource TitleTextBlockStyle}" MaxLines="1"/>
<TextBlock Text="{x:Bind Author}" MaxLines="1"/>
<TextBlock Text="{x:Bind Path}" Style="{StaticResource CaptionTextBlockStyle}" MaxLines="1"/>
</StackPanel>
<StackPanel Grid.Column="2" Orientation="Horizontal" Tag="{x:Bind}">
<Button Width="75" Height="75" Padding="0" Background="Transparent" Click="OpenVideo">
<StackPanel>
<TextBlock Text="&#xED25;" FontFamily="Segoe MDL2 Assets" FontSize="30" HorizontalAlignment="Center"/>
<TextBlock Text="Open" TextWrapping="WrapWholeWords" HorizontalTextAlignment="Center"/>
</StackPanel>
</Button>
<Button Width="75" Height="75" Padding="0" Background="Transparent" Margin="10,0,0,0" Click="OpenOriginal">
<StackPanel>
<TextBlock Text="&#xE2B4;" FontFamily="Segoe MDL2 Assets" FontSize="30" HorizontalAlignment="Center"/>
<TextBlock Text="Go to original" TextWrapping="WrapWholeWords" HorizontalTextAlignment="Center" HorizontalAlignment="Center"/>
</StackPanel>
</Button>
</StackPanel>
</Grid>
</controls:DropShadowPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<ListView x:Name="list" SelectionChanged="List_SelectionChanged" SelectionMode="None">
<ListView.ItemContainerTransitions>
<TransitionCollection>
<EntranceThemeTransition IsStaggeringEnabled="True"/>
<AddDeleteThemeTransition/>
</TransitionCollection>
</ListView.ItemContainerTransitions>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="Padding" Value="5"/>
<Setter Property="ContextFlyout">
<Setter.Value>
<MenuFlyout>
<MenuFlyoutItem Text="Delete" Icon="Delete" Click="DeleteOneItem"/>
<MenuFlyoutItem Text="Select" Click="SelectOneItem">
<MenuFlyoutItem.Icon>
<FontIcon Glyph="&#xE762;"/>
</MenuFlyoutItem.Icon>
</MenuFlyoutItem>
<MenuFlyoutItem Text="Show in folder" Click="SelectOneItem">
<MenuFlyoutItem.Icon>
<FontIcon Glyph="&#xE19C;"/>
</MenuFlyoutItem.Icon>
</MenuFlyoutItem>
</MenuFlyout>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate x:DataType="models:DownloadItem">
<controls:DropShadowPanel HorizontalContentAlignment="Stretch">
<Grid Padding="10" ColumnSpacing="10" Background="{ThemeResource SystemChromeLowColor}" CornerRadius="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<controls:ImageEx PlaceholderStretch="UniformToFill" CornerRadius="2" Height="75" PlaceholderSource="/Assets/DefaultVideoThumbnail.png" Source="{x:Bind Thumbnail}"/>
<Border CornerRadius="5,0,0,0" Background="{StaticResource SystemChromeMediumColor}" VerticalAlignment="Bottom" HorizontalAlignment="Right" Padding="10,2">
<TextBlock Text="{x:Bind Duration}" Style="{StaticResource CaptionTextBlockStyle}"/>
</Border>
<StackPanel Grid.Column="1">
<TextBlock Text="{x:Bind Title}" Style="{StaticResource TitleTextBlockStyle}" MaxLines="1"/>
<TextBlock Text="{x:Bind Author}" MaxLines="1"/>
<TextBlock Text="{x:Bind Path}" Style="{StaticResource CaptionTextBlockStyle}" MaxLines="1"/>
</StackPanel>
<StackPanel Grid.Column="2" Orientation="Horizontal" Visibility="Collapsed">
<Button Width="75" Height="75" Padding="0" Background="Transparent">
<StackPanel>
<TextBlock Text="&#xED25;" FontFamily="Segoe MDL2 Assets" FontSize="30" HorizontalAlignment="Center"/>
<TextBlock Text="Open" TextWrapping="WrapWholeWords" HorizontalTextAlignment="Center"/>
</StackPanel>
</Button>
<Button Width="75" Height="75" Padding="0" Background="Transparent" Margin="10,0,0,0">
<StackPanel>
<TextBlock Text="&#xE2B4;" FontFamily="Segoe MDL2 Assets" FontSize="30" HorizontalAlignment="Center"/>
<TextBlock Text="Go to original" TextWrapping="WrapWholeWords" HorizontalTextAlignment="Center" HorizontalAlignment="Center"/>
</StackPanel>
</Button>
</StackPanel>
<Grid Grid.Column="2" RowSpacing="5" VerticalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Text="Downloading..." RelativePanel.Above="progressBar"/>
<TextBlock Text="50%" RelativePanel.AlignRightWithPanel="True" RelativePanel.Above="progressBar" Grid.Column="1" HorizontalAlignment="Right"/>
<ProgressBar Value="50" Width="200" Grid.Row="1" Grid.ColumnSpan="2"/>
<Button Content="&#xE106;" ToolTipService.ToolTip="Cancel" RelativePanel.Below="progressBar" RelativePanel.AlignRightWithPanel="True" Background="Transparent" FontFamily="Segoe MDL2 Assets" Grid.Column="1" Grid.Row="2" HorizontalAlignment="Right"/>
</Grid>
</Grid>
</controls:DropShadowPanel>
</DataTemplate>
</ListView.ItemTemplate>
<ListViewItem HorizontalContentAlignment="Stretch" Padding="5">
<ListViewItem.ContextFlyout>
<MenuFlyout>
<MenuFlyoutItem Text="Delete" Icon="Delete"/>
<MenuFlyoutItem Text="Select">
<MenuFlyoutItem.Icon>
<FontIcon Glyph="&#xE762;"/>
</MenuFlyoutItem.Icon>
</MenuFlyoutItem>
</MenuFlyout>
</ListViewItem.ContextFlyout>
<controls:DropShadowPanel HorizontalContentAlignment="Stretch">
<Grid Padding="10" ColumnSpacing="10" Background="{ThemeResource SystemChromeLowColor}" CornerRadius="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<controls:ImageEx PlaceholderStretch="UniformToFill" CornerRadius="2" Height="75" PlaceholderSource="/Assets/DefaultVideoThumbnail.png"/>
<Border CornerRadius="5,0,0,0" Background="{StaticResource SystemChromeMediumColor}" VerticalAlignment="Bottom" HorizontalAlignment="Right" Padding="10,2">
<TextBlock Text="2:13:45" Style="{StaticResource CaptionTextBlockStyle}"/>
</Border>
<StackPanel Grid.Column="1">
<TextBlock Text="[Quality] Video title" Style="{StaticResource TitleTextBlockStyle}" MaxLines="1"/>
<TextBlock Text="Author" MaxLines="1"/>
<TextBlock Text="video_file_path.mp4" Style="{StaticResource CaptionTextBlockStyle}" MaxLines="1"/>
</StackPanel>
<StackPanel Grid.Column="2" Orientation="Horizontal" Visibility="Collapsed">
<Button Width="75" Height="75" Padding="0" Background="Transparent">
<StackPanel>
<TextBlock Text="&#xED25;" FontFamily="Segoe MDL2 Assets" FontSize="30" HorizontalAlignment="Center"/>
<TextBlock Text="Open" TextWrapping="WrapWholeWords" HorizontalTextAlignment="Center"/>
</StackPanel>
</Button>
<Button Width="75" Height="75" Padding="0" Background="Transparent" Margin="10,0,0,0">
<StackPanel>
<TextBlock Text="&#xE2B4;" FontFamily="Segoe MDL2 Assets" FontSize="30" HorizontalAlignment="Center"/>
<TextBlock Text="Go to original" TextWrapping="WrapWholeWords" HorizontalTextAlignment="Center" HorizontalAlignment="Center"/>
</StackPanel>
</Button>
</StackPanel>
<Grid Grid.Column="2" RowSpacing="5" VerticalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Text="Downloading..." RelativePanel.Above="progressBar"/>
<TextBlock Text="50%" RelativePanel.AlignRightWithPanel="True" RelativePanel.Above="progressBar" Grid.Column="1" HorizontalAlignment="Right"/>
<ProgressBar Value="50" Width="200" Grid.Row="1" Grid.ColumnSpan="2"/>
<Button Content="&#xE106;" ToolTipService.ToolTip="Cancel" RelativePanel.Below="progressBar" RelativePanel.AlignRightWithPanel="True" Background="Transparent" FontFamily="Segoe MDL2 Assets" Grid.Column="1" Grid.Row="2" HorizontalAlignment="Right"/>
</Grid>
</Grid>
</controls:DropShadowPanel>
</ListViewItem>
<ListViewItem HorizontalContentAlignment="Stretch" Padding="5">
<ListViewItem.ContextFlyout>
<MenuFlyout>
<MenuFlyoutItem Text="Delete" Icon="Delete"/>
<MenuFlyoutItem Text="Select">
<MenuFlyoutItem.Icon>
<FontIcon Glyph="&#xE762;"/>
</MenuFlyoutItem.Icon>
</MenuFlyoutItem>
</MenuFlyout>
</ListViewItem.ContextFlyout>
<controls:DropShadowPanel HorizontalContentAlignment="Stretch">
<Grid Padding="10" ColumnSpacing="10" Background="{ThemeResource SystemChromeLowColor}" CornerRadius="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<controls:ImageEx PlaceholderStretch="UniformToFill" CornerRadius="2" Height="75" PlaceholderSource="/Assets/DefaultVideoThumbnail.png"/>
<Border CornerRadius="5,0,0,0" Background="{StaticResource SystemChromeMediumColor}" VerticalAlignment="Bottom" HorizontalAlignment="Right" Padding="10,2">
<TextBlock Text="2:13:45" Style="{StaticResource CaptionTextBlockStyle}"/>
</Border>
<StackPanel Grid.Column="1">
<TextBlock Text="[Quality] Video title" Style="{StaticResource TitleTextBlockStyle}" MaxLines="1"/>
<TextBlock Text="Author" MaxLines="1"/>
<TextBlock Text="video_file_path.mp4" Style="{StaticResource CaptionTextBlockStyle}" MaxLines="1"/>
</StackPanel>
<StackPanel Grid.Column="2" Orientation="Horizontal" Visibility="Visible">
<Button Width="75" Height="75" Padding="0" Background="Transparent">
<StackPanel>
<TextBlock Text="&#xED25;" FontFamily="Segoe MDL2 Assets" FontSize="30" HorizontalAlignment="Center"/>
<TextBlock Text="Open" TextWrapping="WrapWholeWords" HorizontalTextAlignment="Center"/>
</StackPanel>
</Button>
<Button Width="75" Height="75" Padding="0" Background="Transparent" Margin="10,0,0,0">
<StackPanel>
<TextBlock Text="&#xE2B4;" FontFamily="Segoe MDL2 Assets" FontSize="30" HorizontalAlignment="Center"/>
<TextBlock Text="Go to original" TextWrapping="WrapWholeWords" HorizontalTextAlignment="Center" HorizontalAlignment="Center"/>
</StackPanel>
</Button>
</StackPanel>
<Grid Grid.Column="2" RowSpacing="5" VerticalAlignment="Center" Visibility="Collapsed">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Text="Downloading..." RelativePanel.Above="progressBar"/>
<TextBlock Text="50%" RelativePanel.AlignRightWithPanel="True" RelativePanel.Above="progressBar" Grid.Column="1" HorizontalAlignment="Right"/>
<ProgressBar Value="50" Width="200" Grid.Row="1" Grid.ColumnSpan="2"/>
<Button Content="&#xE106;" ToolTipService.ToolTip="Cancel" RelativePanel.Below="progressBar" RelativePanel.AlignRightWithPanel="True" Background="Transparent" FontFamily="Segoe MDL2 Assets" Grid.Column="1" Grid.Row="2" HorizontalAlignment="Right"/>
</Grid>
</Grid>
</controls:DropShadowPanel>
</ListViewItem>
</ListView>
</StackPanel>
</ScrollViewer>
</Grid>
</PivotItem>
</Pivot>
</Page>
+114
View File
@@ -0,0 +1,114 @@
using FoxTube.Controls.Dialogs;
using FoxTube.Services;
using FoxTube.Models;
using System;
using System.Collections.Generic;
using Windows.System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using YoutubeExplode;
using YoutubeExplode.Videos;
using YoutubeExplode.Videos.Streams;
using System.IO;
namespace FoxTube.Views
{
/// <summary>
/// Video download page
/// </summary>
public sealed partial class Downloads : Page
{
public Downloads()
{
InitializeComponent();
downloadHistoryList.ItemsSource = DownloadsCenter.History;
// TODO: Add downloads list
UpdateList();
}
private void ToggleButton_Checked(object sender, RoutedEventArgs e)
{
deleteItemsButton.Visibility = Visibility.Visible;
deleteItemsButton.IsEnabled = false;
list.SelectionMode = ListViewSelectionMode.Multiple;
}
private void ToggleButton_Unchecked(object sender, RoutedEventArgs e)
{
deleteItemsButton.Visibility = Visibility.Collapsed;
list.SelectionMode = ListViewSelectionMode.None;
}
private void List_SelectionChanged(object sender, SelectionChangedEventArgs e) =>
deleteItemsButton.IsEnabled = list.SelectedItems.Count > 0;
private void DeleteSelectedItems(object sender, RoutedEventArgs e)
{
// TODO: Delete downloads
}
private async void OpenDefaultFolder(object sender, RoutedEventArgs e) =>
await Launcher.LaunchFolderAsync(await DownloadsCenter.GetDefaultDownloadsFolder());
private void OpenDownloadSettings(object sender, RoutedEventArgs e) =>
Navigation.NavigateTo(NavigationTarget.Settings, "downloads");
public void UpdateList() =>
empty.Opacity = (((list.ItemsSource as List<object>)?.Count) ?? list.Items.Count) > 0 ? 0 : 1;
private async void AutoSuggestBox_QuerySubmitted(AutoSuggestBox sender, AutoSuggestBoxQuerySubmittedEventArgs args)
{
YoutubeClient client = new YoutubeClient(UserManagement.Service.HttpClient);
VideoId? id;
Video meta;
if ((id = VideoId.TryParse(args.QueryText)) == null || (meta = await client.Videos.GetAsync(id.Value)) == null)
{
sender.Items.Clear();
sender.Items.Add(new ComboBoxItem
{
Content = "No video found",
IsEnabled = false
});
return;
}
StreamManifest manifest = await client.Videos.Streams.GetManifestAsync(id.Value);
await new DownloadVideoDialog(meta, manifest).ShowAsync();
}
private void AutoSuggestBox_TextChanged(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args) =>
sender.Items.Clear();
private void DeleteOneItem(object sender, RoutedEventArgs e)
{
}
private void SelectOneItem(object sender, RoutedEventArgs e)
{
object item = ((sender as FrameworkElement).Parent as FrameworkElement).Parent;
ListView list;
}
private void OpenOriginal(object sender, RoutedEventArgs e)
{
SavedVideo item = (sender as FrameworkElement).Parent.GetValue(TagProperty) as SavedVideo;
Navigation.NavigateTo(NavigationTarget.Home, item.Id); // TODO: Replace with actual navigation
}
private async void OpenVideo(object sender, RoutedEventArgs e)
{
SavedVideo item = (sender as FrameworkElement).Parent.GetValue(TagProperty) as SavedVideo;
await Launcher.LaunchUriAsync(item.Path.ToUri());
}
private async void ShowInFolder(object sender, RoutedEventArgs e)
{
SavedVideo item = (sender as FrameworkElement).Parent.GetValue(TagProperty) as SavedVideo;
await Launcher.LaunchUriAsync(new FileInfo(item.Path).Directory.FullName.ToUri());
}
}
}
+15 -54
View File
@@ -1,61 +1,22 @@
<models:PageView <Page
xmlns:models="using:FoxTube.Core.Models"
NavigationCacheMode="Enabled" NavigationCacheMode="Enabled"
x:Class="FoxTube.Views.Home" x:Class="FoxTube.Views.Home"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:toolkit="using:Microsoft.Toolkit.Uwp.UI.Controls" xmlns:homesections="using:FoxTube.Views.HomeSections"
xmlns:controls="using:FoxTube.Controls" mc:Ignorable="d">
mc:Ignorable="d"
Header="Home">
<Pivot> <Pivot>
<PivotItem Header="Recommended"> <PivotItem Header="Recommended">
<Grid> <homesections:Recommended/>
<RefreshContainer> </PivotItem>
<ScrollViewer Padding="5,0"> <PivotItem Header="Trending">
<controls:ItemsGrid x:Name="recommendedItems"/> <homesections:Trending/>
</ScrollViewer> </PivotItem>
</RefreshContainer> <PivotItem Header="Subscriptions">
<toolkit:Loading IsLoading="False" x:Name="recommendedLoading" VerticalContentAlignment="Center"> <homesections:Subscriptions/>
<toolkit:Loading.Background> </PivotItem>
<AcrylicBrush BackgroundSource="HostBackdrop" TintColor="{ThemeResource SystemColorBackgroundColor}" TintOpacity=".5"/> </Pivot>
</toolkit:Loading.Background> </Page>
<ProgressRing Height="100" Width="100" IsActive="True"/>
</toolkit:Loading>
</Grid>
</PivotItem>
<PivotItem Header="Trending">
<Grid>
<RefreshContainer>
<ScrollViewer Padding="5,0">
<controls:ItemsGrid x:Name="trendingItems"/>
</ScrollViewer>
</RefreshContainer>
<toolkit:Loading IsLoading="False" x:Name="trendingLoading" VerticalContentAlignment="Center">
<toolkit:Loading.Background>
<AcrylicBrush BackgroundSource="HostBackdrop" TintColor="{ThemeResource SystemColorBackgroundColor}" TintOpacity=".5"/>
</toolkit:Loading.Background>
<ProgressRing Height="100" Width="100" IsActive="True"/>
</toolkit:Loading>
</Grid>
</PivotItem>
<PivotItem Header="Subscriptions">
<Grid>
<RefreshContainer>
<ScrollViewer Padding="5,0">
<controls:ItemsGrid x:Name="subscriptionsItems"/>
</ScrollViewer>
</RefreshContainer>
<toolkit:Loading IsLoading="False" x:Name="subscriptionsLoading" VerticalContentAlignment="Center">
<toolkit:Loading.Background>
<AcrylicBrush BackgroundSource="HostBackdrop" TintColor="{ThemeResource SystemColorBackgroundColor}" TintOpacity=".5"/>
</toolkit:Loading.Background>
<ProgressRing Height="100" Width="100" IsActive="True"/>
</toolkit:Loading>
</Grid>
</PivotItem>
</Pivot>
</models:PageView>
+12 -31
View File
@@ -1,35 +1,16 @@
using FoxTube.Controls.Cards; using FoxTube.Attributes;
using FoxTube.Core.Models; using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation; using Windows.UI.Xaml.Navigation;
// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238
namespace FoxTube.Views namespace FoxTube.Views
{ {
/// <summary> /// <summary>
/// An empty page that can be used on its own or navigated to within a Frame. /// An empty page that can be used on its own or navigated to within a Frame.
/// </summary> /// </summary>
public sealed partial class Home : PageView, IRefreshable [Refreshable]
{ public sealed partial class Home : Page
public Home() => {
InitializeComponent(); public Home() =>
InitializeComponent();
public void RefreshPage() }
{ }
throw new System.NotImplementedException();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
if (e.NavigationMode != NavigationMode.New)
return;
for (int i = 0; i < 25; i++)
{
recommendedItems.Add(new VideoCard());
}
}
}
}
@@ -0,0 +1,17 @@
<Page
x:Class="FoxTube.Views.HomeSections.Recommended"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:controls="using:FoxTube.Controls"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
Loaded="Page_Loaded">
<Grid>
<RefreshContainer>
<ListView x:Name="list"/>
</RefreshContainer>
<controls:LoadingScreen x:Name="loadingScreen"/>
</Grid>
</Page>
@@ -0,0 +1,37 @@
using FoxTube.Attributes;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
namespace FoxTube.Views.HomeSections
{
/// <summary>
/// Page with videos recommeded to user
/// </summary>
[Refreshable]
public sealed partial class Recommended : Page
{
public Recommended() =>
InitializeComponent();
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
if (e.NavigationMode == NavigationMode.New)
LoadContent();
}
private void Page_Loaded(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
if (!(Parent is Frame))
LoadContent();
}
private void LoadContent()
{
loadingScreen.Activate();
// TODO: Load content
}
}
}
@@ -0,0 +1,20 @@
<Page
NavigationCacheMode="Enabled"
x:Class="FoxTube.Views.HomeSections.Subscriptions"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:controls="using:FoxTube.Controls"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
Loaded="Page_Loaded">
<Grid>
<RefreshContainer>
<ScrollViewer Padding="5,0">
<controls:ItemsGrid x:Name="grid"/>
</ScrollViewer>
</RefreshContainer>
<controls:LoadingScreen x:Name="loadingScreen"/>
</Grid>
</Page>
@@ -0,0 +1,38 @@
using FoxTube.Attributes;
using FoxTube.Controls.Cards;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
namespace FoxTube.Views.HomeSections
{
/// <summary>
/// Users subscriptions videos page
/// </summary>
[Refreshable]
public sealed partial class Subscriptions : Page
{
public Subscriptions() =>
InitializeComponent();
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
if (e.NavigationMode == NavigationMode.New)
LoadContent();
}
private void Page_Loaded(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
if (!(Parent is Frame))
LoadContent();
}
private void LoadContent()
{
loadingScreen.Activate();
// TODO: Load content
}
}
}
+17
View File
@@ -0,0 +1,17 @@
<Page
NavigationCacheMode="Enabled"
x:Class="FoxTube.Views.HomeSections.Trending"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:controls="using:FoxTube.Controls"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
Loaded="Page_Loaded">
<Grid>
<RefreshContainer>
<controls:ItemsGrid x:Name="grid"/>
</RefreshContainer>
</Grid>
</Page>
@@ -0,0 +1,61 @@
using FoxTube.Attributes;
using FoxTube.Controls.Cards;
using FoxTube.Models;
using Google.Apis.YouTube.v3;
using Google.Apis.YouTube.v3.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
namespace FoxTube.Views.HomeSections
{
/// <summary>
/// YouTube trending videos page
/// </summary>
[Refreshable]
public sealed partial class Trending : Page, IIncrementalLoadingHost
{
VideosResource.ListRequest client;
public Trending() =>
InitializeComponent();
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
if (e.NavigationMode != NavigationMode.Back)
LoadContent();
}
private void Page_Loaded(object sender, RoutedEventArgs e)
{
if (!(Parent is Frame))
LoadContent();
}
private void LoadContent()
{
client = UserManagement.Service.Videos.List("snippet,liveStreamingDetails");
client.MaxResults = 25;
client.Chart = VideosResource.ListRequest.ChartEnum.MostPopular;
client.RegionCode = FoxTube.Settings.Region;
grid.Initialize(this);
}
public async Task<(List<object>, bool)> LoadMoreItems()
{
VideoListResponse response = await client.ExecuteAsync();
client.PageToken = response.NextPageToken;
return (response.Items.Select(i => new VideoItem(i) as object).ToList(),
!string.IsNullOrWhiteSpace(response.NextPageToken));
}
}
}
+3 -4
View File
@@ -1,4 +1,4 @@
<models:PageView <Page
xmlns:models="using:FoxTube.Core.Models" xmlns:models="using:FoxTube.Core.Models"
x:Class="FoxTube.Views.Search" x:Class="FoxTube.Views.Search"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
@@ -8,8 +8,7 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="using:FoxTube.Controls" xmlns:controls="using:FoxTube.Controls"
xmlns:toolkit="using:Microsoft.Toolkit.Uwp.UI.Controls" xmlns:toolkit="using:Microsoft.Toolkit.Uwp.UI.Controls"
mc:Ignorable="d" mc:Ignorable="d">
Header="Search">
<Grid> <Grid>
<Grid.RowDefinitions> <Grid.RowDefinitions>
@@ -98,4 +97,4 @@
<ProgressRing Height="100" Width="100" IsActive="True"/> <ProgressRing Height="100" Width="100" IsActive="True"/>
</toolkit:Loading> </toolkit:Loading>
</Grid> </Grid>
</models:PageView> </Page>
+34 -49
View File
@@ -1,60 +1,45 @@
using FoxTube.Core.Models; using FoxTube.Attributes;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml; using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives; using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
namespace FoxTube.Views namespace FoxTube.Views
{ {
/// <summary> /// <summary>
/// Search results page /// Search results page
/// </summary> /// </summary>
public sealed partial class Search : PageView, IRefreshable [Refreshable]
{ public sealed partial class Search : Page
bool closingByToggle = false; {
bool closingByToggle = false;
public Search() => public Search() =>
InitializeComponent(); InitializeComponent();
public void RefreshPage() void ToggleFilters_Click(object sender, RoutedEventArgs e)
{ {
throw new NotImplementedException(); if (filters.Visibility == Visibility.Visible)
} {
filters.Visibility = Visibility.Collapsed;
(sender as HyperlinkButton).Content = "Show filters \xE71C";
}
else
{
filters.Visibility = Visibility.Visible;
(sender as HyperlinkButton).Content = "Hide filters \xE71C";
}
}
void ToggleFilters_Click(object sender, RoutedEventArgs e) private void MenuFlyout_Closing(FlyoutBase sender, FlyoutBaseClosingEventArgs args)
{ {
if(filters.Visibility == Visibility.Visible) if (closingByToggle)
{ {
filters.Visibility = Visibility.Collapsed; args.Cancel = true;
(sender as HyperlinkButton).Content = "Show filters \xE71C"; closingByToggle = false;
} }
else }
{
filters.Visibility = Visibility.Visible;
(sender as HyperlinkButton).Content = "Hide filters \xE71C";
}
}
private void MenuFlyout_Closing(FlyoutBase sender, FlyoutBaseClosingEventArgs args) void ToggleMenuFlyoutItem_Click(object sender, RoutedEventArgs e) =>
{ closingByToggle = true;
if(closingByToggle) }
{
args.Cancel = true;
closingByToggle = false;
}
}
void ToggleMenuFlyoutItem_Click(object sender, RoutedEventArgs e) =>
closingByToggle = true;
}
} }
+20 -33
View File
@@ -1,40 +1,27 @@
<models:PageView <Page
xmlns:models="using:FoxTube.Core.Models"
x:Class="FoxTube.Views.Settings" x:Class="FoxTube.Views.Settings"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:settingssections="using:FoxTube.Views.SettingsSections" xmlns:settingssections="using:FoxTube.Views.SettingsSections"
mc:Ignorable="d" mc:Ignorable="d">
Header="Settings">
<Page.Resources> <Pivot SelectedIndex="0" Name="pivot">
<Style TargetType="ScrollViewer"> <PivotItem Name="generalTab" Header="Preferences">
<Setter Property="Padding" Value="10,0"/> <ScrollViewer Padding="15,0">
</Style> <settingssections:General/>
</Page.Resources> </ScrollViewer>
</PivotItem>
<Pivot SelectedIndex="0" Name="pivot" IsHeaderItemsCarouselEnabled="False"> <PivotItem Name="aboutTab" Header="About us">
<PivotItem Name="generalTab" Header="Preferences"> <ScrollViewer Padding="15,0">
<ScrollViewer> <settingssections:About/>
<settingssections:General/> </ScrollViewer>
</ScrollViewer> </PivotItem>
</PivotItem> <PivotItem Name="inboxTab" Header="Inbox">
<PivotItem Name="aboutTab" Header="About us"> <ScrollViewer Padding="15,0">
<ScrollViewer> <settingssections:Inbox x:Name="inbox"/>
<settingssections:About/> </ScrollViewer>
</ScrollViewer> </PivotItem>
</PivotItem> </Pivot>
<!--<PivotItem Name="translateTab" Header="Help us translate this app"> </Page>
<ScrollViewer>
<settingssections:Translate/>
</ScrollViewer>
</PivotItem>-->
<PivotItem Name="inboxTab" Header="Inbox">
<ScrollViewer>
<settingssections:Inbox x:Name="inbox"/>
</ScrollViewer>
</PivotItem>
</Pivot>
</models:PageView>
+34 -37
View File
@@ -1,45 +1,42 @@
using FoxTube.Core.Models; using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation; using Windows.UI.Xaml.Navigation;
namespace FoxTube.Views namespace FoxTube.Views
{ {
/// <summary> /// <summary>
/// Settings page /// Settings page
/// </summary> /// </summary>
public sealed partial class Settings : PageView public sealed partial class Settings : Page
{ {
public Settings() => public Settings() =>
InitializeComponent(); InitializeComponent();
protected override void OnNavigatedTo(NavigationEventArgs e) protected override void OnNavigatedTo(NavigationEventArgs e)
{ {
base.OnNavigatedTo(e); base.OnNavigatedTo(e);
if (string.IsNullOrWhiteSpace(e.Parameter as string)) if (string.IsNullOrWhiteSpace(e.Parameter as string))
return; return;
string[] param = (e.Parameter as string).Split('/'); string[] param = (e.Parameter as string).Split('/');
object focus; switch (param[0])
switch(param[0]) {
{ case "about":
case "about": case "info":
case "info": pivot.SelectedItem = aboutTab;
focus = aboutTab; break;
break; case "inbox":
case "inbox": case "message":
case "message": case "changelog":
case "changelog": pivot.SelectedItem = inboxTab;
focus = inboxTab; if (param.Length > 1)
break; inbox.Open(param[1]);
default: break;
focus = generalTab; default:
break; pivot.SelectedItem = generalTab;
} break;
pivot.SelectedItem = focus; }
}
if (focus == inboxTab && param.Length > 1) }
inbox.Open(param[1]); }
}
}
}
+40 -40
View File
@@ -7,62 +7,62 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"> mc:Ignorable="d">
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition/> <ColumnDefinition/>
<ColumnDefinition Width="auto"/> <ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<controls:DropShadowPanel Grid.Column="1" VerticalAlignment="Top" OffsetX="5" OffsetY="5"> <controls:DropShadowPanel Grid.Column="1" VerticalAlignment="Top">
<Image Source="/Assets/StoreLogo.scale-400.png" Width="150"/> <Image Source="/Assets/StoreLogo.scale-400.png" Width="150"/>
</controls:DropShadowPanel> </controls:DropShadowPanel>
<StackPanel> <StackPanel>
<StackPanel.ChildrenTransitions> <StackPanel.ChildrenTransitions>
<TransitionCollection> <TransitionCollection>
<EntranceThemeTransition IsStaggeringEnabled="True"/> <EntranceThemeTransition IsStaggeringEnabled="True" FromVerticalOffset="100"/>
</TransitionCollection> </TransitionCollection>
</StackPanel.ChildrenTransitions> </StackPanel.ChildrenTransitions>
<TextBlock Text="FoxTube" Style="{StaticResource SubheaderTextBlockStyle}"/>
<TextBlock Name="version" Text="[currentVersion]" Style="{StaticResource CaptionTextBlockStyle}" FontStyle="Italic" Margin="0,-5,0,0"/>
<TextBlock TextWrapping="WrapWholeWords" Text="Developed by Michael &#x22;XFox&#x22; Gordeev" Margin="0,10,0,0"/> <TextBlock Text="FoxTube" Style="{StaticResource SubheaderTextBlockStyle}"/>
<TextBlock Name="version" Text="[currentVersion]" Style="{StaticResource CaptionTextBlockStyle}" FontStyle="Italic" Margin="0,-5,0,0"/>
<StackPanel Margin="0,10,0,0"> <TextBlock TextWrapping="WrapWholeWords" Text="Developed by Michael &#x22;XFox&#x22; Gordeev" Margin="0,10,0,0"/>
<TextBlock Text="Special thanks to:" Style="{StaticResource TitleTextBlockStyle}"/>
<TextBlock> <StackPanel Margin="0,10,0,0">
<TextBlock Text="Special thanks to:" Style="{StaticResource TitleTextBlockStyle}"/>
<TextBlock>
<Hyperlink NavigateUri="https://github.com/Tyrrrz">@Tyrrrz</Hyperlink> for his awesome library <Hyperlink NavigateUri="https://github.com/Tyrrrz">@Tyrrrz</Hyperlink> for his awesome library
<LineBreak/><Hyperlink NavigateUri="https://vk.com/msreviewnet">@msreviewnet</Hyperlink> for warm welcome and first feedback <LineBreak/><Hyperlink NavigateUri="https://vk.com/msreviewnet">@msreviewnet</Hyperlink> for warm welcome and first feedback
<LineBreak/><Underline Foreground="Red">You</Underline> for using my app :) <LineBreak/><Underline Foreground="Red">You</Underline> for using my app :)
</TextBlock> </TextBlock>
</StackPanel> </StackPanel>
<StackPanel Margin="0,10,0,0"> <StackPanel Margin="0,10,0,0">
<TextBlock Text="Contacts" Style="{StaticResource TitleTextBlockStyle}"/> <TextBlock Text="Contacts" Style="{StaticResource TitleTextBlockStyle}"/>
<TextBlock> <TextBlock>
Twitter: <Hyperlink NavigateUri="https://twitter.com/xfox111">@xfox111</Hyperlink> Twitter: <Hyperlink NavigateUri="https://twitter.com/xfox111">@xfox111</Hyperlink>
<LineBreak/>Vkontakte: <Hyperlink NavigateUri="https://vk.com/XFox.Mike">@XFox.Mike</Hyperlink> <LineBreak/>Vkontakte: <Hyperlink NavigateUri="https://vk.com/XFox.Mike">@XFox.Mike</Hyperlink>
<!--<LineBreak/>YouTube: <Hyperlink NavigateUri="https://youtube.com/c/FoxGameStudioChannel">@xfox</Hyperlink>--> <!--<LineBreak/>YouTube: <Hyperlink NavigateUri="https://youtube.com/c/FoxGameStudioChannel">@xfox</Hyperlink>-->
<LineBreak/>E-mail: <Hyperlink NavigateUri="mailto:michael.xfox@outlook.com">michael.xfox@outlook.com</Hyperlink> <LineBreak/>E-mail: <Hyperlink NavigateUri="mailto:michael@xfox111.net">michael@xfox111.net</Hyperlink>
<LineBreak/>My website: <Hyperlink NavigateUri="https://xfox111.net">https://xfox111.net</Hyperlink> <LineBreak/>My website: <Hyperlink NavigateUri="https://xfox111.net">https://xfox111.net</Hyperlink>
</TextBlock> </TextBlock>
</StackPanel> </StackPanel>
<StackPanel Margin="0,10,0,0"> <StackPanel Margin="0,10,0,0">
<TextBlock Text="Legal stuff" Style="{StaticResource TitleTextBlockStyle}"/> <TextBlock Text="Legal stuff" Style="{StaticResource TitleTextBlockStyle}"/>
<TextBlock> <TextBlock>
<Hyperlink NavigateUri="https://xfox111.net/Projects/FoxTube/PrivacyPolicy.txt">Our Privacy Policy</Hyperlink> <Hyperlink NavigateUri="https://xfox111.net/Projects/FoxTube/Privacy">Our Privacy Policy</Hyperlink>
<LineBreak/><Hyperlink NavigateUri="https://youtube.com/t/privacy">YouTube Privacy Policy</Hyperlink> <LineBreak/><Hyperlink NavigateUri="https://youtube.com/t/privacy">YouTube Privacy Policy</Hyperlink>
<LineBreak/><Hyperlink NavigateUri="https://youtube.com/t/terms">YouTube Terms of use</Hyperlink> <LineBreak/><Hyperlink NavigateUri="https://youtube.com/t/terms">YouTube Terms of use</Hyperlink>
<LineBreak/><Hyperlink NavigateUri="https://youtube.com/t/community_guidelines">YouTube Community Guidelines</Hyperlink> <LineBreak/><Hyperlink NavigateUri="https://youtube.com/t/community_guidelines">YouTube Community Guidelines</Hyperlink>
</TextBlock> </TextBlock>
</StackPanel> </StackPanel>
<TextBlock Name="copyrights" Margin="0,10,0,0"> <TextBlock Name="copyrights" Margin="0,10,0,0">
©[year] Michael Gordeev ©[year] Michael Gordeev
<LineBreak/>©[year] YouTube, LLC <LineBreak/>©[year] YouTube, LLC
</TextBlock> </TextBlock>
<Button Name="feedback" Content="Leave feedback" Margin="0,10" Visibility="Collapsed" Click="OpenFeedbackHub"/> <Button Name="feedback" Content="Leave feedback" Margin="0,10" Visibility="Collapsed" Click="OpenFeedbackHub"/>
</StackPanel> </StackPanel>
</Grid> </Grid>
</Page> </Page>
+17 -17
View File
@@ -1,27 +1,27 @@
using FoxTube.Core.Helpers; using FoxTube.Utils;
using System; using System;
using Windows.UI.Xaml; using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls;
namespace FoxTube.Views.SettingsSections namespace FoxTube.Views.SettingsSections
{ {
/// <summary> /// <summary>
/// About page /// About page
/// </summary> /// </summary>
public sealed partial class About : Page public sealed partial class About : Page
{ {
public About() public About()
{ {
InitializeComponent(); InitializeComponent();
version.Text = Metrics.CurrentVersion; version.Text = Metrics.CurrentVersion;
copyrights.Text = copyrights.Text.Replace("[year]", DateTime.Today.Year.ToString()); copyrights.Text = copyrights.Text.Replace("[year]", DateTime.Today.Year.ToString());
if (Feedback.HasFeedbackHub) if (Feedback.HasFeedbackHub)
feedback.Visibility = Visibility.Visible; feedback.Visibility = Visibility.Visible;
} }
void OpenFeedbackHub(object sender, RoutedEventArgs e) => private void OpenFeedbackHub(object sender, RoutedEventArgs e) =>
Feedback.OpenFeedbackHub(); Feedback.OpenFeedbackHub();
} }
} }
+68 -50
View File
@@ -4,59 +4,77 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"> mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<StackPanel> <StackPanel>
<StackPanel.ChildrenTransitions> <StackPanel.ChildrenTransitions>
<TransitionCollection> <TransitionCollection>
<EntranceThemeTransition IsStaggeringEnabled="True"/> <EntranceThemeTransition IsStaggeringEnabled="True" FromVerticalOffset="100"/>
</TransitionCollection> </TransitionCollection>
</StackPanel.ChildrenTransitions> </StackPanel.ChildrenTransitions>
<StackPanel Margin="0,0,0,10">
<TextBlock Text="Region &#x26; search" Style="{StaticResource TitleTextBlockStyle}"/>
<ComboBox Header="App interface language" Width="250" Name="language" SelectionChanged="LanguageChanged">
<ComboBoxItem Content="English (United States)" Tag="en-US"/>
<ComboBoxItem Content="Russian (Russia)" Tag="ru-RU"/>
</ComboBox>
<Button Content="Restart application" x:Name="restart" Visibility="Collapsed" Foreground="White" Background="Red" Margin="5" Click="Restart"/>
<ComboBox Header="Search relevance language" Width="250" Name="relevanceLanguage" SelectionChanged="RelevanceLanguageChanged" Loaded="LoadRelevaneLanguageList"/> <StackPanel Margin="0,0,0,10">
<ComboBox Header="Region" Width="250" Name="region" SelectionChanged="RegionChanged" Loaded="LoadRegionList"/> <ComboBox Header="Default homepage tab" Width="250">
<ComboBox Header="SafeSearch" Width="250" Name="safeSearch" SelectionChanged="SafeSearchChanged"> <ComboBoxItem Content="Recommended"/>
<ComboBoxItem Content="Moderate"/> <ComboBoxItem Content="Trending"/>
<ComboBoxItem Content="None"/> <ComboBoxItem Content="Subscriptions"/>
<ComboBoxItem Content="Strict"/> </ComboBox>
</ComboBox> </StackPanel>
</StackPanel>
<StackPanel Margin="0,0,0,10">
<TextBlock Text="Region &#x26; search" Style="{StaticResource TitleTextBlockStyle}"/>
<ComboBox Header="App interface language" Width="250" Name="language" SelectionChanged="LanguageChanged">
<ComboBoxItem Content="English (United States)" Tag="en-US"/>
<ComboBoxItem Content="Russian (Russia)" Tag="ru-RU"/>
</ComboBox>
<Button Content="Restart application" x:Name="restart" Visibility="Collapsed" Foreground="White" Background="Red" Margin="5" Click="Restart"/>
<StackPanel Margin="0,0,0,10"> <ComboBox Header="Preffered content language" Width="250" Name="relevanceLanguage" SelectionChanged="RelevanceLanguageChanged" Loaded="LoadRelevaneLanguageList"/>
<TextBlock Text="Playback" Style="{StaticResource TitleTextBlockStyle}"/> <ComboBox Header="Region" Width="250" Name="region" SelectionChanged="RegionChanged" Loaded="LoadRegionList"/>
<ComboBox Width="250" Header="Default video playback quality" Name="quality" SelectionChanged="QualityChanged" Loaded="LoadQualitiesList"> <ComboBox Header="SafeSearch" Width="250" Name="safeSearch" SelectionChanged="SafeSearchChanged">
<ComboBoxItem Tag="remember" Content="Remember my choice"/> <ComboBoxItem Content="Moderate"/>
<ComboBoxItem Tag="auto" Content="Auto"/> <ComboBoxItem Content="None"/>
</ComboBox> <ComboBoxItem Content="Strict"/>
<ToggleSwitch OnContent="Notify when playing on metered connection" OffContent="Notify when playing on metered connection" Name="meteredWarning" Toggled="MeteredWarningChanged"/> </ComboBox>
<ToggleSwitch OnContent="Play videos automatically" OffContent="Play videos automatically" Name="autoplay" Toggled="AutoplayChanged"/> </StackPanel>
<ToggleSwitch OnContent="Notify before playing explicit content" OffContent="Notify before playing explicit content" Name="explicitWarning" Toggled="ExplicitWarningChanged"/>
</StackPanel>
<StackPanel Margin="0,0,0,10"> <StackPanel Margin="0,0,0,10">
<TextBlock Text="Notifications" Style="{StaticResource TitleTextBlockStyle}"/> <TextBlock Text="Playback" Style="{StaticResource TitleTextBlockStyle}"/>
<ToggleSwitch OnContent="Notify when someone of your subscriptions uploaded new video" OffContent="Notify when someone of your subscriptions uploaded new video" Name="channelNotifications" Toggled="ChannelNotificationsChanged"/> <ComboBox Width="250" Header="Default video playback quality" Name="quality" SelectionChanged="QualityChanged" Loaded="LoadQualitiesList">
<ToggleSwitch OnContent="Notify if I have any YouTube link on my clipboard" OffContent="Notify if I have any YouTube link on my clipboard" x:Name="clipboardProcessing" Toggled="ClipboardProcessingChanged"/> <ComboBoxItem Tag="remember" Content="Remember my choice"/>
<ToggleSwitch OnContent="Recieve messages from developers" OffContent="Recieve messages from developers" Name="developersNews" Toggled="DevelopersNotificationsChanged"/> <ComboBoxItem Tag="auto" Content="Auto"/>
</StackPanel> </ComboBox>
<ToggleSwitch OnContent="Notify when playing on metered connection" OffContent="Notify when playing on metered connection" Name="meteredWarning" Toggled="MeteredWarningChanged"/>
<ToggleSwitch OnContent="Play videos automatically" OffContent="Play videos automatically" Name="autoplay" Toggled="AutoplayChanged"/>
<ToggleSwitch OnContent="Notify before playing explicit content" OffContent="Notify before playing explicit content" Name="explicitWarning" Toggled="ExplicitWarningChanged"/>
</StackPanel>
<StackPanel Margin="0,0,0,10"> <StackPanel Margin="0,0,0,10">
<TextBlock Text="Theme" Style="{StaticResource TitleTextBlockStyle}"/> <TextBlock Text="Notifications" Style="{StaticResource TitleTextBlockStyle}"/>
<StackPanel> <ToggleSwitch OnContent="Notify when someone of your subscriptions uploaded new video" OffContent="Notify when someone of your subscriptions uploaded new video" Name="channelNotifications" Toggled="ChannelNotificationsChanged"/>
<TextBlock Text="Color mode" Style="{StaticResource SubtitleTextBlockStyle}"/> <ToggleSwitch OnContent="Notify if I have any YouTube link on my clipboard" OffContent="Notify if I have any YouTube link on my clipboard" x:Name="clipboardProcessing" Toggled="ClipboardProcessingChanged"/>
<RadioButton Content="Light" Name="light" Tag="0" GroupName="theme" Checked="ThemeChanged"/> <ToggleSwitch OnContent="Recieve messages from developers" OffContent="Recieve messages from developers" Name="developersNews" Toggled="DevelopersNotificationsChanged"/>
<RadioButton Content="Dark" Name="dark" Tag="1" GroupName="theme" Checked="ThemeChanged"/> </StackPanel>
<RadioButton Content="Windows default" Tag="2" Name="system" GroupName="theme" Checked="ThemeChanged"/>
</StackPanel> <StackPanel Margin="0,0,0,10">
<HyperlinkButton Content="Windows color settings" NavigateUri="ms-settings:colors"/> <TextBlock Text="Downloads" Style="{StaticResource TitleTextBlockStyle}"/>
</StackPanel> <StackPanel Orientation="Horizontal" HorizontalAlignment="Left" Margin="0,5">
</StackPanel> <TextBox Header="Default downloads location" Width="250" IsReadOnly="True" PlaceholderText="//Videos/FoxTube"/>
<Button VerticalAlignment="Bottom" FontFamily="Segoe MDL2 Assets" Content="&#xE10C;" Margin="5,0"/>
</StackPanel>
<ToggleSwitch OnContent="Ask where to save before downloading" OffContent="Ask where to save before downloading"/>
</StackPanel>
<StackPanel Margin="0,0,0,10">
<TextBlock Text="Theme" Style="{StaticResource TitleTextBlockStyle}"/>
<RadioButton Content="Light" Name="light" Tag="0" GroupName="theme" Checked="ThemeChanged"/>
<RadioButton Content="Dark" Name="dark" Tag="1" GroupName="theme" Checked="ThemeChanged"/>
<RadioButton Content="Windows default" Tag="2" Name="system" GroupName="theme" Checked="ThemeChanged"/>
<HyperlinkButton Content="Windows color settings" NavigateUri="ms-settings:colors"/>
</StackPanel>
<Button Content="Reset application" Click="ResetApp"/>
</StackPanel>
</Page> </Page>
+101 -106
View File
@@ -1,137 +1,132 @@
using FoxTube.Core.Helpers; using System.Linq;
using System.Linq;
using Windows.Globalization; using Windows.Globalization;
using Windows.UI;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml; using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls;
namespace FoxTube.Views.SettingsSections namespace FoxTube.Views.SettingsSections
{ {
/// <summary> /// <summary>
/// Preferences page /// Preferences page
/// </summary> /// </summary>
public sealed partial class General : Page public sealed partial class General : Page
{ {
public General() public General()
{ {
InitializeComponent(); InitializeComponent();
language.SelectedItem = language.Items.FirstOrDefault(i => ((ComboBoxItem)i).Tag.ToString() == FoxTube.Settings.Language); language.SelectedItem = language.Items.FirstOrDefault(i => ((ComboBoxItem)i).Tag.ToString() == FoxTube.Settings.Language);
safeSearch.SelectedIndex = FoxTube.Settings.SafeSearch; safeSearch.SelectedIndex = FoxTube.Settings.SafeSearch;
meteredWarning.IsOn = FoxTube.Settings.CheckConnection; meteredWarning.IsOn = FoxTube.Settings.CheckConnection;
autoplay.IsOn = FoxTube.Settings.Autoplay; autoplay.IsOn = FoxTube.Settings.Autoplay;
explicitWarning.IsOn = FoxTube.Settings.BlockExplicitContent; explicitWarning.IsOn = FoxTube.Settings.BlockExplicitContent;
channelNotifications.IsOn = FoxTube.Settings.VideoNotifications; channelNotifications.IsOn = FoxTube.Settings.VideoNotifications;
developersNews.IsOn = FoxTube.Settings.DevNotifications; developersNews.IsOn = FoxTube.Settings.DevNotifications;
clipboardProcessing.IsOn = FoxTube.Settings.ProcessClipboard; clipboardProcessing.IsOn = FoxTube.Settings.ProcessClipboard;
switch (FoxTube.Settings.Theme) switch (FoxTube.Settings.Theme)
{ {
case 0: case 0:
light.IsChecked = true; light.IsChecked = true;
break; break;
case 1: case 1:
dark.IsChecked = true; dark.IsChecked = true;
break; break;
case 2: case 2:
system.IsChecked = true; system.IsChecked = true;
break; break;
} }
} }
void LoadRelevaneLanguageList(object sender, RoutedEventArgs e) private void LoadRelevaneLanguageList(object sender, RoutedEventArgs e)
{ {
// TODO: Add list loading // TODO: Add list loading
} }
void LoadRegionList(object sender, RoutedEventArgs e) private void LoadRegionList(object sender, RoutedEventArgs e)
{ {
// TODO: Add list loading // TODO: Add list loading
} }
void LoadQualitiesList(object sender, RoutedEventArgs e) private void LoadQualitiesList(object sender, RoutedEventArgs e)
{ {
// TODO: Add qualities loading // TODO: Add qualities loading
quality.SelectedItem = quality.Items.FirstOrDefault(i => ((ComboBoxItem)i).Tag.ToString() == FoxTube.Settings.DesiredVideoQuality); quality.SelectedItem = quality.Items.FirstOrDefault(i => ((ComboBoxItem)i).Tag.ToString() == FoxTube.Settings.DesiredVideoQuality);
} }
void LanguageChanged(object sender, SelectionChangedEventArgs e) private void LanguageChanged(object sender, SelectionChangedEventArgs e)
{ {
if ((language.SelectedItem as ComboBoxItem).Tag.ToString() == FoxTube.Settings.Language) if ((language.SelectedItem as ComboBoxItem).Tag.ToString() == FoxTube.Settings.Language)
return; return;
ApplicationLanguages.PrimaryLanguageOverride = (language.SelectedItem as ComboBoxItem).Tag.ToString(); ApplicationLanguages.PrimaryLanguageOverride = (language.SelectedItem as ComboBoxItem).Tag.ToString();
FoxTube.Settings.Language = (language.SelectedItem as ComboBoxItem).Tag.ToString(); FoxTube.Settings.Language = (language.SelectedItem as ComboBoxItem).Tag.ToString();
restart.Visibility = Visibility.Visible; restart.Visibility = Visibility.Visible;
} }
void Restart(object sender, RoutedEventArgs e) => private void Restart(object sender, RoutedEventArgs e) =>
Utils.RestartApp(); Utils.Utils.RestartApp();
void RelevanceLanguageChanged(object sender, SelectionChangedEventArgs e) => private void RelevanceLanguageChanged(object sender, SelectionChangedEventArgs e) =>
FoxTube.Settings.RelevanceLanguage = ((ComboBoxItem)relevanceLanguage.SelectedItem).Tag.ToString(); FoxTube.Settings.RelevanceLanguage = ((ComboBoxItem)relevanceLanguage.SelectedItem).Tag.ToString();
void RegionChanged(object sender, SelectionChangedEventArgs e) => private void RegionChanged(object sender, SelectionChangedEventArgs e) =>
FoxTube.Settings.Region = ((ComboBoxItem)region.SelectedItem).Tag.ToString(); FoxTube.Settings.Region = ((ComboBoxItem)region.SelectedItem).Tag.ToString();
void SafeSearchChanged(object sender, SelectionChangedEventArgs e) => private void SafeSearchChanged(object sender, SelectionChangedEventArgs e) =>
FoxTube.Settings.SafeSearch = safeSearch.SelectedIndex; FoxTube.Settings.SafeSearch = safeSearch.SelectedIndex;
void QualityChanged(object sender, SelectionChangedEventArgs e) => private void QualityChanged(object sender, SelectionChangedEventArgs e) =>
FoxTube.Settings.DesiredVideoQuality = (quality.SelectedItem as ComboBoxItem).Tag as string; FoxTube.Settings.DesiredVideoQuality = (quality.SelectedItem as ComboBoxItem).Tag as string;
void MeteredWarningChanged(object sender, RoutedEventArgs e) => private void MeteredWarningChanged(object sender, RoutedEventArgs e) =>
FoxTube.Settings.CheckConnection = meteredWarning.IsOn; FoxTube.Settings.CheckConnection = meteredWarning.IsOn;
void AutoplayChanged(object sender, RoutedEventArgs e) => private void AutoplayChanged(object sender, RoutedEventArgs e) =>
FoxTube.Settings.Autoplay = autoplay.IsOn; FoxTube.Settings.Autoplay = autoplay.IsOn;
void ExplicitWarningChanged(object sender, RoutedEventArgs e) => private void ExplicitWarningChanged(object sender, RoutedEventArgs e) =>
FoxTube.Settings.BlockExplicitContent = explicitWarning.IsOn; FoxTube.Settings.BlockExplicitContent = explicitWarning.IsOn;
void ChannelNotificationsChanged(object sender, RoutedEventArgs e) => private void ChannelNotificationsChanged(object sender, RoutedEventArgs e) =>
FoxTube.Settings.VideoNotifications = channelNotifications.IsOn; FoxTube.Settings.VideoNotifications = channelNotifications.IsOn;
void ClipboardProcessingChanged(object sender, RoutedEventArgs e) => private void ClipboardProcessingChanged(object sender, RoutedEventArgs e) =>
FoxTube.Settings.ProcessClipboard = clipboardProcessing.IsOn; FoxTube.Settings.ProcessClipboard = clipboardProcessing.IsOn;
void DevelopersNotificationsChanged(object sender, RoutedEventArgs e) => private void DevelopersNotificationsChanged(object sender, RoutedEventArgs e) =>
FoxTube.Settings.DevNotifications = developersNews.IsOn; FoxTube.Settings.DevNotifications = developersNews.IsOn;
void ThemeChanged(object sender, RoutedEventArgs e) private void ThemeChanged(object sender, RoutedEventArgs e)
{ {
if (FoxTube.Settings.Theme.ToString() == (string)(sender as RadioButton).Tag) if (FoxTube.Settings.Theme.ToString() == (string)(sender as RadioButton).Tag)
return; return;
switch((sender as RadioButton).Name) switch ((sender as RadioButton).Name)
{ {
case "light": case "light":
FoxTube.Settings.Theme = 0; FoxTube.Settings.Theme = 0;
MainPage.Current.RequestedTheme = ElementTheme.Light; MainPage.Current.RequestedTheme = ElementTheme.Light;
break; App.UpdateTitleBar(false);
case "dark": break;
FoxTube.Settings.Theme = 1; case "dark":
MainPage.Current.RequestedTheme = ElementTheme.Dark; FoxTube.Settings.Theme = 1;
break; MainPage.Current.RequestedTheme = ElementTheme.Dark;
default: App.UpdateTitleBar(true);
FoxTube.Settings.Theme = 2; break;
MainPage.Current.RequestedTheme = ElementTheme.Default; default:
break; FoxTube.Settings.Theme = 2;
} MainPage.Current.RequestedTheme = ElementTheme.Default;
App.UpdateTitleBar(Application.Current.RequestedTheme == ApplicationTheme.Dark);
break;
}
}
ApplicationViewTitleBar titleBar = ApplicationView.GetForCurrentView().TitleBar; private void ResetApp(object sender, RoutedEventArgs e)
if (MainPage.Current.RequestedTheme == ElementTheme.Default) {
titleBar.ButtonForegroundColor = Utils.Utils.InitializeFailsafeProtocol();
titleBar.ButtonHoverForegroundColor = }
titleBar.ButtonPressedForegroundColor = Application.Current.RequestedTheme == ApplicationTheme.Dark ? Colors.White : Colors.Black; }
else
titleBar.ButtonForegroundColor =
titleBar.ButtonHoverForegroundColor =
titleBar.ButtonPressedForegroundColor = MainPage.Current.RequestedTheme == ElementTheme.Dark ? Colors.White : Colors.Black;
}
}
} }
+87 -74
View File
@@ -5,84 +5,97 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls" xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
xmlns:models="using:FoxTube.Core.Models" xmlns:models="using:FoxTube.Models"
mc:Ignorable="d" mc:Ignorable="d"
Loaded="Page_Loaded"> Loaded="Page_Loaded">
<Page.Resources> <Page.Resources>
<Style TargetType="controls:DropShadowPanel"> <Style TargetType="controls:DropShadowPanel">
<Setter Property="OffsetX" Value="3"/> <Setter Property="OffsetX" Value="3"/>
<Setter Property="OffsetY" Value="3"/> <Setter Property="OffsetY" Value="3"/>
</Style> <Setter Property="ShadowOpacity" Value=".5"/>
</Page.Resources> </Style>
</Page.Resources>
<controls:MasterDetailsView Background="Transparent" MasterPaneWidth="400" CompactModeThresholdWidth="850" x:Name="masterDetailsView" BackButtonBehavior="Inline"> <controls:MasterDetailsView MasterPaneWidth="400" CompactModeThresholdWidth="850" x:Name="masterDetailsView" BackButtonBehavior="Inline">
<controls:MasterDetailsView.MasterHeader> <controls:MasterDetailsView.ItemContainerTransitions>
<StackPanel> <TransitionCollection>
<ProgressBar IsIndeterminate="True" x:Name="progressBar"/> <EntranceThemeTransition IsStaggeringEnabled="True" FromVerticalOffset="100"/>
<ComboBox Header="Filter" HorizontalAlignment="Stretch" x:Name="filter" SelectionChanged="FilterChanged" IsEnabled="False"> </TransitionCollection>
<ComboBoxItem Content="All"/> </controls:MasterDetailsView.ItemContainerTransitions>
<ComboBoxItem Content="Changelogs"/>
<ComboBoxItem Content="Messages"/> <controls:MasterDetailsView.MasterHeader>
</ComboBox> <StackPanel Margin="0,0,0,10">
</StackPanel> <ProgressBar IsIndeterminate="True" x:Name="progressBar" Background="Transparent"/>
</controls:MasterDetailsView.MasterHeader> <ComboBox Header="Filter" HorizontalAlignment="Stretch" x:Name="filter" SelectionChanged="FilterChanged" IsEnabled="False">
<controls:MasterDetailsView.NoSelectionContent> <ComboBoxItem Content="All"/>
<StackPanel Orientation="Horizontal" VerticalAlignment="Center"> <ComboBoxItem Content="Changelogs"/>
<controls:DropShadowPanel Margin="20,0"> <ComboBoxItem Content="Messages"/>
<TextBlock FontFamily="Segoe MDL2 Assets" Text="&#xE0A6;" Style="{ThemeResource HeaderTextBlockStyle}"/> </ComboBox>
</controls:DropShadowPanel> </StackPanel>
<controls:DropShadowPanel> </controls:MasterDetailsView.MasterHeader>
<TextBlock Text="Select an item to view" Style="{StaticResource SubheaderTextBlockStyle}"/>
</controls:DropShadowPanel> <controls:MasterDetailsView.NoSelectionContent>
</StackPanel> <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
</controls:MasterDetailsView.NoSelectionContent> <controls:DropShadowPanel Margin="20,0">
<controls:MasterDetailsView.ItemContainerStyle> <TextBlock FontFamily="Segoe MDL2 Assets" Text="&#xE0A6;" Style="{ThemeResource HeaderTextBlockStyle}"/>
<Style TargetType="ListViewItem"> </controls:DropShadowPanel>
<Setter Property="Padding" Value="0"/> <controls:DropShadowPanel>
</Style> <TextBlock Text="Select an item to view" Style="{StaticResource SubheaderTextBlockStyle}"/>
</controls:MasterDetailsView.ItemContainerStyle> </controls:DropShadowPanel>
<controls:MasterDetailsView.ItemTemplate> </StackPanel>
<DataTemplate x:DataType="models:InboxItem"> </controls:MasterDetailsView.NoSelectionContent>
<Grid ColumnSpacing="10" Margin="10">
<Grid.ColumnDefinitions> <controls:MasterDetailsView.ItemContainerStyle>
<ColumnDefinition Width="auto"/> <Style TargetType="ListViewItem">
<ColumnDefinition/> <Setter Property="Padding" Value="0"/>
</Grid.ColumnDefinitions> </Style>
<Grid.Resources> </controls:MasterDetailsView.ItemContainerStyle>
<Style TargetType="TextBlock">
<Setter Property="TextTrimming" Value="CharacterEllipsis"/> <controls:MasterDetailsView.ItemTemplate>
<Setter Property="MaxLines" Value="1"/> <DataTemplate x:DataType="models:InboxItem">
<Setter Property="TextWrapping" Value="WrapWholeWords"/> <Grid ColumnSpacing="10" Margin="10">
</Style> <Grid.ColumnDefinitions>
</Grid.Resources> <ColumnDefinition Width="auto"/>
<ColumnDefinition/>
<PersonPicture Width="50" VerticalAlignment="Top" ProfilePicture="{Binding Avatar}" Initials="{Binding DefaultIcon}" FontFamily="Segoe MDL2 Assets" Foreground="White"/> </Grid.ColumnDefinitions>
<StackPanel Grid.Column="1">
<TextBlock Text="{Binding Title}" Style="{StaticResource SubtitleTextBlockStyle}"/> <PersonPicture Width="50" VerticalAlignment="Top" ProfilePicture="{Binding Avatar}" Initials="{Binding DefaultIcon}" FontFamily="Segoe MDL2 Assets" Foreground="White"/>
<TextBlock Text="{Binding Description}" MaxLines="2"/> <StackPanel Grid.Column="1">
<TextBlock Style="{StaticResource CaptionTextBlockStyle}" FontStyle="Italic"> <TextBlock Text="{Binding Title}" Style="{StaticResource SubtitleTextBlockStyle}" MaxLines="1"/>
<TextBlock Text="{Binding Description}" MaxLines="2"/>
<TextBlock Style="{StaticResource CaptionTextBlockStyle}" FontStyle="Italic" MaxLines="1">
<Run Text="{Binding Type}"/> • <Run Text="{Binding ShortTimeStamp}"/> <Run Text="{Binding Type}"/> • <Run Text="{Binding ShortTimeStamp}"/>
</TextBlock> </TextBlock>
</StackPanel> </StackPanel>
</Grid> </Grid>
</DataTemplate> </DataTemplate>
</controls:MasterDetailsView.ItemTemplate> </controls:MasterDetailsView.ItemTemplate>
<controls:MasterDetailsView.DetailsTemplate>
<DataTemplate x:DataType="models:InboxItem"> <controls:MasterDetailsView.DetailsTemplate>
<ScrollViewer> <DataTemplate x:DataType="models:InboxItem">
<RelativePanel Margin="10"> <ScrollViewer>
<PersonPicture x:Name="avatar" Foreground="White" FontFamily="Segoe MDL2 Assets" Initials="{Binding DefaultIcon}" ProfilePicture="{Binding Avatar}" Height="60" Margin="10"/> <Grid RowSpacing="10" Margin="10">
<StackPanel RelativePanel.RightOf="avatar"> <Grid.RowDefinitions>
<TextBlock Style="{StaticResource SubtitleTextBlockStyle}" Text="{Binding Title}"/> <RowDefinition Height="auto"/>
<TextBlock Text="{Binding TimeStamp}"/> <RowDefinition Height="auto"/>
<TextBlock Style="{StaticResource CaptionTextBlockStyle}" FontStyle="Italic" Text="{Binding Type}"/> <RowDefinition Height="auto"/>
</StackPanel> </Grid.RowDefinitions>
<RelativePanel Margin="0,10">
<PersonPicture x:Name="avatar" Foreground="White" FontFamily="Segoe MDL2 Assets" Initials="{Binding DefaultIcon}" ProfilePicture="{Binding Avatar}" Height="60"/>
<StackPanel RelativePanel.RightOf="avatar" Margin="10,0">
<TextBlock Style="{StaticResource SubtitleTextBlockStyle}" Text="{Binding Title}"/>
<TextBlock Text="{Binding TimeStamp}"/>
<TextBlock Style="{StaticResource CaptionTextBlockStyle}" FontStyle="Italic" Text="{Binding Type}"/>
</StackPanel>
</RelativePanel>
<controls:MarkdownTextBlock Background="Transparent" RelativePanel.Below="avatar" Text="{Binding Content}"/> <controls:MarkdownTextBlock Background="Transparent" Grid.Row="1" Text="{Binding Content}"/>
</RelativePanel>
</ScrollViewer>
</DataTemplate> </Grid>
</controls:MasterDetailsView.DetailsTemplate> </ScrollViewer>
</controls:MasterDetailsView> </DataTemplate>
</controls:MasterDetailsView.DetailsTemplate>
</controls:MasterDetailsView>
</Page> </Page>
+36 -41
View File
@@ -1,57 +1,52 @@
using FoxTube.Core.Models; using FoxTube.Models;
using FoxTube.Core.Models.Inbox; using System.Linq;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using Windows.UI.Xaml; using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls;
namespace FoxTube.Views.SettingsSections namespace FoxTube.Views.SettingsSections
{ {
/// <summary> /// <summary>
/// Inbox view /// Inbox view
/// </summary> /// </summary>
public sealed partial class Inbox : Page public sealed partial class Inbox : Page
{ {
List<InboxItem> items; InboxItem[] items;
string idToOpen; string idToOpen;
public Inbox() => public Inbox() =>
InitializeComponent(); InitializeComponent();
async void Page_Loaded(object sender, RoutedEventArgs e) private async void Page_Loaded(object sender, RoutedEventArgs e)
{ {
items = await Core.Helpers.Inbox.GetInbox(); items = await Services.Inbox.GetMessages();
// TODO: Remove filter.SelectedIndex = 0;
items.Add(new Changelog("1.0", "Changelog content", "Changelog description", DateTime.Now));
items.Add(new DeveloperMessage("id", "Message title", "Message content", DateTime.Now, ""));
filter.SelectedIndex = 0; progressBar.IsIndeterminate = false;
filter.IsEnabled = true;
progressBar.Visibility = Visibility.Collapsed; if (idToOpen != null)
filter.IsEnabled = true; Open(idToOpen);
}
if (idToOpen != null) private void FilterChanged(object sender, SelectionChangedEventArgs e) =>
Open(idToOpen); masterDetailsView.ItemsSource = filter.SelectedIndex switch
} {
1 => items.Where(i => i.Id.StartsWith("changelog")),
2 => items.Where(i => i.Id.StartsWith("inbox")),
_ => items
};
void FilterChanged(object sender, SelectionChangedEventArgs e) => public void Open(string id)
masterDetailsView.ItemsSource = filter.SelectedIndex switch {
{ idToOpen = id;
1 => items.FindAll(i => i is Changelog), if (!IsLoaded)
2 => items.FindAll(i => i is DeveloperMessage), return;
_ => items
};
public void Open(string id) masterDetailsView.SelectedItem = (masterDetailsView.ItemsSource as List<InboxItem>).Find(i => i.Id == id);
{
idToOpen = id;
if (!IsLoaded)
return;
masterDetailsView.SelectedItem = (masterDetailsView.ItemsSource as List<InboxItem>).Find(i => i.Id == id); idToOpen = null;
}
idToOpen = null; }
}
}
} }
@@ -1,68 +0,0 @@
<Page
x:Class="FoxTube.Views.SettingsSections.Translate"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:FoxTube.Views.SettingsSections"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:globalization="using:System.Globalization"
mc:Ignorable="d">
<StackPanel>
<TextBlock Text="Help us translate this app" Style="{StaticResource SubheaderTextBlockStyle}"/>
<TextBlock TextWrapping="WrapWholeWords" Text="You can help us make this app better and deliver it to more regions by translating it" Margin="0,0,0,10"/>
<TextBlock Text="It's quite simple:" Margin="0,0,0,10"/>
<ComboBox Header="1. Choose language you want to translate into" PlaceholderText="Choose language..." Name="LangList" Margin="0,0,0,10" MinWidth="350">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="globalization:CultureInfo">
<TextBlock Text="{Binding DisplayName}" Tag="{Binding ThreeLetterISOLanguageName}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<TextBlock Text="2. Save language pack file to your PC" Margin="0,0,0,10"/>
<Button Content="Export to PC (.zip)" Margin="0,0,0,10" Name="export" IsEnabled="False"/>
<TextBlock TextWrapping="WrapWholeWords" Text="3. Open archive's files with any text editor you want (Notepad, Wordpad, Notepad++, VS Code, etc.)" Margin="0,0,0,10"/>
<TextBlock TextWrapping="WrapWholeWords" Text="4. Edit file by translating nececcary words and sentences" Margin="0,0,0,10"/>
<TextBlock TextWrapping="WrapWholeWords" Text="5. Upload final package to our servers" Margin="0,0,0,10"/>
<StackPanel Name="submitNotification" Visibility="Collapsed" BorderThickness="2" BorderBrush="OrangeRed" Width="350" HorizontalAlignment="Left" Margin="0,0,0,10" Padding="0,0,0,3">
<TextBlock Foreground="OrangeRed" FontWeight="SemiBold" Text="Attention! Once you submitted this language pack you won't be able to contribute to the language anymore. Think twice before continuing" TextWrapping="WrapWholeWords" Margin="5"/>
</StackPanel>
<Button Content="Choose file to upload" Margin="-1,0,0,10" HorizontalAlignment="Left" VerticalAlignment="Top" Name="upload" IsEnabled="False"/>
<Border Background="{ThemeResource SystemChromeMediumLowColor}" CornerRadius="10" Padding="10" HorizontalAlignment="Left" Name="certification" Visibility="Collapsed">
<StackPanel>
<TextBlock FontWeight="Bold" Text="Package certification result"/>
<StackPanel Orientation="Horizontal" Margin="0,5" Name="certificationStatus">
<FontIcon Glyph="&#xEC61;" Foreground="Green"/>
<TextBlock Text="Passed" Margin="5,0"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Visibility="Visible">
<Button Content="Upload" Name="submit"/>
<Button Content="View log" Name="log"/>
<Button Content="Choose another file" Margin="10,0,0,0" Name="chooseFile"/>
</StackPanel>
<ProgressBar HorizontalAlignment="Stretch" IsIndeterminate="True" Name="uploadingProgress" Visibility="Visible"/>
</StackPanel>
</Border>
<TextBlock TextWrapping="WrapWholeWords">
It takes about 2-3 weeks to process new language pack and include it to the next updateThank you for your help &#x1F61A;<LineBreak/>
Best wishes,</TextBlock>
<TextBlock Text=" XFox"/>
<StackPanel Orientation="Horizontal" BorderBrush="Green" BorderThickness="5" Margin="0,10,30,0" Visibility="Collapsed" Name="greenResult">
<TextBlock FontFamily="Segoe MDL2 Assets" Text="&#xE76E;" FontSize="40" Foreground="Green" Margin="5"/>
<StackPanel>
<TextBlock Text="Your language pack has been sent!" Foreground="Green" FontWeight="Bold" FontSize="20"/>
<TextBlock Text="Thank you! It's very imortant for us. You help us making the app better" Foreground="Green"/>
</StackPanel>
</StackPanel>
</StackPanel>
</Page>
@@ -1,30 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238
namespace FoxTube.Views.SettingsSections
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class Translate : Page
{
public Translate()
{
this.InitializeComponent();
}
}
}
+3 -4
View File
@@ -1,4 +1,4 @@
<models:PageView <Page
xmlns:models="using:FoxTube.Core.Models" xmlns:models="using:FoxTube.Core.Models"
x:Class="FoxTube.Views.Subscriptions" x:Class="FoxTube.Views.Subscriptions"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
@@ -7,8 +7,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls" xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
mc:Ignorable="d" mc:Ignorable="d">
Header="Subscriptions">
<ListView Padding="10" SelectionMode="None"> <ListView Padding="10" SelectionMode="None">
<ListViewItem Padding="0" HorizontalAlignment="Left"> <ListViewItem Padding="0" HorizontalAlignment="Left">
@@ -38,4 +37,4 @@
</Grid> </Grid>
</ListViewItem> </ListViewItem>
</ListView> </ListView>
</models:PageView> </Page>
+9 -23
View File
@@ -1,27 +1,13 @@
using FoxTube.Core.Models; using Windows.UI.Xaml.Controls;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
namespace FoxTube.Views namespace FoxTube.Views
{ {
/// <summary> /// <summary>
/// User's subscriptions list /// User's subscriptions list
/// </summary> /// </summary>
public sealed partial class Subscriptions : PageView public sealed partial class Subscriptions : Page
{ {
public Subscriptions() => public Subscriptions() =>
InitializeComponent(); InitializeComponent();
} }
} }