Archived
1
0

Merged PR 21: Version 0.2.1901-2

- Added ability to delete comments. Fixes

Related Work Items: #228, #234
- Refactored Video page

Related Work Items: #183, #186
- Player refactoring
- Chat

Related Work Items: #183, #185
- New Logo draft
- Improving thumbnails quality
- Seek slider fixes

Related Work Items: #235, #237
- Regions and languagaes improved. Video cards duration display fixed. Added settings updating system

Related Work Items: #236
- Items cards' context menu. Fixed duplicating authors' name on comments replies. Another version of logo

Related Work Items: #226
- Context menu for cards done

Related Work Items: #226
- Live stats update done

Related Work Items: #183, #186
- Settings recovery system improvements
- Missync fixed. New logo. Supporting all existing qualities

Related Work Items: #207
- Added support of livestreams. Chat messages avatars added. Formatting live chat messages added. Few player fixes

Related Work Items: #183, #184
- Refactored player. Refactored changelog system. Players isn't localized

Related Work Items: #161, #211, #238
- Player fixes. Localization updates. Tiles updated

Related Work Items: #161
- Menu render fix

Related Work Items: #239
- Fullscreen mode fixes

Related Work Items: #240
- Manifest changes
- Ads development
- Video cards fixes. Localization fixes. CardAdvert created

Related Work Items: #244, #245
- Localization fixed. Player fixes. Menu fixes

Related Work Items: #243, #245
- Menu displaying fixes
- Fixes

Related Work Items: #241, #242, #249, #250
- SafeSearch filter fixed
- Video page fixes

Related Work Items: #249
- Patchnote updated
- Version updated
This commit is contained in:
Michael Gordeev
2019-01-08 14:55:58 +00:00
parent abd8aabc56
commit eea3b11e23
128 changed files with 5240 additions and 1293 deletions
+4 -5
View File
@@ -131,14 +131,13 @@
<Version>6.1.5</Version> <Version>6.1.5</Version>
</PackageReference> </PackageReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup />
<Reference Include="System.Net.WebClient">
<HintPath>..\..\..\..\..\..\Program Files (x86)\Microsoft SDKs\UWPNuGetPackages\microsoft.netcore.universalwindowsplatform\6.1.5\ref\uap10.0.15138\System.Net.WebClient.dll</HintPath>
</Reference>
</ItemGroup>
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '14.0' "> <PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '14.0' ">
<VisualStudioVersion>14.0</VisualStudioVersion> <VisualStudioVersion>14.0</VisualStudioVersion>
</PropertyGroup> </PropertyGroup>
<PropertyGroup>
<SignAssembly>false</SignAssembly>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets" /> <Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.
+35 -6
View File
@@ -1,10 +1,39 @@
using Windows.Data.Xml.Dom; using Newtonsoft.Json;
using System.Collections.Generic;
using Windows.ApplicationModel.Resources;
using Windows.Data.Xml.Dom;
using Windows.Storage;
using Windows.UI.Notifications; using Windows.UI.Notifications;
namespace FoxTube.Background namespace FoxTube.Background
{ {
public static class Notification public static class Notification
{ {
private static Dictionary<string, string> languagePack = LoadPack();
private static Dictionary<string, string> LoadPack()
{
object[] saved = JsonConvert.DeserializeObject<object[]>(ApplicationData.Current.RoamingSettings.Values["settings"] as string);
if (saved[7] as string == "ru-RU")
return new Dictionary<string, string>()
{
{ "addLater", "Посмотреть позже" },
{ "changelog", "Список изменений" },
{ "changelogHeader", "Что нового в версии" },
{ "videoContent", "загрузил новое видео" },
{ "goChannel", "Открыть канал" }
};
else
return new Dictionary<string, string>()
{
{ "addLater", "Add to Watch later" },
{ "changelog", "Changelog" },
{ "changelogHeader", "What's new in version" },
{ "videoContent", "uploaded a new video" },
{ "goChannel", "Go to channel" }
};
}
public static ToastNotification GetChangelogToast(string version) public static ToastNotification GetChangelogToast(string version)
{ {
XmlDocument template = new XmlDocument(); XmlDocument template = new XmlDocument();
@@ -14,8 +43,8 @@ namespace FoxTube.Background
<binding template='ToastGeneric'> <binding template='ToastGeneric'>
<image placement='hero' src='http://foxgame-studio.000webhostapp.com/FoxTubeAssets/WhatsNewThumb.png'/> <image placement='hero' src='http://foxgame-studio.000webhostapp.com/FoxTubeAssets/WhatsNewThumb.png'/>
<image placement='appLogoOverride' hint-crop='circle' src='http://foxgame-studio.000webhostapp.com/FoxTubeAssets/NewsAvatar.png'/> <image placement='appLogoOverride' hint-crop='circle' src='http://foxgame-studio.000webhostapp.com/FoxTubeAssets/NewsAvatar.png'/>
<text>Changelog</text> <text>{languagePack["changelog"]}</text>
<text>See what's new in version {version}</text> <text>{languagePack["changelogHeader"]} {version}</text>
</binding> </binding>
</visual> </visual>
</toast>"); </toast>");
@@ -33,13 +62,13 @@ namespace FoxTube.Background
<image placement='hero' src='{thumbnail.Replace("&", "%26")}'/> <image placement='hero' src='{thumbnail.Replace("&", "%26")}'/>
<image placement='appLogoOverride' hint-crop='circle' src='{avatar.Replace("&", "%26") ?? "http://foxgame-studio.000webhostapp.com/FoxTubeAssets/LogoAvatar.png"}'/> <image placement='appLogoOverride' hint-crop='circle' src='{avatar.Replace("&", "%26") ?? "http://foxgame-studio.000webhostapp.com/FoxTubeAssets/LogoAvatar.png"}'/>
<text>{title}</text> <text>{title}</text>
<text>{channel} uploaded a new video</text> <text>{channel} {languagePack["videoContent"]}</text>
</binding> </binding>
</visual> </visual>
<actions> <actions>
<action content='Add to Watch later' activationType='background' arguments='later|{id}'/> <action content='{languagePack["addLater"]}' activationType='background' arguments='later|{id}'/>
<action content='Go to channel' activationType='foreground' arguments='channel|{channelId}'/> <action content='{languagePack["goChannel"]}' activationType='foreground' arguments='channel|{channelId}'/>
</actions> </actions>
</toast>"); </toast>");
+35 -5
View File
@@ -1,9 +1,39 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<items> <items>
<item time="2018-07-29T23:00:00-03" version="1.0.1"> <item time="2019-01-05" version="0.2.19012">
<content>Announcement body (beware of special characters)</content> <content>
<en-US>### What's new:
- 'Live' button fixed in the player
- Long channel names on crads fixed
- Fixed video description disappearing on window resizing
- Player seek is fixed
- Added video buffering progress indicatior
- Small fixes
### Known issues:
- Recommended and subscriptions pages aren't implemented
- History isn't implemented
- Playlists management isn't implemented
- Ads aren't implemented
</en-US>
<ru-RU>### Что нового:
- Кнопка перехода к прямому эфиру на стримах теперь работает
- Исправлен баг с длинными именами каналов на карточках
- Исправлено исчезание описания видео при изменении размеров окна
- Исправлен ползунок перемотки видео
- Добавлен индикатор буферизации видео
- Мелкие исправления
### Что по-прежнему не работает:
- Страница рекомендованных видео и страница видео с подписок
- История
- Работа с плейлистами
- Нет карточек рекламы
</ru-RU>
</content>
</item> </item>
</items> </items>
<!--<item time="YYYY-MM-DDThh:mm:ss-03" version="1.0.1">
<content>Announcement body (beware of special characters)</content>
</item>-->
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 961 B

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 172 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 394 B

After

Width:  |  Height:  |  Size: 610 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 699 B

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1020 B

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 785 B

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 934 B

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 343 B

After

Width:  |  Height:  |  Size: 461 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 475 B

After

Width:  |  Height:  |  Size: 723 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 595 B

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 831 B

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

After

Width:  |  Height:  |  Size: 55 KiB

-33
View File
@@ -1,33 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FoxTube.Classes
{
public class Caption
{
public TimeSpan Start { get; private set; }
public TimeSpan Duration { get; private set; }
public TimeSpan End
{
get { return Start + Duration; }
}
public string Text { get; private set; }
public Caption(int startTime, int duration, string text)
{
Start = TimeSpan.FromMilliseconds(startTime);
Duration = TimeSpan.FromMilliseconds(duration);
Text = text;
}
public Caption(double startTime, double duration, string text)
{
Start = TimeSpan.FromSeconds(startTime);
Duration = TimeSpan.FromSeconds(duration);
Text = text;
}
}
}
+6 -3
View File
@@ -1,5 +1,6 @@
using System; using System;
using System.Xml; using System.Xml;
using Windows.ApplicationModel.Resources;
namespace FoxTube.Classes namespace FoxTube.Classes
{ {
@@ -14,6 +15,8 @@ namespace FoxTube.Classes
public string Content { get; set; } public string Content { get; set; }
public string Id { get; set; } public string Id { get; set; }
private ResourceLoader resources = ResourceLoader.GetForCurrentView("Inbox");
public string Icon public string Icon
{ {
get get
@@ -29,9 +32,9 @@ namespace FoxTube.Classes
get get
{ {
if (Type == InboxItemType.PatchNote) if (Type == InboxItemType.PatchNote)
return "Patch note"; return resources.GetString("changelog");
else else
return "Developer's message"; return resources.GetString("dev");
} }
} }
@@ -40,7 +43,7 @@ namespace FoxTube.Classes
get get
{ {
if (Type == InboxItemType.PatchNote) if (Type == InboxItemType.PatchNote)
return $"What's new in v{Id}"; return $"{resources.GetString("whatsnew")}{Id}";
else else
return Subject; return Subject;
} }
+99 -15
View File
@@ -1,4 +1,7 @@
using Google.Apis.YouTube.v3; using FoxTube.Controls.Adverts;
using FoxTube.Pages;
using Google.Apis.YouTube.v3;
using Microsoft.Advertising.WinRT.UI;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
@@ -6,8 +9,10 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Web; using System.Web;
using System.Xml;
using Windows.ApplicationModel.Core; using Windows.ApplicationModel.Core;
using Windows.ApplicationModel.DataTransfer; using Windows.ApplicationModel.DataTransfer;
using Windows.ApplicationModel.Resources;
using Windows.Storage; using Windows.Storage;
using Windows.Storage.Streams; using Windows.Storage.Streams;
using Windows.System; using Windows.System;
@@ -16,11 +21,15 @@ using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Documents; using Windows.UI.Xaml.Documents;
using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Media;
using YoutubeExplode.Models.MediaStreams;
namespace FoxTube namespace FoxTube
{ {
public static class Methods public static class Methods
{ {
private static ResourceLoader resources = ResourceLoader.GetForCurrentView("Methods");
public static CommentsPage CommentsPage { get; set; }
public static bool NeedToResponse { get; set; } = false; public static bool NeedToResponse { get; set; } = false;
public static MainPage MainPage public static MainPage MainPage
{ {
@@ -37,6 +46,30 @@ namespace FoxTube
return new Uri(url); return new Uri(url);
} }
public static string GetChars(this string str, int count)
{
try
{
string s = "";
for (int i = 0; i < count; i++)
s += str[i];
return s;
}
catch
{
return "";
}
}
public static List<object> ToReversedList(this Array array)
{
List<object> list = new List<object>();
foreach (object i in array)
list.Add(i);
list.Reverse();
return list;
}
public static void ForEach<T>(this IEnumerable<T> array, Action<T> action) public static void ForEach<T>(this IEnumerable<T> array, Action<T> action)
{ {
array.ToList().ForEach(action); array.ToList().ForEach(action);
@@ -64,36 +97,56 @@ namespace FoxTube
return arr[arr.Length - 1]; return arr[arr.Length - 1];
} }
public static TimeSpan GetDuration(this string str)
{
try
{
return XmlConvert.ToTimeSpan(str);
}
catch (FormatException)
{
TimeSpan time = XmlConvert.ToTimeSpan("PT" + str.Split('T')[1]);
TimeSpan date = TimeSpan.FromDays(int.Parse(str.Split('W')[0].Replace("P", "")) * 7);
date.Add(time);
return date;
}
catch
{
return TimeSpan.FromMilliseconds(0);
}
}
public static string GetAgo(DateTime dateTime) public static string GetAgo(DateTime dateTime)
{ {
TimeSpan span = DateTime.Now - dateTime; TimeSpan span = DateTime.Now - dateTime;
if (span.TotalMinutes < 1) if (span.TotalMinutes < 1)
return "Just now"; return resources.GetString("/Methods/now");
else if (Math.Round(span.TotalMinutes) == 1) else if (Math.Round(span.TotalMinutes) == 1)
return "1 minute ago"; return resources.GetString("/Methods/oneMinute");
else if (span.TotalMinutes < 60) else if (span.TotalMinutes < 60)
return Math.Round(span.TotalMinutes) + " minutes ago"; return Math.Round(span.TotalMinutes) + " " + resources.GetString("/Methods/minutes");
else if (Math.Round(span.TotalHours) == 1) else if (Math.Round(span.TotalHours) == 1)
return "1 hour ago"; return resources.GetString("/Methods/oneHr");
else if (span.TotalHours < 24) else if (span.TotalHours < 24)
return Math.Round(span.TotalHours) + " hours ago"; return Math.Round(span.TotalHours) + " " + resources.GetString("/Methods/hrs");
else if (Math.Round(span.TotalDays) == 1) else if (Math.Round(span.TotalDays) == 1)
return "1 day ago"; return resources.GetString("/Methods/oneDay");
else if (span.TotalDays < 7) else if (span.TotalDays < 7)
return Math.Round(span.TotalDays) + " days ago"; return Math.Round(span.TotalDays) + " " + resources.GetString("/Methods/days");
else if (Math.Round(span.TotalDays) == 7) else if (Math.Round(span.TotalDays) == 7)
return "1 week ago"; return resources.GetString("/Methods/oneWeek");
else if (span.TotalDays < 30) else if (span.TotalDays < 30)
return Math.Round(span.TotalDays / 7) + " weeks ago"; return Math.Round(span.TotalDays / 7) + " " + resources.GetString("/Methods/weeks");
else if (Math.Round(span.TotalDays) == 30) else if (Math.Round(span.TotalDays) == 30)
return "1 month ago"; return resources.GetString("/Methods/oneMonth");
else if (Math.Round(span.TotalDays) < 365) else if (Math.Round(span.TotalDays) < 365)
return Math.Round(span.TotalDays / 30) + " months ago"; return Math.Round(span.TotalDays / 30) + " " + resources.GetString("/Methods/months");
else if (Math.Round(span.TotalDays / 365) == 365) else if (Math.Round(span.TotalDays / 365) == 365)
return "1 year ago"; return resources.GetString("/Methods/oneYear");
else else
return Math.Round(span.TotalDays / 365) + " years ago"; return Math.Round(span.TotalDays / 365) + " " + resources.GetString("/Methods/years");
} }
public static void FormatText(ref TextBlock block, string text) public static void FormatText(ref TextBlock block, string text)
@@ -139,6 +192,37 @@ namespace FoxTube
} }
} }
public static string GetVideoQualityLabel(this VideoQuality quality)
{
switch (quality)
{
case VideoQuality.High1080:
return "1080p";
case VideoQuality.High1440:
return "1440p";
case VideoQuality.High2160:
return "2160p";
case VideoQuality.High2880:
return "2880p";
case VideoQuality.High3072:
return "3072p";
case VideoQuality.High4320:
return "4320p";
case VideoQuality.High720:
return "720p";
case VideoQuality.Low144:
return "144p";
case VideoQuality.Low240:
return "240p";
case VideoQuality.Medium360:
return "360p";
case VideoQuality.Medium480:
return "480p";
default:
return "Unknown";
}
}
/*public static string QualityToString(YouTubeQuality quality) /*public static string QualityToString(YouTubeQuality quality)
{ {
switch(quality) switch(quality)
@@ -242,7 +326,7 @@ namespace FoxTube
{ {
DataRequest request = args.Request; DataRequest request = args.Request;
request.Data.Properties.Title = title; request.Data.Properties.Title = title;
request.Data.Properties.Description = $"Sharing a {type}"; request.Data.Properties.Description = $"{resources.GetString("/Methods/sharing")} {type}";
request.Data.SetText(title + "\n" + "#YouTube #FoxTube #SharedWithFoxTube"); request.Data.SetText(title + "\n" + "#YouTube #FoxTube #SharedWithFoxTube");
request.Data.SetWebLink(url.ToUri()); request.Data.SetWebLink(url.ToUri());
+32 -6
View File
@@ -8,6 +8,7 @@ using Google.Apis.YouTube.v3;
using Google.Apis.YouTube.v3.Data; using Google.Apis.YouTube.v3.Data;
using Newtonsoft.Json; using Newtonsoft.Json;
using Windows.Storage; using Windows.Storage;
using Windows.Services.Store;
namespace FoxTube namespace FoxTube
{ {
@@ -17,7 +18,7 @@ namespace FoxTube
//Events //Events
public static event ObjectEventHandler AuthorizationStateChanged; public static event ObjectEventHandler AuthorizationStateChanged;
public static event ObjectEventHandler SubscriptionsChanged; public static event ObjectEventHandler SubscriptionsChanged;
public static event Event NotPurchased; //Rising when app finds out that it's not a PRO version public static event ObjectEventHandler Purchased; //Rising when app finds out that it's not a PRO version
//Private properties //Private properties
private static ClientSecrets Secrets => new ClientSecrets() private static ClientSecrets Secrets => new ClientSecrets()
@@ -36,6 +37,8 @@ namespace FoxTube
ApplicationName = "FoxTube" ApplicationName = "FoxTube"
}; };
public static YouTubeService Service => IsAuthorized ? new YouTubeService(Initializer) : NoAuthService; public static YouTubeService Service => IsAuthorized ? new YouTubeService(Initializer) : NoAuthService;
public static string AppId => true ? "d25517cb-12d4-4699-8bdc-52040c712cab" : "9ncqqxjtdlfh";
public static string AdUnitId => true ? "test" : "1100037769";
public static bool AdsDisabled { get; private set; } = true; public static bool AdsDisabled { get; private set; } = true;
//User info //User info
@@ -193,15 +196,38 @@ namespace FoxTube
/// <summary> /// <summary>
/// Connects to MS Store and checks if user has bought ad-free /// Connects to MS Store and checks if user has bought ad-free
/// </summary> /// </summary>
public static void CheckAddons() public static async void CheckAddons()
{ {
//TODO: Check addons list try
bool purchased = true; {
StoreContext store = StoreContext.GetDefault();
StoreProductQueryResult requset = await store.GetAssociatedStoreProductsAsync(new[] { "Consumable", "Durable", "UnmanagedConsumable" });
if(!purchased) if (!requset.Products["foxtube-adsremove"].IsInUserCollection)
{ {
AdsDisabled = false; AdsDisabled = false;
NotPurchased?.Invoke(); Purchased?.Invoke(args:false);
}
}
catch { }
}
public static async void GetAdblock()
{
StoreContext store = StoreContext.GetDefault();
StorePurchaseResult request = await store.RequestPurchaseAsync("foxtube-adsremove");
switch (request.Status)
{
case StorePurchaseStatus.AlreadyPurchased:
Purchased?.Invoke(args: true);
AdsDisabled = true;
break;
case StorePurchaseStatus.Succeeded:
Purchased?.Invoke(args: true);
AdsDisabled = true;
break;
} }
} }
#endregion #endregion
+78 -11
View File
@@ -7,6 +7,8 @@ using Windows.Storage;
namespace FoxTube namespace FoxTube
{ {
public enum MatureState { Blocked, Allowed, AllowedOnce }
public static class SettingsStorage public static class SettingsStorage
{ {
public static string VideoQuality public static string VideoQuality
@@ -84,7 +86,7 @@ namespace FoxTube
SaveData(); SaveData();
} }
} }
public static string Region public static string RelevanceLanguage
{ {
get { return (string)settings[8]; } get { return (string)settings[8]; }
set set
@@ -93,17 +95,16 @@ namespace FoxTube
SaveData(); SaveData();
} }
} }
public static int SafeSearch public static string Region
{ {
get { return Convert.ToInt32(settings[9]); } get { return (string)settings[9]; }
set set
{ {
settings[9] = value; settings[9] = value;
SaveData(); SaveData();
} }
} }
public static int SafeSearch
public static int Theme
{ {
get { return Convert.ToInt32(settings[10]); } get { return Convert.ToInt32(settings[10]); }
set set
@@ -112,15 +113,25 @@ namespace FoxTube
SaveData(); SaveData();
} }
} }
public static bool HasAccount
public static int Theme
{ {
get { return (bool)settings[11]; } get { return Convert.ToInt32(settings[11]); }
set set
{ {
settings[11] = value; settings[11] = value;
SaveData(); SaveData();
} }
} }
public static bool HasAccount
{
get { return (bool)settings[12]; }
set
{
settings[12] = value;
SaveData();
}
}
public static string Version public static string Version
{ {
@@ -139,9 +150,25 @@ namespace FoxTube
storage.Values["version"] = value; storage.Values["version"] = value;
} }
} }
public static MatureState Mature
{
get
{
if (storage.Values["mature"] == null)
{
storage.Values["mature"] = MatureState.Blocked;
return MatureState.Blocked;
}
else return (MatureState)storage.Values["mature"];
}
set
{
storage.Values["mature"] = value;
}
}
//Settings storage //Settings storage
private static readonly ApplicationDataContainer storage = ApplicationData.Current.LocalSettings; private static readonly ApplicationDataContainer storage = ApplicationData.Current.RoamingSettings;
//Predefined preferences //Predefined preferences
private static object[] settings = new object[] private static object[] settings = new object[]
@@ -157,7 +184,8 @@ namespace FoxTube
100, 100,
(new[] { "ua", "ru", "by", "kz", "kg", "md", "lv", "ee" }).Contains(CultureInfo.InstalledUICulture.TwoLetterISOLanguageName) ? "ru-RU" : "en-US", (new[] { "ua", "ru", "by", "kz", "kg", "md", "lv", "ee" }).Contains(CultureInfo.InstalledUICulture.TwoLetterISOLanguageName) ? "ru-RU" : "en-US",
CultureInfo.CurrentCulture.Name, (new[] { "ua", "ru", "by", "kz", "kg", "md", "lv", "ee" }).Contains(CultureInfo.InstalledUICulture.TwoLetterISOLanguageName) ? "ru" : "en",
(new[] { "ua", "ru", "by", "kz", "kg", "md", "lv", "ee" }).Contains(CultureInfo.InstalledUICulture.TwoLetterISOLanguageName) ? "ru" : "US",
0, 0,
2, 2,
@@ -166,14 +194,53 @@ namespace FoxTube
public static void LoadData() public static void LoadData()
{ {
/*if(true && (storage.Values["forceUpdate"] == null || storage.Values["forceUpdate"].ToString() != Version))
{
SaveData();
storage.Values["forceUpdate"] = Version;
return;
}*/
try try
{ {
settings = JsonConvert.DeserializeObject<object[]>(storage.Values["settings"] as string); object[] saved = JsonConvert.DeserializeObject<object[]>(storage.Values["settings"] as string);
if (settings.Length > saved.Length)
{
if (saved[0] is string)
settings[0] = saved;
if (saved[1] is string)
settings[1] = saved;
if (saved[2] is bool)
settings[2] = saved;
if (saved[3] is bool)
settings[3] = saved;
if (saved[4] is bool)
settings[4] = saved;
if (saved[5] is bool)
settings[5] = saved;
if (saved[6] is int)
settings[6] = saved;
if (saved[7] is string)
settings[7] = saved;
if (saved[8] is string)
settings[8] = saved;
if (saved[9] is string)
settings[9] = saved;
if (saved[10] is int)
settings[10] = saved;
if (saved[11] is int)
settings[11] = saved;
if (saved[12] is bool)
settings[12] = saved;
SaveData();
}
else settings = saved;
} }
catch (ArgumentNullException) { } catch (ArgumentNullException) { }
} }
public static async void SaveData() public static void SaveData()
{ {
storage.Values["settings"] = JsonConvert.SerializeObject(settings); storage.Values["settings"] = JsonConvert.SerializeObject(settings);
ExportSettings(); ExportSettings();
+1 -1
View File
@@ -36,7 +36,7 @@ namespace FoxTube.Controls
Visibility = Visibility.Visible; Visibility = Visibility.Visible;
else else
Visibility = Visibility.Collapsed; Visibility = Visibility.Collapsed;
SecretsVault.NotPurchased += () => Visibility = Visibility.Visible; SecretsVault.Purchased += (s, e) => Visibility = (bool)e[0] ? Visibility.Collapsed : Visibility.Visible;
} }
private void Grid_SizeChanged(object sender, SizeChangedEventArgs e) private void Grid_SizeChanged(object sender, SizeChangedEventArgs e)
+44
View File
@@ -0,0 +1,44 @@
<UserControl
x:Class="FoxTube.Controls.Adverts.CardAdvert"
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"
HorizontalAlignment="Stretch"
VerticalAlignment="Top"
SizeChanged="UserControl_SizeChanged"
d:DesignHeight="290"
d:DesignWidth="384">
<Button Padding="0" Background="Transparent" Name="btn">
<Grid Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="75"/>
</Grid.RowDefinitions>
<Image Name="image" Source="/Assets/videoThumbSample.png" Stretch="Fill"/>
<StackPanel Margin="0,0,5,5" Background="Orange" VerticalAlignment="Bottom" BorderBrush="OrangeRed" BorderThickness="1" HorizontalAlignment="Right" Padding="5,2,5,3">
<TextBlock Name="info" Text="SPONSORED CONTENT" VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="Gray" FontSize="12"/>
</StackPanel>
<Grid Grid.Row="1">
<Grid.RowDefinitions>
<RowDefinition Height="20"/>
<RowDefinition Height="55"/>
</Grid.RowDefinitions>
<Grid Name="contentGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="60"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Ellipse Grid.Column="0" Height="50" Width="50" Margin="5,-30,5,10" Fill="{ThemeResource SystemControlBackgroundChromeMediumBrush}"/>
<PersonPicture Name="icon" Grid.Column="0" Height="46" Margin="5,-30,5,0" BorderBrush="White" BorderThickness="10"/>
<TextBlock Name="sponsor" HorizontalAlignment="Left" Grid.Column="1" Text="[Sponsored by]" TextTrimming="CharacterEllipsis" Foreground="Gray" Margin="0,2,0,0" FontSize="12"/>
<TextBlock Grid.Column="1" Name="desc" Text="[Description]" HorizontalAlignment="Right" Foreground="Gray" Margin="0,2,2,0" FontSize="12"/>
</Grid>
<TextBlock Grid.Row="1" Name="title" Text="[Title]" TextWrapping="WrapWholeWords" Margin="5" MaxLines="2" TextTrimming="CharacterEllipsis"/>
</Grid>
</Grid>
</Button>
</UserControl>
@@ -0,0 +1,62 @@
using System.Linq;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Microsoft.Advertising.WinRT.UI;
using Windows.UI.Xaml.Media.Imaging;
namespace FoxTube.Controls.Adverts
{
/// <summary>
/// Advert which is looks similar to video cards
/// </summary>
public sealed partial class CardAdvert : UserControl
{
NativeAdsManagerV2 manager = new NativeAdsManagerV2(SecretsVault.AppId, SecretsVault.AdUnitId);
public NativeAdV2 advert;
public CardAdvert()
{
InitializeComponent();
manager.AdReady += AdReady;
manager.RequestAd();
}
private void AdReady(object sender, NativeAdReadyEventArgs e)
{
advert = e.NativeAd;
Initialize();
e.NativeAd.RegisterAdContainer(this);
}
public void Initialize()
{
title.Text = advert.Title;
image.Source = new BitmapImage(advert.MainImages.First().Url.ToUri());
if (advert.AdIcon == null)
contentGrid.ColumnDefinitions[0].Width = new GridLength(0);
else
icon.ProfilePicture = advert.AdIcon.Source;
if (string.IsNullOrWhiteSpace(advert.SponsoredBy))
sponsor.Visibility = Visibility.Collapsed;
else
sponsor.Text = advert.SponsoredBy;
if (!string.IsNullOrWhiteSpace(advert.Rating))
info.Text += $" {advert.Rating}";
if (string.IsNullOrWhiteSpace(advert.CallToActionText) && string.IsNullOrWhiteSpace(advert.Price))
desc.Visibility = Visibility.Collapsed;
else if (!string.IsNullOrWhiteSpace(advert.CallToActionText))
desc.Text = advert.CallToActionText;
else
desc.Text = advert.Price;
Visibility = Visibility.Visible;
}
private void UserControl_SizeChanged(object sender, SizeChangedEventArgs e)
{
Height = e.NewSize.Width * 0.75;
}
}
}
+13 -4
View File
@@ -20,7 +20,7 @@
<Image Name="cover" Source="/Assets/ChannelCoverTemplate.png" Stretch="UniformToFill" VerticalAlignment="Center"/> <Image Name="cover" Source="/Assets/ChannelCoverTemplate.png" Stretch="UniformToFill" VerticalAlignment="Center"/>
<StackPanel Name="liveTag" Margin="5" Background="Red" BorderBrush="White" BorderThickness="1" VerticalAlignment="Bottom" HorizontalAlignment="Right" Padding="5,2,5,3" Orientation="Horizontal" Visibility="Collapsed"> <StackPanel Name="liveTag" Margin="5" Background="Red" BorderBrush="White" BorderThickness="1" VerticalAlignment="Bottom" HorizontalAlignment="Right" Padding="5,2,5,3" Orientation="Horizontal" Visibility="Collapsed">
<TextBlock Text="&#xEC44; " VerticalAlignment="Center" Foreground="White" FontSize="12" FontFamily="Segoe MDL2 Assets" FontWeight="Black"/> <TextBlock Text="&#xEC44; " VerticalAlignment="Center" Foreground="White" FontSize="12" FontFamily="Segoe MDL2 Assets" FontWeight="Black"/>
<TextBlock Text="LIVE" VerticalAlignment="Center" Foreground="White" FontSize="12" FontWeight="Bold"/> <TextBlock x:Uid="/Cards/live" Text="LIVE" VerticalAlignment="Center" Foreground="White" FontSize="12" FontWeight="Bold"/>
</StackPanel> </StackPanel>
<Grid Grid.Row="1"> <Grid Grid.Row="1">
<Grid.RowDefinitions> <Grid.RowDefinitions>
@@ -36,20 +36,29 @@
<Ellipse Height="80" Width="80" Margin="0,-45,0,0" VerticalAlignment="Bottom" Fill="{ThemeResource SystemControlBackgroundChromeMediumBrush}"/> <Ellipse Height="80" Width="80" Margin="0,-45,0,0" VerticalAlignment="Bottom" Fill="{ThemeResource SystemControlBackgroundChromeMediumBrush}"/>
<PersonPicture Name="avatar" Grid.Column="0" Height="74" Margin="3,-45,3,3" VerticalAlignment="Bottom" BorderBrush="White" BorderThickness="10"/> <PersonPicture Name="avatar" Grid.Column="0" Height="74" Margin="3,-45,3,3" VerticalAlignment="Bottom" BorderBrush="White" BorderThickness="10"/>
<TextBlock Name="title" Grid.Column="1" Text="[Channel name]" Margin="5" TextWrapping="WrapWholeWords" MaxLines="2"/> <TextBlock Name="title" Grid.Column="1" Text="[Channel name]" Margin="5" TextWrapping="WrapWholeWords" MaxLines="2" TextTrimming="CharacterEllipsis"/>
<StackPanel Grid.Column="2" Margin="5"> <StackPanel Grid.Column="2" Margin="5">
<TextBlock Name="subs" Text="[Subscribers counter]" Foreground="Gray"/> <TextBlock Name="subs" Text="[Subscribers counter]" Foreground="Gray"/>
<TextBlock Name="uploads" Text="[Uploads counter]" Foreground="Gray"/> <TextBlock Name="uploads" Text="[Uploads counter]" Foreground="Gray"/>
</StackPanel> </StackPanel>
</Grid> </Grid>
<TextBlock Grid.Row="1" VerticalAlignment="Bottom" HorizontalAlignment="Stretch" Height="50" Margin="10" TextAlignment="Center" Padding="0,16,0,0" Foreground="Gray"> <TextBlock Grid.Row="1" VerticalAlignment="Bottom" HorizontalAlignment="Stretch" Height="50" Margin="10" TextAlignment="Center" Padding="0,16,0,0" Foreground="Gray">
<Hyperlink Click="Hyperlink_Click">Log in</Hyperlink> to manage your subscriptions <Hyperlink Click="Hyperlink_Click"><Run x:Uid="/Cards/login">Log in</Run></Hyperlink> <Run x:Uid="/Cards/tomanage">to manage your subscriptions</Run>
</TextBlock> </TextBlock>
<Grid Visibility="Collapsed" Grid.Row="1" VerticalAlignment="Bottom" Margin="10" Name="subscriptionPane" Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}"> <Grid Visibility="Collapsed" Grid.Row="1" VerticalAlignment="Bottom" Margin="10" Name="subscriptionPane" Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}">
<Button Click="subscribe_Click" Name="subscribe" HorizontalAlignment="Stretch" Height="50" Background="Red" Foreground="White" FontSize="18" FontWeight="SemiBold" Content="Subscirbe" Margin="0,0,0,0"/> <Button x:Uid="/Cards/subscribe" Click="subscribe_Click" Name="subscribe" HorizontalAlignment="Stretch" Height="50" Background="Red" Foreground="White" FontSize="18" FontWeight="SemiBold" Content="Subscirbe" Margin="0,0,0,0"/>
<ToggleButton Name="notify" Height="50" Width="50" Visibility="Collapsed" FontFamily="Segoe MDL2 Assets" FontSize="18" FontWeight="SemiBold" Content="&#xE7ED;" Foreground="White" Background="Red" HorizontalAlignment="Right"/> <ToggleButton Name="notify" Height="50" Width="50" Visibility="Collapsed" FontFamily="Segoe MDL2 Assets" FontSize="18" FontWeight="SemiBold" Content="&#xE7ED;" Foreground="White" Background="Red" HorizontalAlignment="Right"/>
</Grid> </Grid>
</Grid> </Grid>
</Grid> </Grid>
</Button> </Button>
<UserControl.ContextFlyout>
<MenuFlyout>
<MenuFlyoutItem x:Uid="/Cards/channel" Icon="Contact" Text="View channel" Click="Button_Click"/>
<MenuFlyoutSeparator/>
<MenuFlyoutItem x:Uid="/Cards/getLink" Icon="Link" Text="Copy link" Name="getLink" Click="GetLink_Click"/>
<MenuFlyoutItem x:Uid="/Cards/openWeb" Icon="Globe" Text="Open in browser" Name="inBrowser" Click="InBrowser_Click"/>
<MenuFlyoutItem x:Uid="/Cards/share" Icon="Share" Text="Share" Name="share" Visibility="Collapsed"/>
</MenuFlyout>
</UserControl.ContextFlyout>
</UserControl> </UserControl>
+27 -19
View File
@@ -1,34 +1,30 @@
using Google.Apis.YouTube.v3; using Google.Apis.YouTube.v3;
using Google.Apis.YouTube.v3.Data; using Google.Apis.YouTube.v3.Data;
using System; using System;
using System.Collections.Generic; using Windows.ApplicationModel.DataTransfer;
using System.IO; using Windows.ApplicationModel.Resources;
using System.Linq; using Windows.System;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI; using Windows.UI;
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.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging; using Windows.UI.Xaml.Media.Imaging;
using Windows.UI.Xaml.Navigation;
// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236
namespace FoxTube.Controls namespace FoxTube.Controls
{ {
/// <summary>
/// Channel item card
/// </summary>
public sealed partial class ChannelCard : UserControl public sealed partial class ChannelCard : UserControl
{ {
ResourceLoader resources = ResourceLoader.GetForCurrentView("Cards");
string channelId; string channelId;
Channel item; Channel item;
public ChannelCard(string id, string live = "null") public ChannelCard(string id, string live = "null")
{ {
this.InitializeComponent(); InitializeComponent();
Initialize(id, live); Initialize(id, live);
} }
@@ -48,8 +44,8 @@ namespace FoxTube.Controls
title.Text = item.Snippet.Title; title.Text = item.Snippet.Title;
subs.Text = $"{item.Statistics.SubscriberCount:0,0} subscribers"; subs.Text = $"{item.Statistics.SubscriberCount:0,0} {resources.GetString("/Cards/subscribers")}";
uploads.Text = $"{item.Statistics.VideoCount:0,0} videos"; uploads.Text = $"{item.Statistics.VideoCount:0,0} {resources.GetString("/Cards/videos")}";
if (live == "live") if (live == "live")
liveTag.Visibility = Visibility.Visible; liveTag.Visibility = Visibility.Visible;
@@ -62,7 +58,7 @@ namespace FoxTube.Controls
{ {
subscribe.Background = new SolidColorBrush(Colors.Transparent); subscribe.Background = new SolidColorBrush(Colors.Transparent);
subscribe.Foreground = new SolidColorBrush(Colors.Gray); subscribe.Foreground = new SolidColorBrush(Colors.Gray);
subscribe.Content = "Subscribed"; subscribe.Content = resources.GetString("/Cards/unsubscribe");
} }
} }
subscriptionPane.Visibility = Visibility.Visible; subscriptionPane.Visibility = Visibility.Visible;
@@ -74,7 +70,7 @@ namespace FoxTube.Controls
{ {
if (item.BrandingSettings.Image.BannerImageUrl.Contains("default")) if (item.BrandingSettings.Image.BannerImageUrl.Contains("default"))
throw new Exception("Default channel cover detected"); throw new Exception("Default channel cover detected");
cover.Source = new BitmapImage(new Uri(item.BrandingSettings.Image.BannerTvLowImageUrl)); cover.Source = new BitmapImage((item.BrandingSettings.Image.BannerTvHighImageUrl ?? item.BrandingSettings.Image.BannerTvImageUrl).ToUri());
} }
catch { } catch { }
} }
@@ -95,14 +91,26 @@ namespace FoxTube.Controls
{ {
subscribe.Background = new SolidColorBrush(Colors.Transparent); subscribe.Background = new SolidColorBrush(Colors.Transparent);
subscribe.Foreground = new SolidColorBrush(Colors.Gray); subscribe.Foreground = new SolidColorBrush(Colors.Gray);
subscribe.Content = "Subscribed"; subscribe.Content = resources.GetString("/Cards/unsubscribe");
} }
else else
{ {
subscribe.Background = new SolidColorBrush(Colors.Red); subscribe.Background = new SolidColorBrush(Colors.Red);
subscribe.Foreground = new SolidColorBrush(Colors.White); subscribe.Foreground = new SolidColorBrush(Colors.White);
subscribe.Content = "Subscribe"; subscribe.Content = resources.GetString("/Cards/subscribe/Content");
} }
} }
private void GetLink_Click(object sender, RoutedEventArgs e)
{
DataPackage data = new DataPackage();
data.SetText(string.IsNullOrWhiteSpace(item.Snippet.CustomUrl) ? $"https://www.youtube.com/channel/{item.Id}" : $"https://www.youtube.com/user/{item.Snippet.CustomUrl}");
Clipboard.SetContent(data);
}
private async void InBrowser_Click(object sender, RoutedEventArgs e)
{
await Launcher.LaunchUriAsync((string.IsNullOrWhiteSpace(item.Snippet.CustomUrl) ? $"https://www.youtube.com/channel/{item.Id}" : $"https://www.youtube.com/user/{item.Snippet.CustomUrl}").ToUri());
}
} }
} }
+76
View File
@@ -0,0 +1,76 @@
<UserControl
x:Class="FoxTube.Controls.Chat"
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"
d:DesignHeight="600"
d:DesignWidth="400">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid Name="inputField">
<TextBox x:Uid="/Chat/box" Margin="5,5,42,5" PlaceholderText="Send a message" Name="newMessage" VerticalAlignment="Center" MinHeight="32" TextWrapping="Wrap" AcceptsReturn="True"/>
<Button HorizontalAlignment="Right" Name="send" Click="send_Click" VerticalAlignment="Top"
Height="32" Width="32"
Margin="0,5,5,0" Padding="0"
Background="Transparent"
FontFamily="Segoe MDL2 Assets"
Content="&#xE122;" FontSize="30"/>
</Grid>
<ScrollViewer Grid.Row="1">
<ListView Name="list" SelectionMode="None">
<ListView.ItemTemplate>
<DataTemplate>
<Border BorderBrush="Red" BorderThickness="{Binding Path=BorderThickness}" CornerRadius="5" HorizontalAlignment="Stretch" Background="{Binding Path=Background}" Margin="0,2">
<Grid Margin="0,5,5,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal" VerticalAlignment="Top" Margin="5,0">
<PersonPicture Height="20" ProfilePicture="{Binding Path=Avatar}"/>
<FontIcon Glyph="&#xEC61;" Margin="2,0" Visibility="{Binding Path=IsVerified}">
<ToolTipService.ToolTip>
<TextBlock x:Uid="/Chat/verified"/>
</ToolTipService.ToolTip>
</FontIcon>
<FontIcon Glyph="&#xEC1B;" Margin="2,0" Visibility="{Binding Path=IsModerator}">
<ToolTipService.ToolTip>
<TextBlock x:Uid="/Chat/moder"/>
</ToolTipService.ToolTip>
</FontIcon>
<FontIcon Glyph="&#xECA7;" Margin="2,0" Visibility="{Binding Path=IsOwner}">
<ToolTipService.ToolTip>
<TextBlock x:Uid="/Chat/owner"/>
</ToolTipService.ToolTip>
</FontIcon>
<FontIcon Glyph="&#xE735;" Margin="2,0" Visibility="{Binding Path=IsSponsor}">
<ToolTipService.ToolTip>
<TextBlock x:Uid="/Chat/sponsor"/>
</ToolTipService.ToolTip>
</FontIcon>
</StackPanel>
<StackPanel Orientation="Horizontal" Grid.Column="1" VerticalAlignment="Top" Margin="0,0,5,0">
<HyperlinkButton Content="{Binding Path=Author}" Tag="{Binding Path=ChannelId}" Grid.Column="1" Margin="0,-6,0,0" FontWeight="Bold" Click="HyperlinkButton_Click"/>
<TextBlock Text=":"/>
</StackPanel>
<GroupItem Content="{Binding Path=Message}" Grid.Column="2"/>
</Grid>
</Border>
</DataTemplate>
</ListView.ItemTemplate>
<ListViewItem>
<TextBlock x:Uid="/Chat/welcome" Text="Welcome to the chat room" Foreground="Gray"/>
</ListViewItem>
</ListView>
</ScrollViewer>
</Grid>
</UserControl>
+141
View File
@@ -0,0 +1,141 @@
using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
using Google.Apis.YouTube.v3.Data;
using Google.Apis.YouTube.v3;
using Windows.UI;
namespace FoxTube.Controls
{
public class ChatMessage
{
public string Author => message.AuthorDetails.DisplayName;
public TextBlock Message
{
get
{
TextBlock block = new TextBlock()
{
IsTextSelectionEnabled = true,
VerticalAlignment = VerticalAlignment.Top,
TextWrapping = TextWrapping.WrapWholeWords
};
Methods.FormatText(ref block, message.Snippet.DisplayMessage);
return block;
}
}
public string ChannelId => message.AuthorDetails.ChannelId;
public string Avatar => message.AuthorDetails.ProfileImageUrl;
public Visibility IsVerified => message.AuthorDetails.IsVerified.Value ? Visibility.Visible : Visibility.Collapsed;
public Visibility IsOwner => message.AuthorDetails.IsChatOwner.Value ? Visibility.Visible : Visibility.Collapsed;
public Visibility IsSponsor => message.AuthorDetails.IsChatSponsor.Value ? Visibility.Visible : Visibility.Collapsed;
public Visibility IsModerator => message.AuthorDetails.IsChatModerator.Value ? Visibility.Visible : Visibility.Collapsed;
public Brush Background
{
get
{
if (IsVerified == Visibility.Visible || IsOwner == Visibility.Visible || IsSponsor == Visibility.Visible || IsModerator == Visibility.Visible)
return new SolidColorBrush() { Color = Colors.Red, Opacity = .2 };
else
return new SolidColorBrush();
}
}
public Thickness BorderThickness
{
get
{
if (IsVerified == Visibility.Visible || IsOwner == Visibility.Visible || IsSponsor == Visibility.Visible || IsModerator == Visibility.Visible)
return new Thickness(2);
else
return new Thickness(0);
}
}
private LiveChatMessage message;
public ChatMessage(LiveChatMessage item)
{
message = item;
}
}
public sealed partial class Chat : UserControl
{
string chatId;
DateTime lastInsert;
DispatcherTimer timer = new DispatcherTimer()
{
Interval = TimeSpan.FromSeconds(1)
};
public Chat(string id)
{
InitializeComponent();
if (!SecretsVault.IsAuthorized)
inputField.Visibility = Visibility.Collapsed;
chatId = id;
timer.Tick += Update;
timer.Start();
}
public async void Update(object sender, object e)
{
LiveChatMessagesResource.ListRequest request = SecretsVault.Service.LiveChatMessages.List(chatId, "snippet,authorDetails");
LiveChatMessageListResponse response = await request.ExecuteAsync();
foreach (LiveChatMessage i in response.Items)
if(i.Snippet.PublishedAt >= lastInsert)
list.Items.Insert(0, new ChatMessage(i));
lastInsert = DateTime.Now;
timer.Interval = TimeSpan.FromMilliseconds(response.PollingIntervalMillis.Value);
timer.Start();
}
private void HyperlinkButton_Click(object sender, RoutedEventArgs e)
{
Methods.MainPage.GoToChannel(((HyperlinkButton)sender).Tag as string);
}
private async void send_Click(object sender, RoutedEventArgs e)
{
try
{
newMessage.IsEnabled = false;
send.IsEnabled = false;
if (string.IsNullOrWhiteSpace(newMessage.Text))
return;
LiveChatMessage message = new LiveChatMessage()
{
Snippet = new LiveChatMessageSnippet()
{
Type = "textMessageEvent",
LiveChatId = chatId,
TextMessageDetails = new LiveChatTextMessageDetails()
{
MessageText = newMessage.Text
}
}
};
LiveChatMessagesResource.InsertRequest request = SecretsVault.Service.LiveChatMessages.Insert(message, "snippet,authorDetails");
LiveChatMessage response = await request.ExecuteAsync();
if(response != null)
{
newMessage.Text = string.Empty;
list.Items.Add(new ChatMessage(response));
}
}
finally
{
newMessage.IsEnabled = true;
send.IsEnabled = true;
}
}
}
}
+6 -7
View File
@@ -2,10 +2,8 @@
x:Class="FoxTube.Controls.CommentCard" x:Class="FoxTube.Controls.CommentCard"
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:local="using:FoxTube.Controls"
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"
mc:Ignorable="d" mc:Ignorable="d"
d:DesignWidth="400"> d:DesignWidth="400">
@@ -38,8 +36,9 @@
<StackPanel Grid.Row="2" Name="editor" Visibility="Collapsed"> <StackPanel Grid.Row="2" Name="editor" Visibility="Collapsed">
<TextBox Name="editorText" Text="[Content]" AcceptsReturn="True" TextWrapping="Wrap" TextChanged="editorText_TextChanged"/> <TextBox Name="editorText" Text="[Content]" AcceptsReturn="True" TextWrapping="Wrap" TextChanged="editorText_TextChanged"/>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,5,0,5"> <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,5,0,5">
<Button Name="editorClose" Content="Cancel" Click="editorClose_Click"/> <Button x:Uid="/CommentsPage/editorDelete" Content="Delete comment" Background="Red" Name="deleteComment" Click="DeleteComment_Click"/>
<Button Name="editorSend" Content="Submit" Margin="5,0,0,0" Click="editorSend_Click"/> <Button x:Uid="/CommentsPage/editorCancel" Name="editorClose" Content="Cancel" Click="editorClose_Click" Margin="5, 0"/>
<Button x:Uid="/CommentsPage/editorSubmit" Name="editorSend" Content="Submit" Click="editorSend_Click"/>
</StackPanel> </StackPanel>
<ProgressBar Name="editorSending" Foreground="Red" IsIndeterminate="True" Visibility="Collapsed"/> <ProgressBar Name="editorSending" Foreground="Red" IsIndeterminate="True" Visibility="Collapsed"/>
</StackPanel> </StackPanel>
@@ -69,7 +68,7 @@
Height="35"> Height="35">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<TextBlock FontFamily="Segoe MDL2 Assets" Text="&#xEE35;" FontSize="20"/> <TextBlock FontFamily="Segoe MDL2 Assets" Text="&#xEE35;" FontSize="20"/>
<TextBlock Text="Reply"/> <TextBlock x:Uid="/CommentsPage/reply" Text="Reply"/>
</StackPanel> </StackPanel>
</Button> </Button>
@@ -78,7 +77,7 @@
Height="35"> Height="35">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<TextBlock FontFamily="Segoe MDL2 Assets" Text="&#xE104;" FontSize="20"/> <TextBlock FontFamily="Segoe MDL2 Assets" Text="&#xE104;" FontSize="20"/>
<TextBlock Text="Edit"/> <TextBlock x:Uid="/CommentsPage/edit" Text="Edit"/>
</StackPanel> </StackPanel>
</Button> </Button>
</StackPanel> </StackPanel>
@@ -86,7 +85,7 @@
</Grid> </Grid>
</Grid> </Grid>
<TextBox Grid.Row="1" Name="reply" TextChanged="reply_TextChanged" TextWrapping="Wrap" BorderThickness="0" Background="{ThemeResource SystemControlBackgroundChromeMediumLowBrush}" AcceptsReturn="True" MaxLength="500" <TextBox x:Uid="/CommentsPage/replyBox" Grid.Row="1" Name="reply" TextChanged="reply_TextChanged" TextWrapping="Wrap" BorderThickness="0" Background="{ThemeResource SystemControlBackgroundChromeMediumLowBrush}" AcceptsReturn="True" MaxLength="500"
Padding="5" Margin="0,0,32,0" Padding="5" Margin="0,0,32,0"
PlaceholderText="Enter your reply..."/> PlaceholderText="Enter your reply..."/>
<Button Grid.Row="1" Name="send" Click="send_Click" IsEnabled="False" HorizontalAlignment="Right" VerticalAlignment="Top" <Button Grid.Row="1" Name="send" Click="send_Click" IsEnabled="False" HorizontalAlignment="Right" VerticalAlignment="Top"
+32 -16
View File
@@ -1,31 +1,26 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Linq; 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.Data;
using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using Google.Apis.YouTube.v3; using Google.Apis.YouTube.v3;
using Google.Apis.YouTube.v3.Data; using Google.Apis.YouTube.v3.Data;
using Windows.UI.Xaml.Media.Imaging; using Windows.UI.Xaml.Media.Imaging;
using Windows.System;
using Windows.UI.Popups; using Windows.UI.Popups;
using Windows.ApplicationModel.Resources;
// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236
namespace FoxTube.Controls namespace FoxTube.Controls
{ {
public enum CommentType { TopLevel, Reply } public enum CommentType { TopLevel, Reply }
/// <summary>
/// Control represents video comment entity
/// </summary>
public sealed partial class CommentCard : UserControl public sealed partial class CommentCard : UserControl
{ {
ResourceLoader resources = ResourceLoader.GetForCurrentView("CommentsPage");
Comment item; Comment item;
CommentThread thread; CommentThread thread;
bool repliesLoaded = false; bool repliesLoaded = false;
@@ -33,7 +28,7 @@ namespace FoxTube.Controls
public CommentCard(CommentThread comment) public CommentCard(CommentThread comment)
{ {
this.InitializeComponent(); InitializeComponent();
Initialize(comment); Initialize(comment);
} }
@@ -72,7 +67,7 @@ namespace FoxTube.Controls
else else
author.Text = comment.Snippet.TopLevelComment.Snippet.AuthorDisplayName; author.Text = comment.Snippet.TopLevelComment.Snippet.AuthorDisplayName;
meta.Text = string.Format("{0} {1}", Methods.GetAgo(comment.Snippet.TopLevelComment.Snippet.PublishedAt.Value), comment.Snippet.TopLevelComment.Snippet.UpdatedAt != comment.Snippet.TopLevelComment.Snippet.PublishedAt ? "(edited)" : ""); meta.Text = string.Format("{0} {1}", Methods.GetAgo(comment.Snippet.TopLevelComment.Snippet.PublishedAt.Value), comment.Snippet.TopLevelComment.Snippet.UpdatedAt != comment.Snippet.TopLevelComment.Snippet.PublishedAt ? resources.GetString("/CommentsPage/edited") : "");
Methods.FormatText(ref text, comment.Snippet.TopLevelComment.Snippet.TextDisplay); Methods.FormatText(ref text, comment.Snippet.TopLevelComment.Snippet.TextDisplay);
try { avatar.ProfilePicture = new BitmapImage(new Uri(comment.Snippet.TopLevelComment.Snippet.AuthorProfileImageUrl)); } try { avatar.ProfilePicture = new BitmapImage(new Uri(comment.Snippet.TopLevelComment.Snippet.AuthorProfileImageUrl)); }
@@ -118,7 +113,7 @@ namespace FoxTube.Controls
else else
author.Text = comment.Snippet.AuthorDisplayName; author.Text = comment.Snippet.AuthorDisplayName;
meta.Text = string.Format("{0} {1}", comment.Snippet.AuthorDisplayName, Methods.GetAgo(comment.Snippet.PublishedAt.Value), comment.Snippet.UpdatedAt.Value != comment.Snippet.PublishedAt.Value ? "(edited)" : ""); meta.Text = string.Format("{0} {1}", Methods.GetAgo(comment.Snippet.PublishedAt.Value), comment.Snippet.UpdatedAt != comment.Snippet.PublishedAt ? resources.GetString("/CommentsPage/edited") : "");
Methods.FormatText(ref text, comment.Snippet.TextDisplay); Methods.FormatText(ref text, comment.Snippet.TextDisplay);
try { avatar.ProfilePicture = new BitmapImage(new Uri(comment.Snippet.AuthorProfileImageUrl)); } try { avatar.ProfilePicture = new BitmapImage(new Uri(comment.Snippet.AuthorProfileImageUrl)); }
@@ -209,7 +204,7 @@ namespace FoxTube.Controls
} }
catch catch
{ {
await new MessageDialog("Failed to send your reply. Please, try again later.", "Failed to send your reply").ShowAsync(); await new MessageDialog(resources.GetString("/CommentsPage/failedReply")).ShowAsync();
} }
send.IsEnabled = true; send.IsEnabled = true;
reply.IsEnabled = true; reply.IsEnabled = true;
@@ -251,7 +246,7 @@ namespace FoxTube.Controls
} }
catch catch
{ {
await new MessageDialog("Failed to edit your commentary. Please, try again later.", "Failed to edit your commentary").ShowAsync(); await new MessageDialog(resources.GetString("/CommentsPage/failedEdit")).ShowAsync();
} }
editorText.IsEnabled = true; editorText.IsEnabled = true;
@@ -274,5 +269,26 @@ namespace FoxTube.Controls
editorText.Text = text.Text; editorText.Text = text.Text;
editor.Visibility = Visibility.Visible; editor.Visibility = Visibility.Visible;
} }
private async void DeleteComment_Click(object sender, RoutedEventArgs e)
{
MessageDialog dialog = new MessageDialog(resources.GetString("/CommentsPage/deleteContent"), resources.GetString("/CommentsPage/deleteHeader"));
dialog.Commands.Add(new UICommand(resources.GetString("/CommentsPage/yes"), async (command) =>
{
try
{
await SecretsVault.Service.Comments.Delete(item.Id).ExecuteAsync();
Methods.CommentsPage.RemoveComment(this);
}
catch { }
}));
dialog.Commands.Add(new UICommand(resources.GetString("/CommentsPage/no")));
dialog.CancelCommandIndex = 1;
dialog.DefaultCommandIndex = 0;
await dialog.ShowAsync();
}
} }
} }
+3 -3
View File
@@ -33,13 +33,13 @@
<Button Name="open" Click="open_Click" Width="80" Height="80" Padding="0" Background="Transparent"> <Button Name="open" Click="open_Click" Width="80" Height="80" Padding="0" Background="Transparent">
<StackPanel> <StackPanel>
<TextBlock Text="&#xED25;" FontFamily="Segoe MDL2 Assets" FontSize="30" HorizontalAlignment="Center"/> <TextBlock Text="&#xED25;" FontFamily="Segoe MDL2 Assets" FontSize="30" HorizontalAlignment="Center"/>
<TextBlock Text="Open" TextWrapping="WrapWholeWords" HorizontalTextAlignment="Center"/> <TextBlock x:Uid="/Downloads/openFile" Text="Open" TextWrapping="WrapWholeWords" HorizontalTextAlignment="Center"/>
</StackPanel> </StackPanel>
</Button> </Button>
<Button Name="gotoOriginal" Click="gotoOriginal_Click" Width="80" Height="80" Padding="0" Background="Transparent"> <Button Name="gotoOriginal" Click="gotoOriginal_Click" Width="80" Height="80" Padding="0" Background="Transparent">
<StackPanel> <StackPanel>
<TextBlock Text="&#xE2B4;" FontFamily="Segoe MDL2 Assets" FontSize="30" HorizontalAlignment="Center"/> <TextBlock Text="&#xE2B4;" FontFamily="Segoe MDL2 Assets" FontSize="30" HorizontalAlignment="Center"/>
<TextBlock Text="Go to original" TextWrapping="WrapWholeWords" HorizontalTextAlignment="Center" HorizontalAlignment="Center"/> <TextBlock x:Uid="/Downloads/gotoOrign" Text="Go to original" TextWrapping="WrapWholeWords" HorizontalTextAlignment="Center" HorizontalAlignment="Center"/>
</StackPanel> </StackPanel>
</Button> </Button>
</StackPanel> </StackPanel>
@@ -47,7 +47,7 @@
<TextBlock Name="status" Text="Downloading..." HorizontalAlignment="Left"/> <TextBlock Name="status" Text="Downloading..." HorizontalAlignment="Left"/>
<ProgressBar Name="progressBar" Width="200" Maximum="1" IsIndeterminate="True" Foreground="Red"/> <ProgressBar Name="progressBar" Width="200" Maximum="1" IsIndeterminate="True" Foreground="Red"/>
<TextBlock Name="perc" Text="--%"/> <TextBlock Name="perc" Text="--%"/>
<Button Content="Cancel" Name="cancel" Click="CancelPrompt" HorizontalAlignment="Right"/> <Button x:Uid="/Downloads/cancel" Content="Cancel" Name="cancel" Click="CancelPrompt" HorizontalAlignment="Right"/>
</StackPanel> </StackPanel>
</Grid> </Grid>
</UserControl> </UserControl>
+21 -18
View File
@@ -15,11 +15,14 @@ using Windows.UI.Popups;
using Windows.UI.Notifications; using Windows.UI.Notifications;
using Microsoft.Toolkit.Uwp.Notifications; using Microsoft.Toolkit.Uwp.Notifications;
using System.Threading.Tasks; using System.Threading.Tasks;
using Windows.ApplicationModel.Resources;
namespace FoxTube.Controls namespace FoxTube.Controls
{ {
public sealed partial class DownloadItem : UserControl public sealed partial class DownloadItem : UserControl
{ {
ResourceLoader resources = ResourceLoader.GetForCurrentView("Downloads");
public DownloadItemContainer Container { get; private set; } public DownloadItemContainer Container { get; private set; }
public StorageFile file; public StorageFile file;
public bool InProgress { get; set; } = false; public bool InProgress { get; set; } = false;
@@ -62,10 +65,10 @@ namespace FoxTube.Controls
title.Text = Container.Title; title.Text = Container.Title;
path.Text = file.Name; path.Text = file.Name;
thumbnail.Source = new BitmapImage(Container.Thumbnail); thumbnail.Source = new BitmapImage(Container.Thumbnail);
quality.Text = $"Quality: {Container.Quality}"; quality.Text = $"{resources.GetString("/Downloads/quality")}: {Container.Quality}";
duration.Text = $"Duration: {Container.Duration}"; duration.Text = $"{resources.GetString("/Downloads/duration")}: {Container.Duration}";
channel.Text = $"Author: {Container.Channel}"; channel.Text = $"{resources.GetString("/Downloads/author")}: {Container.Channel}";
ext.Text = $"Extension: {Container.Extension}"; ext.Text = $"{resources.GetString("/Downloads/ext")}: {Container.Extension}";
progressPanel.Visibility = Visibility.Collapsed; progressPanel.Visibility = Visibility.Collapsed;
donePanel.Visibility = Visibility.Visible; donePanel.Visibility = Visibility.Visible;
@@ -93,11 +96,11 @@ namespace FoxTube.Controls
{ {
Children = Children =
{ {
new AdaptiveText() { Text = "Downloading a video" }, new AdaptiveText() { Text = resources.GetString("/Downloads/toastStartHeader") },
new AdaptiveProgressBar() new AdaptiveProgressBar()
{ {
Title = meta.Snippet.Title, Title = meta.Snippet.Title,
Status = "Downloading...", Status = resources.GetString("/Downloads/downloading/Text"),
Value = new BindableProgressBarValue("value") Value = new BindableProgressBarValue("value")
} }
} }
@@ -108,7 +111,7 @@ namespace FoxTube.Controls
{ {
Buttons = Buttons =
{ {
new ToastButton("Cancel", $"dcancel|{Container.Id}") new ToastButton(resources.GetString("/Downloads/cancel/Content"), $"dcancel|{Container.Id}")
{ {
ActivationType = ToastActivationType.Background ActivationType = ToastActivationType.Background
} }
@@ -131,10 +134,10 @@ namespace FoxTube.Controls
thumbnail.Source = new BitmapImage(new Uri(meta.Snippet.Thumbnails.Medium.Url)); thumbnail.Source = new BitmapImage(new Uri(meta.Snippet.Thumbnails.Medium.Url));
title.Text = meta.Snippet.Title; title.Text = meta.Snippet.Title;
ext.Text = $"Extension: {info.Container.GetFileExtension()}"; ext.Text = $"{resources.GetString("/Downloads/ext")}: {info.Container.GetFileExtension()}";
quality.Text = $"Quality: {q}"; quality.Text = $"{resources.GetString("/Downloads/quality")}: {q}";
duration.Text = $"Duration: {XmlConvert.ToTimeSpan(meta.ContentDetails.Duration)}"; duration.Text = $"{resources.GetString("/Downloads/duration")}: {XmlConvert.ToTimeSpan(meta.ContentDetails.Duration)}";
channel.Text = $"Author: {meta.Snippet.ChannelTitle}"; channel.Text = $"{resources.GetString("/Downloads/author")}: {meta.Snippet.ChannelTitle}";
path.Text = file.Name; path.Text = file.Name;
progressPanel.Visibility = Visibility.Visible; progressPanel.Visibility = Visibility.Visible;
@@ -170,13 +173,13 @@ namespace FoxTube.Controls
template.LoadXml($@"<toast activationType='background' launch='download|{file.Path}'> template.LoadXml($@"<toast activationType='background' launch='download|{file.Path}'>
<visual> <visual>
<binding template='ToastGeneric'> <binding template='ToastGeneric'>
<text>Download complete</text> <text>{resources.GetString("/Downloads/toastCompleteHeader")}</text>
<text>{Container.Title}</text> <text>{Container.Title}</text>
</binding> </binding>
</visual> </visual>
<actions> <actions>
<action content='Go to original' <action content='{resources.GetString("/Downloads/gotoOrign/Text")}'
activationType='foreground' activationType='foreground'
arguments='video|{Container.Id}'/> arguments='video|{Container.Id}'/>
</actions> </actions>
@@ -196,7 +199,7 @@ namespace FoxTube.Controls
public async void Cancel() public async void Cancel()
{ {
status.Text = "Cancelling..."; status.Text = resources.GetString("/Downloads/cancelling");
progressBar.IsIndeterminate = true; progressBar.IsIndeterminate = true;
cancel.IsEnabled = false; cancel.IsEnabled = false;
cts.Cancel(); cts.Cancel();
@@ -210,7 +213,7 @@ namespace FoxTube.Controls
template.LoadXml($@"<toast activationType='foreground' launch='download'> template.LoadXml($@"<toast activationType='foreground' launch='download'>
<visual> <visual>
<binding template='ToastGeneric'> <binding template='ToastGeneric'>
<text>Download canceled</text> <text>{resources.GetString("/Downloads/toastCanceledHeader")}</text>
<text>{Container.Title}</text> <text>{Container.Title}</text>
</binding> </binding>
</visual> </visual>
@@ -224,10 +227,10 @@ namespace FoxTube.Controls
{ {
if(InProgress) if(InProgress)
{ {
MessageDialog dialog = new MessageDialog("Are you sure?", "Cancelling download"); MessageDialog dialog = new MessageDialog(resources.GetString("/Downloads/prompt"), resources.GetString("/Downloads/cancellingHeader"));
dialog.Commands.Add(new UICommand("Yes", (command) => Cancel())); dialog.Commands.Add(new UICommand(resources.GetString("/Downloads/yes"), (command) => Cancel()));
dialog.Commands.Add(new UICommand("No")); dialog.Commands.Add(new UICommand(resources.GetString("/Downloads/no")));
dialog.DefaultCommandIndex = 1; dialog.DefaultCommandIndex = 1;
await dialog.ShowAsync(); await dialog.ShowAsync();
+26 -39
View File
@@ -1,36 +1,32 @@
using FoxTube.Classes; using System;
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.Media;
using Windows.UI.Xaml.Data; using YoutubeExplode.Models.ClosedCaptions;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using System.Xml;
using System.Diagnostics;
// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236
namespace FoxTube.Controls namespace FoxTube.Controls
{ {
/// <summary>
/// Control for displaying closed captions
/// </summary>
public sealed partial class LiveCaptions : UserControl public sealed partial class LiveCaptions : UserControl
{ {
public MediaElement Player { get; set; } public double Size
{
get => text.FontSize;
set => text.FontSize = value;
}
public MediaTimelineController Player { get; set; }
private bool isClosed = false; private bool isClosed = false;
DispatcherTimer timer = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(10) }; DispatcherTimer timer = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(10) };
List<Caption> captions = new List<Caption>(); ClosedCaption currentCaption = null;
Caption currentCaption = null;
ClosedCaptionTrack track = null;
public LiveCaptions() public LiveCaptions()
{ {
this.InitializeComponent(); InitializeComponent();
timer.Tick += UpdateCaption; timer.Tick += UpdateCaption;
} }
@@ -40,11 +36,11 @@ namespace FoxTube.Controls
bool found = false; bool found = false;
if(!isClosed) if(!isClosed)
captions.ForEach((x) => track.Captions.ForEach(i =>
{ {
if (Player.Position >= x.Start && Player.Position <= x.End) if (Player.Position >= i.Offset && Player.Position <= i.Offset + i.Duration)
{ {
currentCaption = x; currentCaption = i;
text.Text = currentCaption.Text; text.Text = currentCaption.Text;
Visibility = Visibility.Visible; Visibility = Visibility.Visible;
found = true; found = true;
@@ -58,24 +54,15 @@ namespace FoxTube.Controls
} }
} }
public void Initialize(string source, bool isAutoGenerated = false) public async void Initialize(ClosedCaptionTrackInfo info)
{ {
captions.Clear(); track = await new YoutubeExplode.YoutubeClient().GetClosedCaptionTrackAsync(info);
XmlDocument doc = new XmlDocument();
doc.Load(source);
if (!isAutoGenerated) track.Captions.ForEach(i =>
foreach (XmlElement i in doc["timedtext"]["body"].ChildNodes)
captions.Add(new Caption(int.Parse(i.GetAttribute("t")), int.Parse(i.GetAttribute("d")), i.InnerText));
else
foreach (XmlElement i in doc["transcript"].ChildNodes)
captions.Add(new Caption(double.Parse(i.GetAttribute("start")), double.Parse(i.GetAttribute("dur")), i.InnerText.Replace("<font color=\"#E5E5E5\">", "").Replace("<font color=\"#CCCCCC\">", "").Replace("</font>", "").Replace("&#39;", "'")));
captions.ForEach((x) =>
{ {
if (Player.Position > x.Start && Player.Position < x.End) if (Player.Position > i.Offset && Player.Position < i.Offset + i.Duration)
{ {
currentCaption = x; currentCaption = i;
text.Text = currentCaption.Text; text.Text = currentCaption.Text;
Visibility = Visibility.Visible; Visibility = Visibility.Visible;
} }
@@ -86,7 +73,7 @@ namespace FoxTube.Controls
public void Close() public void Close()
{ {
captions.Clear(); track = null;
currentCaption = null; currentCaption = null;
Visibility = Visibility.Collapsed; Visibility = Visibility.Collapsed;
timer.Stop(); timer.Stop();
+12 -2
View File
@@ -41,11 +41,21 @@
<Ellipse Grid.Column="0" Height="50" Width="50" Margin="5,-30,5,10" Fill="{ThemeResource SystemControlBackgroundChromeMediumBrush}"/> <Ellipse Grid.Column="0" Height="50" Width="50" Margin="5,-30,5,10" Fill="{ThemeResource SystemControlBackgroundChromeMediumBrush}"/>
<PersonPicture Name="avatar" Grid.Column="0" Height="46" Margin="5,-30,5,0" BorderBrush="White" BorderThickness="10"/> <PersonPicture Name="avatar" Grid.Column="0" Height="46" Margin="5,-30,5,0" BorderBrush="White" BorderThickness="10"/>
<TextBlock Name="channelName" Grid.Column="1" Text="[Channel name]" Foreground="Gray" Margin="0,2,0,0" FontSize="12"/> <TextBlock HorizontalAlignment="Left" MaxWidth="200" TextTrimming="CharacterEllipsis" Name="channelName" Grid.Column="1" Text="[Channel name]" Foreground="Gray" Margin="0,2,0,0" FontSize="12"/>
<TextBlock Grid.Column="1" Name="date" Text="[Published at]" HorizontalAlignment="Right" Foreground="Gray" Margin="0,2,2,0" FontSize="12"/> <TextBlock Grid.Column="1" Name="date" Text="[Published at]" HorizontalAlignment="Right" Foreground="Gray" Margin="0,2,2,0" FontSize="12"/>
</Grid> </Grid>
<TextBlock Grid.Row="1" Name="title" Text="[Title]" TextWrapping="WrapWholeWords" Margin="5" MaxLines="2"/> <TextBlock Grid.Row="1" Name="title" Text="[Title]" TextWrapping="WrapWholeWords" TextTrimming="CharacterEllipsis" Margin="5" MaxLines="2"/>
</Grid> </Grid>
</Grid> </Grid>
</Button> </Button>
<UserControl.ContextFlyout>
<MenuFlyout>
<MenuFlyoutItem x:Uid="/Cards/playlist" Icon="List" Text="View playlist" Click="Button_Click"/>
<MenuFlyoutItem x:Uid="/Cards/channel" Icon="Contact" Text="View channel" Name="openChannel" Click="OpenChannel_Click"/>
<MenuFlyoutSeparator/>
<MenuFlyoutItem x:Uid="/Cards/getLink" Icon="Link" Text="Copy link" Name="getLink" Click="GetLink_Click"/>
<MenuFlyoutItem x:Uid="/Cards/openWeb" Icon="Globe" Text="Open in browser" Name="inBrowser" Click="InBrowser_Click"/>
<MenuFlyoutItem x:Uid="/Cards/share" Icon="Share" Text="Share" Name="share" Visibility="Collapsed"/>
</MenuFlyout>
</UserControl.ContextFlyout>
</Page> </Page>
+20 -1
View File
@@ -1,6 +1,8 @@
using Google.Apis.YouTube.v3; using Google.Apis.YouTube.v3;
using Google.Apis.YouTube.v3.Data; using Google.Apis.YouTube.v3.Data;
using System; using System;
using Windows.ApplicationModel.DataTransfer;
using Windows.System;
using Windows.UI.Xaml; using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media.Imaging; using Windows.UI.Xaml.Media.Imaging;
@@ -40,7 +42,7 @@ namespace FoxTube.Controls
try try
{ {
thumbnail.Source = new BitmapImage(new Uri(item.Snippet.Thumbnails.Medium.Url)); thumbnail.Source = new BitmapImage((item.Snippet.Thumbnails.Maxres ?? item.Snippet.Thumbnails.Medium).Url.ToUri());
avatar.ProfilePicture = new BitmapImage(new Uri((await r.ExecuteAsync()).Items[0].Snippet.Thumbnails.Medium.Url)); avatar.ProfilePicture = new BitmapImage(new Uri((await r.ExecuteAsync()).Items[0].Snippet.Thumbnails.Medium.Url));
} catch { } } catch { }
} }
@@ -54,5 +56,22 @@ namespace FoxTube.Controls
{ {
Methods.MainPage.GoToPlaylist(item.Id); Methods.MainPage.GoToPlaylist(item.Id);
} }
private void OpenChannel_Click(object sender, RoutedEventArgs e)
{
Methods.MainPage.GoToChannel(item.Snippet.ChannelId);
}
private void GetLink_Click(object sender, RoutedEventArgs e)
{
DataPackage data = new DataPackage();
data.SetText($"https://www.youtube.com/playlist?list={playlistId}");
Clipboard.SetContent(data);
}
private async void InBrowser_Click(object sender, RoutedEventArgs e)
{
await Launcher.LaunchUriAsync($"https://www.youtube.com/playlist?list={playlistId}".ToUri());
}
} }
} }
+1 -1
View File
@@ -8,7 +8,7 @@
mc:Ignorable="d"> mc:Ignorable="d">
<Grid> <Grid>
<HyperlinkButton Foreground="Red" HorizontalAlignment="Center" Content="Show more" Name="btn" Click="btn_Click"/> <HyperlinkButton x:Uid="/Cards/more" Foreground="Red" HorizontalAlignment="Center" Content="Show more" Name="btn" Click="btn_Click"/>
<ProgressBar Name="bar" IsIndeterminate="True" Foreground="Red" Visibility="Collapsed"/> <ProgressBar Name="bar" IsIndeterminate="True" Foreground="Red" Visibility="Collapsed"/>
</Grid> </Grid>
</UserControl> </UserControl>
+16 -10
View File
@@ -20,7 +20,7 @@
<Image Name="thumbnail" Source="/Assets/videoThumbSample.png" Stretch="Fill"/> <Image Name="thumbnail" Source="/Assets/videoThumbSample.png" Stretch="Fill"/>
<Grid Background="#7F000000" Name="watched" Visibility="Collapsed"> <Grid Background="#7F000000" Name="watched" Visibility="Collapsed">
<StackPanel Margin="5" Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}" VerticalAlignment="Top" HorizontalAlignment="Left" Padding="5,2,5,2" BorderBrush="Gray" BorderThickness="1"> <StackPanel Margin="5" Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}" VerticalAlignment="Top" HorizontalAlignment="Left" Padding="5,2,5,2" BorderBrush="Gray" BorderThickness="1">
<TextBlock Text="Watched" Foreground="Gray" FontSize="12"/> <TextBlock x:Uid="/Cards/watched" Text="Watched" Foreground="Gray" FontSize="12"/>
</StackPanel> </StackPanel>
<ProgressBar VerticalAlignment="Bottom" Margin="54,0,0,0" Foreground="Red" Name="leftOn"/> <ProgressBar VerticalAlignment="Bottom" Margin="54,0,0,0" Foreground="Red" Name="leftOn"/>
</Grid> </Grid>
@@ -29,7 +29,7 @@
</StackPanel> </StackPanel>
<StackPanel Name="liveTag" Margin="0,0,5,30" Background="Red" BorderBrush="White" BorderThickness="1" VerticalAlignment="Bottom" HorizontalAlignment="Right" Padding="5,2,5,3" Orientation="Horizontal" Visibility="Collapsed"> <StackPanel Name="liveTag" Margin="0,0,5,30" Background="Red" BorderBrush="White" BorderThickness="1" VerticalAlignment="Bottom" HorizontalAlignment="Right" Padding="5,2,5,3" Orientation="Horizontal" Visibility="Collapsed">
<TextBlock Text="&#xEC44; " VerticalAlignment="Center" Foreground="White" FontSize="12" FontFamily="Segoe MDL2 Assets" FontWeight="Black"/> <TextBlock Text="&#xEC44; " VerticalAlignment="Center" Foreground="White" FontSize="12" FontFamily="Segoe MDL2 Assets" FontWeight="Black"/>
<TextBlock Name="liveContent" Text="LIVE" VerticalAlignment="Center" Foreground="White" FontSize="12" FontWeight="Bold"/> <TextBlock x:Uid="/Cards/live" Name="liveContent" Text="LIVE" VerticalAlignment="Center" Foreground="White" FontSize="12" FontWeight="Bold"/>
</StackPanel> </StackPanel>
<Grid Grid.Row="1"> <Grid Grid.Row="1">
<Grid.RowDefinitions> <Grid.RowDefinitions>
@@ -44,22 +44,28 @@
<Ellipse Grid.Column="0" Height="50" Width="50" Margin="5,-30,5,10" Fill="{ThemeResource SystemControlBackgroundChromeMediumBrush}"/> <Ellipse Grid.Column="0" Height="50" Width="50" Margin="5,-30,5,10" Fill="{ThemeResource SystemControlBackgroundChromeMediumBrush}"/>
<PersonPicture Name="avatar" Grid.Column="0" Height="46" Margin="5,-30,5,0" BorderBrush="White" BorderThickness="10"/> <PersonPicture Name="avatar" Grid.Column="0" Height="46" Margin="5,-30,5,0" BorderBrush="White" BorderThickness="10"/>
<TextBlock Name="channelName" Grid.Column="1" Text="[Channel name]" Foreground="Gray" Margin="0,2,0,0" FontSize="12"/> <TextBlock MaxWidth="200" Name="channelName" HorizontalAlignment="Left" Grid.Column="1" Text="[Channel name]" TextTrimming="CharacterEllipsis" Foreground="Gray" Margin="0,2,0,0" FontSize="12"/>
<TextBlock Grid.Column="1" Name="views" Text="[Views]" HorizontalAlignment="Right" Foreground="Gray" Margin="0,2,2,0" FontSize="12"/> <TextBlock Grid.Column="1" Name="views" Text="[Views]" HorizontalAlignment="Right" Foreground="Gray" Margin="0,2,2,0" FontSize="12"/>
</Grid> </Grid>
<TextBlock Grid.Row="1" Name="title" Text="[Title]" TextWrapping="WrapWholeWords" Margin="5" MaxLines="2"/> <TextBlock Grid.Row="1" Name="title" Text="[Title]" TextWrapping="WrapWholeWords" Margin="5" MaxLines="2" TextTrimming="CharacterEllipsis"/>
</Grid> </Grid>
</Grid> </Grid>
</Button> </Button>
<UserControl.ContextFlyout> <UserControl.ContextFlyout>
<MenuFlyout> <MenuFlyout>
<MenuFlyoutItem Icon="Play" Text="Play"/> <MenuFlyoutItem x:Uid="/Cards/play" Icon="Play" Text="Play" Name="play" Click="Button_Click"/>
<MenuFlyoutItem Icon="Contact" Text="View channel"/> <MenuFlyoutItem x:Uid="/Cards/incognitoPlay" Text="Play incognito" Visibility="Collapsed">
<MenuFlyoutItem.Icon>
<FontIcon Glyph="&#xE727;"/>
</MenuFlyoutItem.Icon>
</MenuFlyoutItem>
<MenuFlyoutItem x:Uid="/Cards/channel" Icon="Contact" Text="View channel" Name="viewChannel" Click="ViewChannel_Click"/>
<MenuFlyoutSeparator/> <MenuFlyoutSeparator/>
<MenuFlyoutItem Icon="Link" Text="Copy link"/> <MenuFlyoutItem x:Uid="/Cards/getLink" Icon="Link" Text="Copy link" Name="getLink" Click="GetLink_Click"/>
<MenuFlyoutItem Icon="Share" Text="Share"/> <MenuFlyoutItem x:Uid="/Cards/openWeb" Icon="Globe" Text="Open in browser" Name="inBrowser" Click="InBrowser_Click"/>
<MenuFlyoutSeparator/> <MenuFlyoutItem x:Uid="/Cards/share" Icon="Share" Text="Share" Name="share" Visibility="Collapsed"/>
<MenuFlyoutItem Icon="Download" Text="Download"/> <MenuFlyoutSeparator Visibility="Collapsed"/>
<MenuFlyoutItem Icon="Download" Text="Download" Visibility="Collapsed"/>
</MenuFlyout> </MenuFlyout>
</UserControl.ContextFlyout> </UserControl.ContextFlyout>
</UserControl> </UserControl>
+32 -26
View File
@@ -4,22 +4,26 @@ using Windows.UI.Xaml.Controls;
using Google.Apis.YouTube.v3; using Google.Apis.YouTube.v3;
using Google.Apis.YouTube.v3.Data; using Google.Apis.YouTube.v3.Data;
using Windows.UI.Xaml.Media.Imaging; using Windows.UI.Xaml.Media.Imaging;
using System.Xml;
using Windows.System; using Windows.System;
using Windows.UI.Popups; using Windows.ApplicationModel.DataTransfer;
using Windows.ApplicationModel.Resources;
namespace FoxTube.Controls namespace FoxTube.Controls
{ {
/// <summary>
/// Video item card
/// </summary>
public sealed partial class VideoCard : UserControl public sealed partial class VideoCard : UserControl
{ {
ResourceLoader resources = ResourceLoader.GetForCurrentView("Cards");
public string playlistId; public string playlistId;
public string videoId; public string videoId;
Video item; Video item;
bool embed = true;
public VideoCard(string id, string playlist = null) public VideoCard(string id, string playlist = null)
{ {
this.InitializeComponent(); InitializeComponent();
Initialize(id, playlist); Initialize(id, playlist);
} }
@@ -42,7 +46,7 @@ namespace FoxTube.Controls
channelName.Text = item.Snippet.ChannelTitle; channelName.Text = item.Snippet.ChannelTitle;
if (item.Snippet.LiveBroadcastContent == "live") if (item.Snippet.LiveBroadcastContent == "live")
{ {
views.Text = $"{item.LiveStreamingDetails.ConcurrentViewers:0,0} viewers"; views.Text = $"{item.LiveStreamingDetails.ConcurrentViewers:0,0} {resources.GetString("/Cards/viewers")}";
if (item.LiveStreamingDetails.ScheduledStartTime.HasValue && item.LiveStreamingDetails.ScheduledEndTime.HasValue) if (item.LiveStreamingDetails.ScheduledStartTime.HasValue && item.LiveStreamingDetails.ScheduledEndTime.HasValue)
info.Text = $"{item.LiveStreamingDetails.ScheduledEndTime - item.LiveStreamingDetails.ScheduledStartTime} | {Methods.GetAgo(item.LiveStreamingDetails.ActualStartTime.Value)}"; info.Text = $"{item.LiveStreamingDetails.ScheduledEndTime - item.LiveStreamingDetails.ScheduledStartTime} | {Methods.GetAgo(item.LiveStreamingDetails.ActualStartTime.Value)}";
else else
@@ -59,14 +63,13 @@ namespace FoxTube.Controls
liveTag.Visibility = Visibility.Visible; liveTag.Visibility = Visibility.Visible;
if (item.LiveStreamingDetails.ScheduledStartTime.HasValue && (item.LiveStreamingDetails.ScheduledStartTime - DateTime.Now).Value.TotalMilliseconds > 0) if (item.LiveStreamingDetails.ScheduledStartTime.HasValue && (item.LiveStreamingDetails.ScheduledStartTime - DateTime.Now).Value.TotalMilliseconds > 0)
liveContent.Text = $"Goes live in {item.LiveStreamingDetails.ScheduledStartTime}"; liveContent.Text = $"{resources.GetString("/Cards/goesLive")} {item.LiveStreamingDetails.ScheduledStartTime}";
else liveContent.Text = "Upcoming"; else liveContent.Text = resources.GetString("/Cards/upcoming");
} }
else else
{ {
views.Text = $"{item.Statistics.ViewCount:0,0} views"; views.Text = $"{item.Statistics.ViewCount:0,0} {resources.GetString("/Cards/views")}";
info.Text = $"{XmlConvert.ToTimeSpan(item.ContentDetails.Duration)} | {Methods.GetAgo(item.Snippet.PublishedAt.Value)}"; info.Text = $"{item.ContentDetails.Duration.GetDuration()} | {Methods.GetAgo(item.Snippet.PublishedAt.Value)}";
embed = false;
} }
var request1 = SecretsVault.Service.Channels.List("snippet"); var request1 = SecretsVault.Service.Channels.List("snippet");
@@ -76,7 +79,7 @@ namespace FoxTube.Controls
try try
{ {
avatar.ProfilePicture = new BitmapImage(new Uri(response1.Items[0].Snippet.Thumbnails.Medium.Url)); avatar.ProfilePicture = new BitmapImage(new Uri(response1.Items[0].Snippet.Thumbnails.Medium.Url));
thumbnail.Source = new BitmapImage(new Uri(item.Snippet.Thumbnails.Medium.Url)); thumbnail.Source = new BitmapImage(new Uri((item.Snippet.Thumbnails.Maxres ?? item.Snippet.Thumbnails.Medium).Url));
} }
catch { } catch { }
@@ -87,23 +90,26 @@ namespace FoxTube.Controls
}*/ }*/
} }
public async void Button_Click(object sender, RoutedEventArgs e) public void Button_Click(object sender, RoutedEventArgs e)
{ {
if (embed)
{
MessageDialog dialog = new MessageDialog("Unfortunately, at this stage of application development we don't support live steams. This issue will be fixed in the next update. Sorry. Would you like us to open this stream in browser?", "Open in browser");
dialog.Commands.Add(new UICommand("Yes", async (command) =>
{
await Launcher.LaunchUriAsync(new Uri($"https://www.youtube.com/watch?v={videoId}"));
}));
dialog.Commands.Add(new UICommand("No"));
dialog.DefaultCommandIndex = 0;
dialog.CancelCommandIndex = 1;
await dialog.ShowAsync();
}
else
Methods.MainPage.GoToVideo(videoId, playlistId); Methods.MainPage.GoToVideo(videoId, playlistId);
} }
private void ViewChannel_Click(object sender, RoutedEventArgs e)
{
Methods.MainPage.GoToChannel(item.Snippet.ChannelId);
}
private void GetLink_Click(object sender, RoutedEventArgs e)
{
DataPackage data = new DataPackage();
data.SetText($"https://www.youtube.com/watch?v={videoId}");
Clipboard.SetContent(data);
}
private async void InBrowser_Click(object sender, RoutedEventArgs e)
{
await Launcher.LaunchUriAsync($"https://www.youtube.com/watch?v={videoId}".ToUri());
}
} }
} }
+116 -46
View File
@@ -2,10 +2,8 @@
x:Class="FoxTube.VideoPlayer" x:Class="FoxTube.VideoPlayer"
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:local="using:FoxTube"
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:controls1="using:FoxTube.Controls" xmlns:controls1="using:FoxTube.Controls"
mc:Ignorable="d" mc:Ignorable="d"
d:DesignHeight="1080" d:DesignHeight="1080"
@@ -16,10 +14,9 @@
PointerEntered="UserControl_PointerEntered"> PointerEntered="UserControl_PointerEntered">
<Grid Background="White" Name="grid" Tapped="UserControl_Tapped"> <Grid Background="White" Name="grid" Tapped="UserControl_Tapped">
<MediaElement Width="0" Height="0" VerticalAlignment="Top" HorizontalAlignment="Right" Name="audioSource" MediaOpened="videoSource_Opened" BufferingProgressChanged="videoSource_BufferingProgressChanged"/> <MediaPlayerElement IsDoubleTapEnabled="False" Name="videoSource" AreTransportControlsEnabled="False" PosterSource="ms-appx:///Assets/videoThumbSample.png"/>
<MediaElement IsDoubleTapEnabled="False" CurrentStateChanged="videoSource_CurrentStateChanged" AutoPlay="False" MediaOpened="videoSource_Opened" BufferingProgressChanged="videoSource_BufferingProgressChanged" Volume="0" Name="videoSource" AreTransportControlsEnabled="False" PosterSource="ms-appx:///Assets/videoThumbSample.png"/> <MediaPlayerElement Name="audioSource" Width="0" Height="0" VerticalAlignment="Top" HorizontalAlignment="Left"/>
<controls1:LiveCaptions Player="{x:Bind controller}" Visibility="Collapsed"/>
<controls1:LiveCaptions Player="{x:Bind videoSource}" Visibility="Collapsed"/>
<Grid Name="controls" Visibility="Visible"> <Grid Name="controls" Visibility="Visible">
<Grid.RowDefinitions> <Grid.RowDefinitions>
@@ -27,21 +24,37 @@
<RowDefinition/> <RowDefinition/>
<RowDefinition Height="auto"/> <RowDefinition Height="auto"/>
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid Grid.Row="0" Name="header" Height="50" Background="#7F000000"> <Grid Name="header" Height="50" Background="#7F000000">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/> <ColumnDefinition Width="auto"/>
<ColumnDefinition/> <ColumnDefinition/>
<ColumnDefinition Width="auto"/> <ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Button Click="minimize_Click" Name="minimize" Background="Transparent" FontFamily="Segoe MDL2 Assets" Content="&#xE011;" Foreground="White" Width="50" Height="50" FontSize="25" ToolTipService.ToolTip="Minimize"/> <Button Click="minimize_Click" Name="minimize" Background="Transparent" FontFamily="Segoe MDL2 Assets" Content="&#xE011;" Foreground="White" Width="50" Height="50" FontSize="25">
<ToolTipService.ToolTip>
<TextBlock x:Uid="/VideoPage/minimize"/>
</ToolTipService.ToolTip>
</Button>
<StackPanel Grid.Column="1" Margin="10,0,10,0" VerticalAlignment="Center"> <StackPanel Grid.Column="1" Margin="10,0,10,0" VerticalAlignment="Center">
<TextBlock Name="title" Text="[Title]" Foreground="White" VerticalAlignment="Center" TextWrapping="WrapWholeWords" FontSize="20" MaxLines="1" ToolTipService.ToolTip="Title"/> <TextBlock Name="title" Text="[Title]" Foreground="White" VerticalAlignment="Center" TextWrapping="WrapWholeWords" FontSize="20" MaxLines="1"/>
<TextBlock Foreground="LightGray" Text="[Channel name]" Name="channelName" FontStyle="Italic"/> <TextBlock Foreground="LightGray" Text="[Channel name]" Name="channelName" FontStyle="Italic"/>
</StackPanel> </StackPanel>
<StackPanel Grid.Column="2" Orientation="Horizontal" HorizontalAlignment="Right"> <StackPanel Grid.Column="2" Orientation="Horizontal" HorizontalAlignment="Right">
<Button Name="closeHeader" Click="close_Click" Background="Transparent" FontFamily="Segoe MDL2 Assets" Content="&#xE10A;" Foreground="White" Width="50" Height="50" FontSize="25" ToolTipService.ToolTip="Close video"/> <Button Name="closeHeader" Click="close_Click" Background="Transparent" FontFamily="Segoe MDL2 Assets" Content="&#xE10A;" Foreground="White" Width="50" Height="50" FontSize="25">
<Button Name="cast" Click="cast_Click" Background="Transparent" FontFamily="Segoe MDL2 Assets" Content="&#xEC15;" Foreground="White" Width="50" Height="50" FontSize="25" ToolTipService.ToolTip="Cast to device"/> <ToolTipService.ToolTip>
<Button Name="miniViewBtn" Click="miniView_Click" Background="Transparent" FontFamily="Segoe MDL2 Assets" Content="&#xE2B3;" Foreground="White" Width="50" Height="50" FontSize="25" ToolTipService.ToolTip="Compact view mode" HorizontalAlignment="Center" Margin="0,0,0,0" VerticalAlignment="Center"/> <TextBlock x:Uid="/VideoPage/close"/>
</ToolTipService.ToolTip>
</Button>
<Button Name="cast" Click="cast_Click" Background="Transparent" FontFamily="Segoe MDL2 Assets" Content="&#xEC15;" Foreground="White" Width="50" Height="50" FontSize="25">
<ToolTipService.ToolTip>
<TextBlock x:Uid="/VideoPage/cast"/>
</ToolTipService.ToolTip>
</Button>
<Button Name="miniViewBtn" Click="miniView_Click" Background="Transparent" FontFamily="Segoe MDL2 Assets" Content="&#xE2B3;" Foreground="White" Width="50" Height="50" FontSize="25" HorizontalAlignment="Center" Margin="0,0,0,0" VerticalAlignment="Center">
<ToolTipService.ToolTip>
<TextBlock x:Uid="/VideoPage/miniview"/>
</ToolTipService.ToolTip>
</Button>
</StackPanel> </StackPanel>
</Grid> </Grid>
@@ -53,27 +66,43 @@
<Button VerticalAlignment="Center" Content="&#xE102;" FontFamily="Segoe MDL2 Assets" Background="Transparent" FontSize="100" Foreground="WhiteSmoke" Name="touchPlay" Click="play_Click"/> <Button VerticalAlignment="Center" Content="&#xE102;" FontFamily="Segoe MDL2 Assets" Background="Transparent" FontSize="100" Foreground="WhiteSmoke" Name="touchPlay" Click="play_Click"/>
<Button VerticalAlignment="Center" Content="&#xED3D;" FontFamily="Segoe MDL2 Assets" Background="Transparent" FontSize="40" Foreground="WhiteSmoke" Name="touchFwd30" Click="fwd30_Click"/> <Button VerticalAlignment="Center" Content="&#xED3D;" FontFamily="Segoe MDL2 Assets" Background="Transparent" FontSize="40" Foreground="WhiteSmoke" Name="touchFwd30" Click="fwd30_Click"/>
</StackPanel> </StackPanel>
<Button Visibility="Collapsed" Margin="0,32,0,0" VerticalAlignment="Top" HorizontalAlignment="Right" Name="miniViewExit" Grid.Row="1" Click="miniView_Click" Background="Transparent" FontFamily="Segoe MDL2 Assets" Content="&#xE2B4;" Foreground="White" Width="45" Height="45" FontSize="25" ToolTipService.ToolTip="Exit compact view mode"/> <Button Visibility="Collapsed" Margin="0,32,0,0" VerticalAlignment="Top" HorizontalAlignment="Right" Name="miniViewExit" Grid.Row="1" Click="miniView_Click" Background="Transparent" FontFamily="Segoe MDL2 Assets" Content="&#xE2B4;" Foreground="White" Width="45" Height="45" FontSize="25">
<Button Visibility="Collapsed" VerticalAlignment="Top" HorizontalAlignment="Right" Name="close" Click="close_Click" Background="Transparent" FontFamily="Segoe MDL2 Assets" Content="&#xE10A;" Foreground="White" Width="45" Height="45" FontSize="25" ToolTipService.ToolTip="Close video"/> <ToolTipService.ToolTip>
<TextBlock x:Uid="/VideoPage/exitminiview"/>
</ToolTipService.ToolTip>
</Button>
<Button Visibility="Collapsed" VerticalAlignment="Top" HorizontalAlignment="Right" Name="close" Click="close_Click" Background="Transparent" FontFamily="Segoe MDL2 Assets" Content="&#xE10A;" Foreground="White" Width="45" Height="45" FontSize="25">
<ToolTipService.ToolTip>
<TextBlock x:Uid="/VideoPage/close"/>
</ToolTipService.ToolTip>
</Button>
<Button Visibility="Collapsed" <Button Visibility="Collapsed"
VerticalAlignment="Top" HorizontalAlignment="Left" VerticalAlignment="Top" HorizontalAlignment="Left"
Name="maximize" Click="maximize_Click" Name="maximize" Click="maximize_Click"
Background="Transparent" FontFamily="Segoe MDL2 Assets" Foreground="White" FontSize="25" Background="Transparent" FontFamily="Segoe MDL2 Assets" Foreground="White" FontSize="25"
Content="&#xE010;" Content="&#xE010;"
Width="45" Height="45" Width="45" Height="45">
ToolTipService.ToolTip="Maximize"/> <ToolTipService.ToolTip>
<TextBlock x:Uid="/VideoPage/maximize"/>
</ToolTipService.ToolTip>
</Button>
<ProgressBar VerticalAlignment="Bottom" Foreground="Red" Name="seekIndicator" Visibility="Collapsed"/> <ProgressBar VerticalAlignment="Bottom" Foreground="Red" Name="seekIndicator" Visibility="Collapsed"/>
</Grid> </Grid>
<Button Name="skipAd" Visibility="Collapsed" Margin="0,0,0,25" Grid.Row="1" HorizontalAlignment="Right" Foreground="White" VerticalAlignment="Bottom" Padding="10" BorderBrush="Black" BorderThickness="2" Background="#7E000000"> <StackPanel Name="schedulePanel" Visibility="Collapsed" VerticalAlignment="Bottom" HorizontalAlignment="Right" Grid.Row="1" BorderBrush="Black" BorderThickness="2" Background="#7E000000" Padding="10" Margin="0,25" Orientation="Horizontal">
<StackPanel Orientation="Horizontal"> <FontIcon Glyph="&#xE704;" FontSize="30" Margin="0,0,10,0" VerticalAlignment="Top"/>
<TextBlock FontFamily="Segoe MDL2 Assets" FontSize="30" Margin="0,0,10,0" Text="&#xE101;" VerticalAlignment="Center"/> <StackPanel>
<TextBlock Text="Skip ad" FontSize="30" TextWrapping="WrapWholeWords" MaxWidth="250"/> <TextBlock FontWeight="Bold" Text="Stream hasn't started yet"/>
<TextBlock Name="scheduleHeader" Visibility="Collapsed" Text="Stream schedule:"/>
<TextBlock Name="scheduleStart" Visibility="Collapsed" Text="Start time: "/>
<TextBlock Name="scheduleEnd" Visibility="Collapsed" Text="End time:"/>
<TextBlock Name="countdownHeader" Visibility="Collapsed" FontWeight="Bold" Text="Stream will be started in:" Margin="0,10,0,0"/>
<TextBlock Name="countdown" Visibility="Collapsed" FontWeight="SemiBold" FontSize="20" Text="1:00:00:00"/>
</StackPanel>
</StackPanel> </StackPanel>
</Button>
<Grid Grid.Row="2" Height="50" Name="mainControls" Background="#7F000000"> <Grid Grid.Row="2" Height="50" Name="mainControls" Background="#7F000000">
<ProgressBar Name="bufferingBar" VerticalAlignment="Top" Margin="0,-4,0,0" IsIndeterminate="True" Visibility="Visible"/>
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/> <ColumnDefinition Width="auto"/>
@@ -81,53 +110,102 @@
<ColumnDefinition Width="auto"/> <ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<Button Click="play_Click" Name="play" Background="Transparent" FontFamily="Segoe MDL2 Assets" Content="&#xE768;" Foreground="White" Width="50" Height="50" FontSize="25" ToolTipService.ToolTip="Play"/> <Button Click="play_Click" Name="play" Background="Transparent" FontFamily="Segoe MDL2 Assets" Content="&#xE768;" Foreground="White" Width="50" Height="50" FontSize="25">
<Button Name="next" Click="next_Click" Background="Transparent" FontFamily="Segoe MDL2 Assets" Content="&#xE101;" Foreground="White" Width="50" Height="50" FontSize="25" ToolTipService.ToolTip="Next video"/> <ToolTipService.ToolTip>
<Button Name="openVolume" Background="Transparent" FontFamily="Segoe MDL2 Assets" Content="&#xE995;" Foreground="White" Width="50" Height="50" FontSize="25" ToolTipService.ToolTip="Volume"> <TextBlock x:Uid="/VideoPage/play"/>
</ToolTipService.ToolTip>
</Button>
<Button Name="next" Click="next_Click" Background="Transparent" FontFamily="Segoe MDL2 Assets" Content="&#xE101;" Foreground="White" Width="50" Height="50" FontSize="25">
<ToolTipService.ToolTip>
<TextBlock x:Uid="/VideoPage/next"/>
</ToolTipService.ToolTip>
</Button>
<Button Name="openVolume" Background="Transparent" FontFamily="Segoe MDL2 Assets" Content="&#xE995;" Foreground="White" Width="50" Height="50" FontSize="25">
<ToolTipService.ToolTip>
<TextBlock x:Uid="/VideoPage/volume"/>
</ToolTipService.ToolTip>
<Button.Flyout> <Button.Flyout>
<Flyout> <Flyout>
<StackPanel Orientation="Horizontal" Margin="-10"> <StackPanel Orientation="Horizontal" Margin="-10">
<Button Background="Transparent" FontFamily="Segoe MDL2 Assets" Content="&#xE995;" Foreground="White" Width="50" Height="50" FontSize="25" ToolTipService.ToolTip="Mute" Name="muteBtn" Click="muteBtn_Click"/> <Button Background="Transparent" FontFamily="Segoe MDL2 Assets" Content="&#xE995;" Foreground="White" Width="50" Height="50" FontSize="25" Name="muteBtn" Click="muteBtn_Click">
<ToolTipService.ToolTip>
<TextBlock x:Uid="/VideoPage/mute"/>
</ToolTipService.ToolTip>
</Button>
<Slider Orientation="Horizontal" Width="150" Margin="10,5,10,0" VerticalAlignment="Center" Name="volume" ValueChanged="volume_ValueChanged"/> <Slider Orientation="Horizontal" Width="150" Margin="10,5,10,0" VerticalAlignment="Center" Name="volume" ValueChanged="volume_ValueChanged"/>
</StackPanel> </StackPanel>
</Flyout> </Flyout>
</Button.Flyout> </Button.Flyout>
</Button> </Button>
<Button Name="gotoLive" Visibility="Collapsed" Click="GotoLive_Click" Background="Transparent" Foreground="White" Height="50" FontSize="25">
<ToolTipService.ToolTip>
<TextBlock x:Uid="/VideoPage/goLive"/>
</ToolTipService.ToolTip>
<StackPanel Orientation="Horizontal">
<FontIcon Glyph="&#xE91F;" Foreground="Red"/>
<TextBlock Text="Live" Margin="5,0,0,0" FontSize="15" VerticalAlignment="Center"/>
</StackPanel>
</Button>
</StackPanel> </StackPanel>
<Grid Grid.Column="1"> <Grid Grid.Column="1" Name="seekPanel">
<TextBlock Name="elapsedTime" Foreground="White" Text="[Elapsed]" VerticalAlignment="Bottom" HorizontalAlignment="Left" ToolTipService.ToolTip="Time elapsed"/> <TextBlock Name="elapsedTime" Foreground="White" Text="[Elapsed]" VerticalAlignment="Bottom" HorizontalAlignment="Left"/>
<TextBlock Name="remainingTime" Foreground="White" Text="[Remaining]" VerticalAlignment="Bottom" HorizontalAlignment="Right" ToolTipService.ToolTip="Time remaining"/> <TextBlock Name="remainingTime" Foreground="White" Text="[Remaining]" VerticalAlignment="Bottom" HorizontalAlignment="Right"/>
<Grid VerticalAlignment="Top" Margin="0,15,0,0" Height="2"> <Grid VerticalAlignment="Top" Margin="0,15,0,0" Height="2">
<ProgressBar Background="#66FFFFFF" Foreground="LightGray" Name="bufferingLevel"/> <ProgressBar Background="#66FFFFFF" Foreground="LightGray" Name="bufferingLevel"/>
</Grid> </Grid>
<Slider PointerCaptureLost="seek_PointerCaptureLost" ValueChanged="seek_ValueChanged" Name="seek" VerticalAlignment="Top" ToolTipService.ToolTip="Seek" IsThumbToolTipEnabled="False" Background="Transparent" HorizontalAlignment="Stretch"/> <Slider PointerCaptureLost="seek_PointerCaptureLost" ManipulationStarted="Seek_PointerCaptured" ManipulationMode="TranslateRailsX" ValueChanged="seek_ValueChanged" Name="seek" VerticalAlignment="Top" IsThumbToolTipEnabled="False" Background="Transparent" HorizontalAlignment="Stretch"/>
</Grid> </Grid>
<StackPanel Grid.Column="2" Orientation="Horizontal"> <StackPanel Grid.Column="2" Orientation="Horizontal">
<Button Click="back10_Click" Name="back10" Background="Transparent" FontFamily="Segoe MDL2 Assets" Content="&#xED3C;" Foreground="White" Width="50" Height="50" FontSize="25" ToolTipService.ToolTip="Skip back for 10 seconds"/> <TextBlock Text="1:12:32" Name="liveElapsed" Visibility="Collapsed" Margin="10,0" FontSize="20" VerticalAlignment="Center">
<Button Click="fwd30_Click" Name="fwd30" Background="Transparent" FontFamily="Segoe MDL2 Assets" Content="&#xED3D;" Foreground="White" Width="50" Height="50" FontSize="25" ToolTipService.ToolTip="Skip forward for 30 seconds"/> <ToolTipService.ToolTip>
<TextBlock x:Uid="/VideoPage/streamElapsed"/>
</ToolTipService.ToolTip>
</TextBlock>
<StackPanel Orientation="Horizontal" Name="rewindPanel">
<Button Click="back10_Click" Name="back10" Background="Transparent" FontFamily="Segoe MDL2 Assets" Content="&#xED3C;" Foreground="White" Width="50" Height="50" FontSize="25">
<ToolTipService.ToolTip>
<TextBlock x:Uid="/VideoPage/back"/>
</ToolTipService.ToolTip>
</Button>
<Button Click="fwd30_Click" Name="fwd30" Background="Transparent" FontFamily="Segoe MDL2 Assets" Content="&#xED3D;" Foreground="White" Width="50" Height="50" FontSize="25">
<ToolTipService.ToolTip>
<TextBlock x:Uid="/VideoPage/fwd"/>
</ToolTipService.ToolTip>
</Button>
</StackPanel>
<Line Stroke="White" StrokeThickness="2" Y1="5" Y2="45"/> <Line Stroke="White" StrokeThickness="2" Y1="5" Y2="45"/>
<Button Background="Transparent" FontFamily="Segoe MDL2 Assets" Content="&#xE190;" Foreground="White" Width="50" Height="50" FontSize="25" ToolTipService.ToolTip="Subtitles" Name="captionsBtn"> <Button Background="Transparent" FontFamily="Segoe MDL2 Assets" Content="&#xE190;" Foreground="White" Width="50" Height="50" FontSize="25" Name="captionsBtn">
<ToolTipService.ToolTip>
<TextBlock x:Uid="/VideoPage/subs"/>
</ToolTipService.ToolTip>
<Button.Flyout> <Button.Flyout>
<Flyout> <Flyout>
<StackPanel Width="225"> <StackPanel Width="225">
<ToggleSwitch Name="subsSwitch" Toggled="subsSwitch_Toggled" OnContent="Subtitles" OffContent="Subtitles"/> <ToggleSwitch x:Uid="/VideoPage/subsSwitch" Name="subsSwitch" Toggled="subsSwitch_Toggled" OnContent="Subtitles" OffContent="Subtitles"/>
<ComboBox Name="subsLang" Header="Language" PlaceholderText="No subtitles are available" Visibility="Collapsed" HorizontalAlignment="Stretch" SelectionChanged="subsLang_SelectionChanged"/> <ComboBox x:Uid="/VideoPage/subsSelector" Name="subsLang" Header="Language" PlaceholderText="No subtitles are available" Visibility="Collapsed" HorizontalAlignment="Stretch" SelectionChanged="subsLang_SelectionChanged"/>
</StackPanel> </StackPanel>
</Flyout> </Flyout>
</Button.Flyout> </Button.Flyout>
</Button> </Button>
<Button Background="Transparent" FontFamily="Segoe MDL2 Assets" Content="&#xE713;" Foreground="White" Width="50" Height="50" FontSize="25" ToolTipService.ToolTip="Video quality"> <Button Name="qualityBtn" Background="Transparent" FontFamily="Segoe MDL2 Assets" Content="&#xE713;" Foreground="White" Width="50" Height="50" FontSize="25">
<ToolTipService.ToolTip>
<TextBlock x:Uid="/VideoPage/quality"/>
</ToolTipService.ToolTip>
<Button.Flyout> <Button.Flyout>
<Flyout> <Flyout>
<ComboBox Width="225" Header="Quality" Name="quality" SelectionChanged="quality_SelectionChanged"/> <ComboBox x:Uid="/VideoPage/qualitySelector" Width="225" Header="Quality" Name="quality" SelectionChanged="quality_SelectionChanged"/>
</Flyout> </Flyout>
</Button.Flyout> </Button.Flyout>
</Button> </Button>
<Button Background="Transparent" FontFamily="Segoe MDL2 Assets" Content="&#xE740;" Foreground="White" Width="50" Height="50" FontSize="25" ToolTipService.ToolTip="Full screen" Name="fullscreen" Click="fullscreen_Click"/> <Button Background="Transparent" FontFamily="Segoe MDL2 Assets" Content="&#xE740;" Foreground="White" Width="50" Height="50" FontSize="25" Name="fullscreen" Click="fullscreen_Click">
<ToolTipService.ToolTip>
<TextBlock x:Uid="/VideoPage/fullscreen"/>
</ToolTipService.ToolTip>
</Button>
</StackPanel> </StackPanel>
</Grid> </Grid>
</Grid> </Grid>
@@ -168,13 +246,5 @@
<Button Name="signin" Click="signin_Click" Content="Sign in now" Foreground="White" Background="Gray" HorizontalAlignment="Right" Grid.Column="1" Margin="0,0,10,0"/> <Button Name="signin" Click="signin_Click" Content="Sign in now" Foreground="White" Background="Gray" HorizontalAlignment="Right" Grid.Column="1" Margin="0,0,10,0"/>
</Grid> </Grid>
</Grid> </Grid>
<Grid Background="#E5000000" Visibility="Collapsed">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Name="errorPlate">
<TextBlock Text="Something went wrong..." HorizontalAlignment="Center" FontSize="20"/>
<TextBlock Text="Video ID: " HorizontalAlignment="Center" IsTextSelectionEnabled="True" FontSize="20"/>
<TextBlock Text="Error type: " HorizontalAlignment="Center" IsTextSelectionEnabled="True" FontSize="20"/>
<TextBlock Text="Message: " HorizontalAlignment="Center" IsTextSelectionEnabled="True" FontSize="20"/>
</StackPanel>
</Grid>
</Grid> </Grid>
</UserControl> </UserControl>
File diff suppressed because it is too large Load Diff
+39 -7
View File
@@ -17,11 +17,12 @@
<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>
<WindowsXamlEnableOverview>true</WindowsXamlEnableOverview> <WindowsXamlEnableOverview>true</WindowsXamlEnableOverview>
<PackageCertificateKeyFile>FoxTube_TemporaryKey.pfx</PackageCertificateKeyFile> <PackageCertificateKeyFile>
<PackageCertificateThumbprint>E33236F6F6066A373DFA92A7B7C1467B1EF0BA81</PackageCertificateThumbprint> </PackageCertificateKeyFile>
<PackageCertificateThumbprint>E888C12EC9A02B902D03CDA4515BDBE9F5E71F1F</PackageCertificateThumbprint>
<GenerateAppInstallerFile>False</GenerateAppInstallerFile> <GenerateAppInstallerFile>False</GenerateAppInstallerFile>
<AppxAutoIncrementPackageRevision>False</AppxAutoIncrementPackageRevision> <AppxAutoIncrementPackageRevision>False</AppxAutoIncrementPackageRevision>
<AppxPackageDir>C:\Users\Michael Gordeev\Downloads\FoxTube dists\0.2.1812-2\</AppxPackageDir> <AppxPackageDir>C:\Users\Michael Gordeev\Downloads\FoxTube dists\0.2.1901-1\</AppxPackageDir>
<AppxBundle>Always</AppxBundle> <AppxBundle>Always</AppxBundle>
<AppxBundlePlatforms>x86|x64|arm</AppxBundlePlatforms> <AppxBundlePlatforms>x86|x64|arm</AppxBundlePlatforms>
<AppInstallerUpdateFrequency>1</AppInstallerUpdateFrequency> <AppInstallerUpdateFrequency>1</AppInstallerUpdateFrequency>
@@ -103,7 +104,6 @@
<Compile Include="App.xaml.cs"> <Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon> <DependentUpon>App.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Classes\Caption.cs" />
<Compile Include="Classes\DownloadItemContainer.cs" /> <Compile Include="Classes\DownloadItemContainer.cs" />
<Compile Include="Classes\InboxItem.cs" /> <Compile Include="Classes\InboxItem.cs" />
<Compile Include="Classes\Methods.cs" /> <Compile Include="Classes\Methods.cs" />
@@ -112,9 +112,15 @@
<Compile Include="Controls\Advert.xaml.cs"> <Compile Include="Controls\Advert.xaml.cs">
<DependentUpon>Advert.xaml</DependentUpon> <DependentUpon>Advert.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Controls\Adverts\CardAdvert.xaml.cs">
<DependentUpon>CardAdvert.xaml</DependentUpon>
</Compile>
<Compile Include="Controls\ChannelCard.xaml.cs"> <Compile Include="Controls\ChannelCard.xaml.cs">
<DependentUpon>ChannelCard.xaml</DependentUpon> <DependentUpon>ChannelCard.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Controls\Chat.xaml.cs">
<DependentUpon>Chat.xaml</DependentUpon>
</Compile>
<Compile Include="Controls\CommentCard.xaml.cs"> <Compile Include="Controls\CommentCard.xaml.cs">
<DependentUpon>CommentCard.xaml</DependentUpon> <DependentUpon>CommentCard.xaml</DependentUpon>
</Compile> </Compile>
@@ -280,10 +286,18 @@
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
<Page Include="Controls\Adverts\CardAdvert.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Controls\ChannelCard.xaml"> <Page Include="Controls\ChannelCard.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
<Page Include="Controls\Chat.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Controls\CommentCard.xaml"> <Page Include="Controls\CommentCard.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
@@ -403,7 +417,7 @@
<Version>6.1.9</Version> <Version>6.1.9</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.Toolkit.Uwp.Notifications"> <PackageReference Include="Microsoft.Toolkit.Uwp.Notifications">
<Version>4.0.0</Version> <Version>5.0.0</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.Toolkit.Uwp.UI.Controls"> <PackageReference Include="Microsoft.Toolkit.Uwp.UI.Controls">
<Version>4.0.0</Version> <Version>4.0.0</Version>
@@ -412,7 +426,7 @@
<Version>4.3.2</Version> <Version>4.3.2</Version>
</PackageReference> </PackageReference>
<PackageReference Include="YoutubeExplode"> <PackageReference Include="YoutubeExplode">
<Version>4.5.1</Version> <Version>4.6.1</Version>
</PackageReference> </PackageReference>
<PackageReference Include="YoutubeExtractor"> <PackageReference Include="YoutubeExtractor">
<Version>0.10.11</Version> <Version>0.10.11</Version>
@@ -420,6 +434,25 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="FoxTube_TemporaryKey.pfx" /> <None Include="FoxTube_TemporaryKey.pfx" />
<PRIResource Include="Strings\ru-RU\VideoPage.resw" />
<PRIResource Include="Strings\en-US\VideoPage.resw" />
<PRIResource Include="Strings\ru-RU\Channel.resw" />
<PRIResource Include="Strings\en-US\Channel.resw" />
<PRIResource Include="Strings\ru-RU\Chat.resw" />
<PRIResource Include="Strings\en-US\Chat.resw" />
<PRIResource Include="Strings\ru-RU\Cards.resw" />
<PRIResource Include="Strings\en-US\Cards.resw" />
<PRIResource Include="Strings\ru-RU\Methods.resw" />
<PRIResource Include="Strings\en-US\Methods.resw" />
<PRIResource Include="Strings\ru-RU\Search.resw" />
<PRIResource Include="Strings\en-US\Search.resw" />
<PRIResource Include="Strings\ru-RU\Playlist.resw" />
<PRIResource Include="Strings\en-US\Playlist.resw" />
<PRIResource Include="Strings\ru-RU\Downloads.resw" />
<PRIResource Include="Strings\ru-RU\CommentsPage.resw" />
<PRIResource Include="Strings\en-US\Downloads.resw" />
<PRIResource Include="Strings\ru-RU\Home.resw" />
<PRIResource Include="Strings\en-US\Home.resw" />
<PRIResource Include="Strings\en-US\CommentsPage.resw" /> <PRIResource Include="Strings\en-US\CommentsPage.resw" />
<PRIResource Include="Strings\ru-RU\LoadingPage.resw" /> <PRIResource Include="Strings\ru-RU\LoadingPage.resw" />
<PRIResource Include="Strings\en-US\LoadingPage.resw" /> <PRIResource Include="Strings\en-US\LoadingPage.resw" />
@@ -427,7 +460,6 @@
<PRIResource Include="Strings\ru-RU\General.resw" /> <PRIResource Include="Strings\ru-RU\General.resw" />
<PRIResource Include="Strings\ru-RU\About.resw" /> <PRIResource Include="Strings\ru-RU\About.resw" />
<PRIResource Include="Strings\ru-RU\Settings.resw" /> <PRIResource Include="Strings\ru-RU\Settings.resw" />
<PRIResource Include="Strings\en-US\Translate.resw" />
<PRIResource Include="Strings\en-US\Inbox.resw" /> <PRIResource Include="Strings\en-US\Inbox.resw" />
<PRIResource Include="Strings\en-US\About.resw" /> <PRIResource Include="Strings\en-US\About.resw" />
<PRIResource Include="Strings\en-US\General.resw" /> <PRIResource Include="Strings\en-US\General.resw" />
+3 -3
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3" IgnorableNamespaces="uap mp uap3"> <Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3" IgnorableNamespaces="uap mp uap3">
<Identity Name="foxtube-5d1cba1f-d7d5-472b-acb7-beb360bab268" Publisher="CN=Michael Gordeev" Version="0.2.18122.0" /> <Identity Name="foxtube-5d1cba1f-d7d5-472b-acb7-beb360bab268" Publisher="CN=Michael Gordeev" Version="0.2.19012.0" />
<mp:PhoneIdentity PhoneProductId="5d1cba1f-d7d5-472b-acb7-beb360bab268" PhonePublisherId="00000000-0000-0000-0000-000000000000" /> <mp:PhoneIdentity PhoneProductId="5d1cba1f-d7d5-472b-acb7-beb360bab268" PhonePublisherId="00000000-0000-0000-0000-000000000000" />
<Properties> <Properties>
<DisplayName>FoxTube</DisplayName> <DisplayName>FoxTube</DisplayName>
@@ -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" BackgroundColor="red"> <uap:VisualElements DisplayName="FoxTube" Square150x150Logo="Assets\Square150x150Logo.png" Square44x44Logo="Assets\Square44x44Logo.png" Description="YouTube Client" BackgroundColor="skyBlue">
<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="red" /> <uap:SplashScreen Image="Assets\SplashScreen.png" BackgroundColor="#282828" />
</uap:VisualElements> </uap:VisualElements>
<Extensions> <Extensions>
<Extension Category="windows.backgroundTasks" EntryPoint="FoxTube.Background.BackgroundProcessor"> <Extension Category="windows.backgroundTasks" EntryPoint="FoxTube.Background.BackgroundProcessor">
+15 -15
View File
@@ -17,7 +17,7 @@
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Pivot SelectedIndex="0" Name="content" IsHeaderItemsCarouselEnabled="False" SelectionChanged="content_SelectionChanged"> <Pivot SelectedIndex="0" Name="content" IsHeaderItemsCarouselEnabled="False" SelectionChanged="content_SelectionChanged">
<PivotItem Header="Videos"> <PivotItem x:Uid="/Channel/videos" Header="Videos">
<ScrollViewer> <ScrollViewer>
<StackPanel Name="videos"> <StackPanel Name="videos">
<Image Name="channelCover" Stretch="Uniform" Source="/Assets/ChannelCoverTemplate.png"/> <Image Name="channelCover" Stretch="Uniform" Source="/Assets/ChannelCoverTemplate.png"/>
@@ -35,11 +35,11 @@
<TextBlock Name="videosCount" Foreground="Gray" Text="563,000 videos"/> <TextBlock Name="videosCount" Foreground="Gray" Text="563,000 videos"/>
</StackPanel> </StackPanel>
<TextBlock Grid.Column="2" VerticalAlignment="Bottom" HorizontalAlignment="Stretch" Height="50" Margin="10" TextAlignment="Center" Padding="0,16,0,0" Foreground="Gray"> <TextBlock Grid.Column="2" VerticalAlignment="Bottom" HorizontalAlignment="Stretch" Height="50" Margin="10" TextAlignment="Center" Padding="0,16,0,0" Foreground="Gray">
<Hyperlink Click="Hyperlink_Click">Log in</Hyperlink> to manage your subscriptions <Hyperlink Click="Hyperlink_Click"><Run x:Uid="/Cards/login">Log in</Run></Hyperlink> <Run x:Uid="/Cards/tomanage">to manage your subscriptions</Run>
</TextBlock> </TextBlock>
<Grid Visibility="Collapsed" Grid.Column="2" VerticalAlignment="Bottom" Margin="10" Name="subscriptionPane" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <Grid Visibility="Collapsed" Grid.Column="2" VerticalAlignment="Bottom" Margin="10" Name="subscriptionPane" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Button Click="subscribe_Click" Name="subscribe" Width="250" Height="50" Background="Red" Foreground="White" FontSize="18" FontWeight="SemiBold" Content="Subscirbe"/> <Button x:Uid="/Cards/subscribe" Click="subscribe_Click" Name="subscribe" Width="250" Height="50" Background="Red" Foreground="White" FontSize="18" FontWeight="SemiBold" Content="Subscirbe"/>
</Grid> </Grid>
</Grid> </Grid>
<pages:VideoGrid/> <pages:VideoGrid/>
@@ -47,11 +47,11 @@
</StackPanel> </StackPanel>
</ScrollViewer> </ScrollViewer>
</PivotItem> </PivotItem>
<PivotItem Header="Playlists"> <PivotItem x:Uid="/Channel/playlists" Header="Playlists">
<ScrollViewer> <ScrollViewer>
<Grid Name="playlists"> <Grid Name="playlists">
<StackPanel Margin="10" Visibility="Visible"> <StackPanel Margin="10" Visibility="Visible">
<TextBlock FontSize="28" Text="Playlists"/> <TextBlock x:Uid="/Channel/playlistTitle" FontSize="28" Text="Playlists"/>
<pages:VideoGrid/> <pages:VideoGrid/>
<controls:ShowMore Clicked="showMorePlaylists_Click"/> <controls:ShowMore Clicked="showMorePlaylists_Click"/>
</StackPanel> </StackPanel>
@@ -59,10 +59,10 @@
</Grid> </Grid>
</ScrollViewer> </ScrollViewer>
</PivotItem> </PivotItem>
<PivotItem Header="About channel"> <PivotItem x:Uid="/Channel/about" Header="About channel">
<ScrollViewer> <ScrollViewer>
<StackPanel Margin="10"> <StackPanel Margin="10">
<TextBlock FontSize="28" Text="About this channel"/> <TextBlock x:Uid="/Channel/aboutTitle" FontSize="28" Text="About this channel"/>
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition/> <ColumnDefinition/>
@@ -70,7 +70,7 @@
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<StackPanel> <StackPanel>
<TextBlock FontSize="24" Text="Description"/> <TextBlock x:Uid="/Channel/desc" FontSize="24" Text="Description"/>
<TextBlock Name="description" Margin="0,10,0,0" TextWrapping="WrapWholeWords" IsTextSelectionEnabled="True"/> <TextBlock Name="description" Margin="0,10,0,0" TextWrapping="WrapWholeWords" IsTextSelectionEnabled="True"/>
</StackPanel> </StackPanel>
@@ -85,12 +85,12 @@
<RowDefinition Height="auto"/> <RowDefinition Height="auto"/>
<RowDefinition Height="auto"/> <RowDefinition Height="auto"/>
</Grid.RowDefinitions> </Grid.RowDefinitions>
<TextBlock FontSize="24" Text="Statistics"/> <TextBlock x:Uid="/Channel/stats" FontSize="24" Text="Statistics"/>
<TextBlock Text="Registration date:" Grid.Row="1"/> <TextBlock x:Uid="/Channel/regDate" Text="Registration date:" Grid.Row="1"/>
<TextBlock Grid.Row="1" Grid.Column="2" Name="registration" Text="13-May-18" HorizontalAlignment="Right"/> <TextBlock Grid.Row="1" Grid.Column="2" Name="registration" Text="13-May-18" HorizontalAlignment="Right"/>
<TextBlock Grid.Row="2" Text="Views"/> <TextBlock x:Uid="/Channel/views" Grid.Row="2" Text="Views"/>
<TextBlock Grid.Row="2" Grid.Column="2" Name="views" Text="1885510485" HorizontalAlignment="Right"/> <TextBlock Grid.Row="2" Grid.Column="2" Name="views" Text="1885510485" HorizontalAlignment="Right"/>
</Grid> </Grid>
</Grid> </Grid>
@@ -99,14 +99,14 @@
</PivotItem> </PivotItem>
<Pivot.RightHeader> <Pivot.RightHeader>
<AutoSuggestBox VerticalAlignment="Center" Width="250" Margin="8" PlaceholderText="Search on channel" QueryIcon="Find" Name="search" QuerySubmitted="AutoSuggestBox_QuerySubmitted"/> <AutoSuggestBox x:Uid="/Channel/search" VerticalAlignment="Center" Width="250" Margin="8" PlaceholderText="Search on channel" QueryIcon="Find" Name="search" QuerySubmitted="AutoSuggestBox_QuerySubmitted"/>
</Pivot.RightHeader> </Pivot.RightHeader>
</Pivot> </Pivot>
<CommandBar Grid.Row="1" VerticalAlignment="Bottom" Name="commandBar"> <CommandBar Grid.Row="1" VerticalAlignment="Bottom" Name="commandBar">
<AppBarButton Icon="Globe" Label="Open in browser" Name="inBrowser" Click="inBrowser_Click"/> <AppBarButton x:Uid="/Channel/openWeb" Icon="Globe" Label="Open in browser" Name="inBrowser" Click="inBrowser_Click"/>
<AppBarButton Icon="Refresh" Label="Refresh" Name="refresh" Click="refresh_Click"/> <AppBarButton x:Uid="/Channel/refresh" Icon="Refresh" Label="Refresh" Name="refresh" Click="refresh_Click"/>
<AppBarButton Icon="Share" Label="Share" Name="share" Click="share_Click"/> <AppBarButton x:Uid="/Channel/share" Icon="Share" Label="Share" Name="share" Click="share_Click"/>
</CommandBar> </CommandBar>
<local:LoadingPage Grid.RowSpan="2" Visibility="Collapsed"/> <local:LoadingPage Grid.RowSpan="2" Visibility="Collapsed"/>
+9 -6
View File
@@ -12,6 +12,7 @@ using FoxTube.Controls;
using Windows.ApplicationModel.DataTransfer; using Windows.ApplicationModel.DataTransfer;
using Windows.System; using Windows.System;
using Windows.UI; using Windows.UI;
using Windows.ApplicationModel.Resources;
namespace FoxTube.Pages namespace FoxTube.Pages
{ {
@@ -20,6 +21,8 @@ namespace FoxTube.Pages
/// </summary> /// </summary>
public sealed partial class ChannelPage : Page public sealed partial class ChannelPage : Page
{ {
ResourceLoader resources = ResourceLoader.GetForCurrentView("Cards");
public string channelId; public string channelId;
public Channel item; public Channel item;
@@ -78,8 +81,8 @@ namespace FoxTube.Pages
item = (await request.ExecuteAsync()).Items[0]; item = (await request.ExecuteAsync()).Items[0];
title.Text = item.Snippet.Title; title.Text = item.Snippet.Title;
subscribers.Text = $"{item.Statistics.SubscriberCount:0,0} subscribers"; subscribers.Text = $"{item.Statistics.SubscriberCount:0,0} {resources.GetString("/Cards/subscribers")}";
videosCount.Text = $"{item.Statistics.VideoCount:0,0} videos"; videosCount.Text = $"{item.Statistics.VideoCount:0,0} {resources.GetString("/Cards/videos")}";
try try
{ {
@@ -121,7 +124,7 @@ namespace FoxTube.Pages
{ {
subscribe.Background = new SolidColorBrush(Colors.Transparent); subscribe.Background = new SolidColorBrush(Colors.Transparent);
subscribe.Foreground = new SolidColorBrush(Colors.Gray); subscribe.Foreground = new SolidColorBrush(Colors.Gray);
subscribe.Content = "Subscribed"; subscribe.Content = resources.GetString("/Cards/unsubscribe");
} }
subscriptionPane.Visibility = Visibility.Visible; subscriptionPane.Visibility = Visibility.Visible;
} }
@@ -228,13 +231,13 @@ namespace FoxTube.Pages
{ {
subscribe.Background = new SolidColorBrush(Colors.Transparent); subscribe.Background = new SolidColorBrush(Colors.Transparent);
subscribe.Foreground = new SolidColorBrush(Colors.Gray); subscribe.Foreground = new SolidColorBrush(Colors.Gray);
subscribe.Content = "Subscribed"; subscribe.Content = resources.GetString("/Cards/unsubscribe");
} }
else else
{ {
subscribe.Background = new SolidColorBrush(Colors.Red); subscribe.Background = new SolidColorBrush(Colors.Red);
subscribe.Foreground = new SolidColorBrush(Colors.White); subscribe.Foreground = new SolidColorBrush(Colors.White);
subscribe.Content = "Subscribe"; subscribe.Content = resources.GetString("/Cards/subscribe/Content");
} }
} }
@@ -286,7 +289,7 @@ namespace FoxTube.Pages
item.Snippet.Thumbnails.Medium.Url, item.Snippet.Thumbnails.Medium.Url,
item.Snippet.Title, item.Snippet.Title,
string.IsNullOrWhiteSpace(item.Snippet.CustomUrl) ? $"https://www.youtube.com/channel/{item.Id}" : $"https://www.youtube.com/user/{item.Snippet.CustomUrl}", string.IsNullOrWhiteSpace(item.Snippet.CustomUrl) ? $"https://www.youtube.com/channel/{item.Id}" : $"https://www.youtube.com/user/{item.Snippet.CustomUrl}",
"channel"); resources.GetString("/Cards/channelShare"));
} }
} }
} }
+2 -2
View File
@@ -29,7 +29,7 @@
<TextBlock Name="counter" Grid.Row="1" Text="[Comments count] Comments" Margin="5,0,0,0" VerticalAlignment="Center" FontWeight="SemiBold"/> <TextBlock Name="counter" Grid.Row="1" Text="[Comments count] Comments" Margin="5,0,0,0" VerticalAlignment="Center" FontWeight="SemiBold"/>
<StackPanel Padding="0" Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,0,10,0"> <StackPanel Padding="0" Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,0,10,0">
<TextBlock x:Uid="/CommentsPage/sortBy" Text="Sort by: " VerticalAlignment="Center" Margin="0,0,5,0"/> <TextBlock x:Uid="/CommentsPage/sortBy" Text="Sort by: " VerticalAlignment="Center" Margin="0,0,5,0"/>
<Button Name="orderBtn" Background="Transparent" Content="Relevance" Foreground="Red" Padding="0" VerticalAlignment="Center"> <Button Name="orderBtn" Background="Transparent" Content="Relevance" Foreground="Red" Padding="0" VerticalAlignment="Bottom" HorizontalAlignment="Center" Margin="0,0,0,3">
<Button.Flyout> <Button.Flyout>
<MenuFlyout> <MenuFlyout>
@@ -44,7 +44,7 @@
<ScrollViewer Grid.Row="1" Name="scroll"> <ScrollViewer Grid.Row="1" Name="scroll">
<StackPanel> <StackPanel>
<StackPanel Name="placeholder"/> <StackPanel Name="placeholder"/>
<HyperlinkButton Visibility="Collapsed" Name="more" Click="more_Click" HorizontalAlignment="Center" Foreground="Red" Content="Show more"/> <HyperlinkButton x:Uid="/CommentsPage/more" Visibility="Collapsed" Name="more" Click="more_Click" HorizontalAlignment="Center" Foreground="Red" Content="Show more"/>
<ProgressBar Name="moreLoading" Visibility="Collapsed" IsIndeterminate="True" Foreground="Red"/> <ProgressBar Name="moreLoading" Visibility="Collapsed" IsIndeterminate="True" Foreground="Red"/>
</StackPanel> </StackPanel>
</ScrollViewer> </ScrollViewer>
+14 -7
View File
@@ -1,21 +1,21 @@
using System; using System;
using Windows.UI.Xaml; using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls;
using Google.Apis.YouTube.v3; using Google.Apis.YouTube.v3;
using Google.Apis.YouTube.v3.Data; using Google.Apis.YouTube.v3.Data;
using FoxTube.Controls; using FoxTube.Controls;
using Windows.UI.Popups; using Windows.UI.Popups;
using Windows.ApplicationModel.Resources;
// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238
namespace FoxTube.Pages namespace FoxTube.Pages
{ {
/// <summary> /// <summary>
/// An empty page that can be used on its own or navigated to within a Frame. /// Comments placeholder
/// </summary> /// </summary>
public sealed partial class CommentsPage : Page public sealed partial class CommentsPage : Page
{ {
ResourceLoader resources = ResourceLoader.GetForCurrentView("CommentsPage");
string threadId; string threadId;
string nextPageToken; string nextPageToken;
@@ -29,13 +29,15 @@ namespace FoxTube.Pages
public async void Initialize(Video video) public async void Initialize(Video video)
{ {
threadId = video.Id; threadId = video.Id;
Methods.CommentsPage = this;
if (!SecretsVault.IsAuthorized) if (!SecretsVault.IsAuthorized)
grid.RowDefinitions[0].Height = new GridLength(0); grid.RowDefinitions[0].Height = new GridLength(0);
else else
grid.RowDefinitions[0].Height = GridLength.Auto; grid.RowDefinitions[0].Height = GridLength.Auto;
counter.Text = string.Format("{0:0,0} Comments", video.Statistics.CommentCount); counter.Text = $"{video.Statistics.CommentCount:0,0} {resources.GetString("/CommentsPage/comments")}";
orderBtn.Content = resources.GetString("/CommentsPage/relevance/Text");
var request = SecretsVault.Service.CommentThreads.List("snippet,replies"); var request = SecretsVault.Service.CommentThreads.List("snippet,replies");
request.Order = order; request.Order = order;
@@ -53,6 +55,11 @@ namespace FoxTube.Pages
placeholder.Children.Add(new CommentCard(comment)); placeholder.Children.Add(new CommentCard(comment));
} }
public void RemoveComment(CommentCard commentCard)
{
placeholder.Children.Remove(commentCard);
}
private async void more_Click(object sender, RoutedEventArgs e) private async void more_Click(object sender, RoutedEventArgs e)
{ {
more.Visibility = Visibility.Collapsed; more.Visibility = Visibility.Collapsed;
@@ -84,7 +91,7 @@ namespace FoxTube.Pages
moreLoading.Visibility = Visibility.Visible; moreLoading.Visibility = Visibility.Visible;
order = CommentThreadsResource.ListRequest.OrderEnum.Relevance; order = CommentThreadsResource.ListRequest.OrderEnum.Relevance;
orderBtn.Content = "Relevance"; orderBtn.Content = resources.GetString("/CommentsPage/relevance/Text");
placeholder.Children.Clear(); placeholder.Children.Clear();
@@ -111,7 +118,7 @@ namespace FoxTube.Pages
moreLoading.Visibility = Visibility.Visible; moreLoading.Visibility = Visibility.Visible;
order = CommentThreadsResource.ListRequest.OrderEnum.Time; order = CommentThreadsResource.ListRequest.OrderEnum.Time;
orderBtn.Content = "Publish date"; orderBtn.Content = resources.GetString("/CommentsPage/publish");
placeholder.Children.Clear(); placeholder.Children.Clear();
+3 -3
View File
@@ -21,17 +21,17 @@
<ColumnDefinition Width="auto"/> <ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<TextBlock Name="path" IsTextSelectionEnabled="True" TextWrapping="WrapWholeWords"/> <TextBlock Name="path" IsTextSelectionEnabled="True" TextWrapping="WrapWholeWords"/>
<Button Grid.Column="1" Content="Open folder" Name="open" Click="Open_Click" VerticalAlignment="Center"/> <Button Grid.Column="1" x:Uid="/Downloads/openFolder" Content="Open folder" Name="open" Click="Open_Click" VerticalAlignment="Center"/>
</Grid> </Grid>
<ScrollViewer Grid.Row="1"> <ScrollViewer Grid.Row="1">
<StackPanel Name="stack"/> <StackPanel Name="stack"/>
</ScrollViewer> </ScrollViewer>
<TextBlock Grid.Row="1" Name="empty" HorizontalAlignment="Center" VerticalAlignment="Top" FontSize="28" Text="You haven't downloaded anything yet" Margin="10" TextWrapping="WrapWholeWords" Foreground="Gray" FontWeight="SemiBold"/> <TextBlock x:Uid="/Downloads/noItems" Grid.Row="1" Name="empty" HorizontalAlignment="Center" VerticalAlignment="Top" FontSize="28" Text="You haven't downloaded anything yet" Margin="10" TextWrapping="WrapWholeWords" Foreground="Gray" FontWeight="SemiBold"/>
<CommandBar DefaultLabelPosition="Right" Grid.Row="2"> <CommandBar DefaultLabelPosition="Right" Grid.Row="2">
<AppBarButton Label="Refresh" Icon="Refresh" Click="Refresh"/> <AppBarButton x:Uid="/Downloads/refresh" Label="Refresh" Icon="Refresh" Click="Refresh"/>
</CommandBar> </CommandBar>
</Grid> </Grid>
</Page> </Page>
+4 -4
View File
@@ -16,12 +16,12 @@
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Pivot Name="pivot" SelectionChanged="pivot_SelectionChanged"> <Pivot Name="pivot" SelectionChanged="pivot_SelectionChanged">
<PivotItem Header="Recommended" Name="recommended"> <PivotItem x:Uid="/Home/recommended" Header="Recommended" Name="recommended">
<ScrollViewer> <ScrollViewer>
<StackPanel/> <StackPanel/>
</ScrollViewer> </ScrollViewer>
</PivotItem> </PivotItem>
<PivotItem Header="Trending" Name="trending"> <PivotItem x:Uid="/Home/trending" Header="Trending" Name="trending">
<ScrollViewer> <ScrollViewer>
<StackPanel> <StackPanel>
<pages:VideoGrid/> <pages:VideoGrid/>
@@ -29,7 +29,7 @@
</StackPanel> </StackPanel>
</ScrollViewer> </ScrollViewer>
</PivotItem> </PivotItem>
<PivotItem Header="Subscriptions" Name="subscriptions"> <PivotItem x:Uid="/Home/subs" Header="Subscriptions" Name="subscriptions">
<ScrollViewer> <ScrollViewer>
<StackPanel/> <StackPanel/>
</ScrollViewer> </ScrollViewer>
@@ -37,7 +37,7 @@
</Pivot> </Pivot>
<CommandBar Grid.Row="1"> <CommandBar Grid.Row="1">
<AppBarButton Icon="Refresh" Label="Refresh page" Name="refresh" Click="refreshPage"/> <AppBarButton x:Uid="/Home/refresh" Icon="Refresh" Label="Refresh page" Name="refresh" Click="refreshPage"/>
</CommandBar> </CommandBar>
<local:LoadingPage Grid.RowSpan="2" Margin="0,50,0,0" Visibility="Visible" RefreshPage="refreshPage"/> <local:LoadingPage Grid.RowSpan="2" Margin="0,50,0,0" Visibility="Visible" RefreshPage="refreshPage"/>
</Grid> </Grid>
+2 -4
View File
@@ -25,12 +25,10 @@ namespace FoxTube
string trendToken; string trendToken;
Dictionary<string, string> subsTokens = new Dictionary<string, string>(); Dictionary<string, string> subsTokens = new Dictionary<string, string>();
string reg;
public Home() public Home()
{ {
InitializeComponent(); InitializeComponent();
reg = CultureInfo.GetCultures(CultureTypes.AllCultures).Find(i => i.IetfLanguageTag == SettingsStorage.Region).IetfLanguageTag.Remove(0, 3);
trendGrid = ((trending.Content as ScrollViewer).Content as StackPanel).Children[0] as VideoGrid; trendGrid = ((trending.Content as ScrollViewer).Content as StackPanel).Children[0] as VideoGrid;
trendMore = ((trending.Content as ScrollViewer).Content as StackPanel).Children[1] as ShowMore; trendMore = ((trending.Content as ScrollViewer).Content as StackPanel).Children[1] as ShowMore;
@@ -54,7 +52,7 @@ namespace FoxTube
request.PageToken = trendToken; request.PageToken = trendToken;
request.Chart = VideosResource.ListRequest.ChartEnum.MostPopular; request.Chart = VideosResource.ListRequest.ChartEnum.MostPopular;
request.RegionCode = reg; request.RegionCode = SettingsStorage.Region;
VideoListResponse response = await request.ExecuteAsync(); VideoListResponse response = await request.ExecuteAsync();
if (!string.IsNullOrWhiteSpace(response.NextPageToken)) if (!string.IsNullOrWhiteSpace(response.NextPageToken))
@@ -108,7 +106,7 @@ namespace FoxTube
request.MaxResults = 48; request.MaxResults = 48;
request.Chart = VideosResource.ListRequest.ChartEnum.MostPopular; request.Chart = VideosResource.ListRequest.ChartEnum.MostPopular;
request.RegionCode = reg; request.RegionCode = SettingsStorage.Region;
VideoListResponse response = await request.ExecuteAsync(); VideoListResponse response = await request.ExecuteAsync();
if (!string.IsNullOrWhiteSpace(response.NextPageToken)) if (!string.IsNullOrWhiteSpace(response.NextPageToken))
+12 -13
View File
@@ -2,7 +2,6 @@
x:Class="FoxTube.LoadingPage" x:Class="FoxTube.LoadingPage"
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:local="using:FoxTube"
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">
@@ -12,28 +11,28 @@
<StackPanel Name="wifiTrouble" Visibility="Collapsed" VerticalAlignment="Center"> <StackPanel Name="wifiTrouble" Visibility="Collapsed" VerticalAlignment="Center">
<FontIcon FontFamily="Segoe MDL2 Assets" Glyph="&#xEB5E;" FontSize="100" HorizontalAlignment="Center"/> <FontIcon FontFamily="Segoe MDL2 Assets" Glyph="&#xEB5E;" FontSize="100" HorizontalAlignment="Center"/>
<TextBlock Text="Check your internet connection" FontSize="48" HorizontalAlignment="Center"/> <TextBlock x:Uid="/LoadingPage/checkConnection" Text="Check your internet connection" TextWrapping="WrapWholeWords" FontSize="48" HorizontalAlignment="Center" HorizontalTextAlignment="Center"/>
<TextBlock Text="Please, make sure you are connected to the internet and try again." HorizontalAlignment="Center"/> <TextBlock x:Uid="/LoadingPage/wifiDesc" Text="Please, make sure you are connected to the internet and try again." HorizontalAlignment="Center" TextWrapping="WrapWholeWords" HorizontalTextAlignment="Center"/>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center"> <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Button Content="Open network settings" Margin="5" Name="openWifi" Click="openWifi_Click"/> <Button x:Uid="/LoadingPage/openWifi" Content="Open network settings" Margin="5" Name="openWifi" Click="openWifi_Click"/>
<Button Content="Open troubleshooter" Background="Red" Foreground="White" Margin="5" Name="openTroubleshoot" Click="openTroubleshoot_Click"/> <Button x:Uid="/LoadingPage/openTroubleshooter" Content="Open troubleshooter" Background="Red" Foreground="White" Margin="5" Name="openTroubleshoot" Click="openTroubleshoot_Click"/>
</StackPanel> </StackPanel>
<TextBlock Text="OR" FontSize="20" HorizontalAlignment="Center"/> <TextBlock x:Uid="/LoadingPage/or" Text="OR" FontSize="20" HorizontalAlignment="Center"/>
<Button Name="wifiRefresh" Click="wifiRefresh_Click" Content="Refresh page" HorizontalAlignment="Center" Background="Red" Foreground="White" Margin="5"/> <Button x:Uid="/LoadingPage/refresh" Name="wifiRefresh" Click="wifiRefresh_Click" Content="Refresh page" HorizontalAlignment="Center" Background="Red" Foreground="White" Margin="5"/>
<TextBlock Name="wifiException" Foreground="Gray" Text="Exception:" HorizontalAlignment="Center" IsTextSelectionEnabled="True"/> <TextBlock Name="wifiException" Foreground="Gray" Text="Exception:" HorizontalAlignment="Center" IsTextSelectionEnabled="True"/>
<TextBlock Name="wifiMessage" Foreground="Gray" Text="Message:" HorizontalAlignment="Center" IsTextSelectionEnabled="True"/> <TextBlock Name="wifiMessage" Foreground="Gray" Text="Message:" HorizontalAlignment="Center" IsTextSelectionEnabled="True" TextWrapping="WrapWholeWords"/>
</StackPanel> </StackPanel>
<StackPanel Name="trouble" Visibility="Collapsed" VerticalAlignment="Center"> <StackPanel Name="trouble" Visibility="Collapsed" VerticalAlignment="Center">
<FontIcon FontFamily="Segoe MDL2 Assets" Glyph="&#xE7BA;" FontSize="100" HorizontalAlignment="Center"/> <FontIcon FontFamily="Segoe MDL2 Assets" Glyph="&#xE7BA;" FontSize="100" HorizontalAlignment="Center"/>
<TextBlock Text="We are unable to display the page" FontSize="48" HorizontalAlignment="Center"/> <TextBlock x:Uid="/LoadingPage/err" Text="We are unable to display the page" FontSize="48" HorizontalAlignment="Center" TextWrapping="WrapWholeWords" HorizontalTextAlignment="Center"/>
<TextBlock Text="It could be caused by YouTube internal server error or by application's bug. Please, try again later" HorizontalAlignment="Center"/> <TextBlock x:Uid="/LoadingPage/errDescription" Text="It could be caused by YouTube internal server error or by application's bug. Please, try again later" HorizontalAlignment="Center" HorizontalTextAlignment="Center" TextWrapping="WrapWholeWords"/>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center"> <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Button Name="refresh" Click="wifiRefresh_Click" Content="Refresh page" Margin="5"/> <Button x:Uid="/LoadingPage/refresh" Name="refresh" Click="wifiRefresh_Click" Content="Refresh page" Margin="5"/>
<Button Content="Leave feedback" Background="Red" Foreground="White" Margin="5" Name="feedback" Click="feedback_Click"/> <Button x:Uid="/LoadingPage/feedback" Content="Leave feedback" Background="Red" Foreground="White" Margin="5" Name="feedback" Click="feedback_Click"/>
</StackPanel> </StackPanel>
<TextBlock Name="exception" Foreground="Gray" Text="Exception:" HorizontalAlignment="Center" IsTextSelectionEnabled="True"/> <TextBlock Name="exception" Foreground="Gray" Text="Exception:" HorizontalAlignment="Center" IsTextSelectionEnabled="True"/>
<TextBlock Name="message" Foreground="Gray" Text="Message:" HorizontalAlignment="Center" IsTextSelectionEnabled="True"/> <TextBlock Name="message" Foreground="Gray" Text="Message:" HorizontalAlignment="Center" IsTextSelectionEnabled="True" TextWrapping="WrapWholeWords"/>
</StackPanel> </StackPanel>
<FontIcon Name="blockIcon" Visibility="Collapsed" Glyph="&#xE25B;" FontSize="100" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="Gray"/> <FontIcon Name="blockIcon" Visibility="Collapsed" Glyph="&#xE25B;" FontSize="100" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="Gray"/>
+9 -19
View File
@@ -1,35 +1,25 @@
using System; using System;
using System.Collections.Generic; using Windows.ApplicationModel.Resources;
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.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 namespace FoxTube
{ {
public enum LoadingState { Loadnig, Loaded, Error, Blocked } public enum LoadingState { Loadnig, Loaded, Error, Blocked }
/// <summary> /// <summary>
/// An empty page that can be used on its own or navigated to within a Frame. /// Loading sreen. Represents loading ring or error
/// </summary> /// </summary>
public sealed partial class LoadingPage : Page public sealed partial class LoadingPage : Page
{ {
ResourceLoader resources = ResourceLoader.GetForCurrentView("LoadingPage");
public event RoutedEventHandler RefreshPage; public event RoutedEventHandler RefreshPage;
public LoadingState State { get; private set; } = LoadingState.Loadnig; public LoadingState State { get; private set; } = LoadingState.Loadnig;
public LoadingPage() public LoadingPage()
{ {
this.InitializeComponent(); InitializeComponent();
} }
public void Error(string exceptionId = "Unknown", string details = "N/A", bool isWifiTrouble = false) public void Error(string exceptionId = "Unknown", string details = "N/A", bool isWifiTrouble = false)
@@ -41,15 +31,15 @@ namespace FoxTube
if (isWifiTrouble) if (isWifiTrouble)
{ {
wifiException.Text = $"ID: {exceptionId}"; wifiException.Text = $"{resources.GetString("/LoadingPage/ex")}: {exceptionId}";
wifiMessage.Text = $"Details: {details}"; wifiMessage.Text = $"{resources.GetString("/LoadingPage/details")}: {details}";
wifiTrouble.Visibility = Visibility.Visible; wifiTrouble.Visibility = Visibility.Visible;
} }
else else
{ {
exception.Text = $"ID: {exceptionId}"; exception.Text = $"{resources.GetString("/LoadingPage/ex")}: {exceptionId}";
message.Text = $"Details: {details}"; message.Text = $"{resources.GetString("/LoadingPage/details")}: {details}";
trouble.Visibility = Visibility.Visible; trouble.Visibility = Visibility.Visible;
} }
+1 -1
View File
@@ -36,7 +36,7 @@
</NavigationViewItem.Icon> </NavigationViewItem.Icon>
</NavigationViewItem> </NavigationViewItem>
<NavigationViewItem x:Uid="/Main/adsFree" Content="Remove ads" Visibility="Collapsed" Name="removeAds"> <NavigationViewItem x:Uid="/Main/adsFree" Content="Remove ads" Visibility="Collapsed" Tapped="RemoveAds_Tapped" Name="removeAds">
<NavigationViewItem.Icon> <NavigationViewItem.Icon>
<FontIcon Glyph="&#xE14D;"/> <FontIcon Glyph="&#xE14D;"/>
</NavigationViewItem.Icon> </NavigationViewItem.Icon>
+88 -46
View File
@@ -21,8 +21,9 @@ using System.Net;
using Windows.UI.Popups; using Windows.UI.Popups;
using Windows.Networking.Connectivity; using Windows.Networking.Connectivity;
using Windows.UI.Core; using Windows.UI.Core;
using System.Threading; using Windows.ApplicationModel.Resources;
using System.Threading.Tasks; using Windows.Storage;
using System.IO;
namespace FoxTube namespace FoxTube
{ {
@@ -34,18 +35,39 @@ namespace FoxTube
public sealed partial class MainPage : Page public sealed partial class MainPage : Page
{ {
Sender s = Sender.None; Sender s = Sender.None;
ResourceLoader resources = ResourceLoader.GetForCurrentView("Main");
public MainPage() public MainPage()
{ {
InitializeComponent(); InitializeComponent();
//Comparing current version with last recorded version. If doesn't match, poping up changelog notification CheckVersion();
SecretsVault.AuthorizationStateChanged += AuthorizationStateChanged;
SecretsVault.SubscriptionsChanged += SecretsVault_SubscriptionsChanged;
SecretsVault.Purchased += (sender, e) =>
{
removeAds.Visibility = (e[0] as bool?).Value ? Visibility.Collapsed : Visibility.Visible;
content.Navigate(typeof(Home));
};
SecretsVault.CheckAuthorization();
SecretsVault.CheckAddons();
SetTitleBar();
}
/// <summary>
/// Comparing current version with last recorded version. If doesn't match, poping up changelog notification
/// </summary>
public async void CheckVersion()
{
PackageVersion ver = Package.Current.Id.Version; PackageVersion ver = Package.Current.Id.Version;
if(SettingsStorage.Version != $"{ver.Major}.{ver.Minor}") if (SettingsStorage.Version != $"{ver.Major}.{ver.Minor}")
{ {
try try
{ {
XmlDocument changelog = new XmlDocument(); XmlDocument changelog = new XmlDocument();
changelog.Load("http://foxgame-studio.000webhostapp.com/foxtube-changelog.xml"); StorageFile file = await (await Package.Current.InstalledLocation.GetFolderAsync(@"Assets\Data")).GetFileAsync("Patchnotes.xml");
changelog.Load(await file.OpenStreamForReadAsync());
XmlElement e = changelog["items"].ChildNodes[0] as XmlElement; XmlElement e = changelog["items"].ChildNodes[0] as XmlElement;
ToastNotificationManager.CreateToastNotifier().Show(FoxTube.Background.Notification.GetChangelogToast(e.GetAttribute("version"))); ToastNotificationManager.CreateToastNotifier().Show(FoxTube.Background.Notification.GetChangelogToast(e.GetAttribute("version")));
@@ -57,14 +79,6 @@ namespace FoxTube
Debug.WriteLine("Unable to retrieve changelog"); Debug.WriteLine("Unable to retrieve changelog");
} }
} }
SecretsVault.AuthorizationStateChanged += AuthorizationStateChanged;
SecretsVault.SubscriptionsChanged += SecretsVault_SubscriptionsChanged;
SecretsVault.NotPurchased += () => removeAds.Visibility = Visibility.Visible;
SecretsVault.CheckAuthorization();
SecretsVault.CheckAddons();
SetTitleBar();
} }
public Video GetCurrentItem() public Video GetCurrentItem()
@@ -73,6 +87,12 @@ namespace FoxTube
catch { return null; } catch { return null; }
} }
public string GetPlaylist()
{
try { return (videoPlaceholder.Content as VideoPage).playlistId; }
catch { return null; }
}
public void SetTitleBar() public void SetTitleBar()
{ {
var titleBar = ApplicationView.GetForCurrentView().TitleBar; var titleBar = ApplicationView.GetForCurrentView().TitleBar;
@@ -200,6 +220,9 @@ namespace FoxTube
} }
else if (e[0] as bool? == false) else if (e[0] as bool? == false)
{ {
for (int k = nav.MenuItems.Count - 1; k > 8; k--)
nav.MenuItems.RemoveAt(k);
account.Visibility = Visibility.Visible; account.Visibility = Visibility.Visible;
avatar.Visibility = Visibility.Collapsed; avatar.Visibility = Visibility.Collapsed;
@@ -212,18 +235,16 @@ namespace FoxTube
subsHeader.Visibility = Visibility.Collapsed; subsHeader.Visibility = Visibility.Collapsed;
subsHeader.Visibility = Visibility.Collapsed; subsHeader.Visibility = Visibility.Collapsed;
for(int k = 9; k < nav.MenuItems.Count; k++)
nav.MenuItems.RemoveAt(k);
} }
else else
{ {
MessageDialog dialog = new MessageDialog("We were unabled to retrieve your account information due to weak internet connection or Google servers' problems. PLease, try again later", "Failed to connect"); MessageDialog dialog = new MessageDialog(resources.GetString("/Main/connectErrContent"), resources.GetString("/Main/connectErrHeader"));
dialog.Commands.Add(new UICommand("Try again", (command) => dialog.Commands.Add(new UICommand(resources.GetString("/Main/tryAgain"), (command) =>
{ {
SecretsVault.Authorize(); SecretsVault.Authorize();
})); }));
dialog.Commands.Add(new UICommand("Quit", (command) => dialog.Commands.Add(new UICommand(resources.GetString("/Main/quit"), (command) =>
{ {
Methods.CloseApp(); Methods.CloseApp();
})); }));
@@ -292,15 +313,15 @@ namespace FoxTube
var connection = NetworkInformation.GetInternetConnectionProfile().GetConnectionCost(); var connection = NetworkInformation.GetInternetConnectionProfile().GetConnectionCost();
if (SettingsStorage.CheckConnection && (connection.NetworkCostType == NetworkCostType.Fixed || connection.NetworkCostType == NetworkCostType.Variable)) if (SettingsStorage.CheckConnection && (connection.NetworkCostType == NetworkCostType.Fixed || connection.NetworkCostType == NetworkCostType.Variable))
{ {
MessageDialog dialog = new MessageDialog("You are on metered connection now. Additional charges may apply. Do you want to continue?") MessageDialog dialog = new MessageDialog(resources.GetString("/Main/metered"))
{ {
DefaultCommandIndex = 2, DefaultCommandIndex = 2,
CancelCommandIndex = 1 CancelCommandIndex = 1
}; };
dialog.Commands.Add(new UICommand("Yes")); dialog.Commands.Add(new UICommand(resources.GetString("/Main/yes")));
dialog.Commands.Add(new UICommand("No", (command) => cancel = true)); dialog.Commands.Add(new UICommand(resources.GetString("/Main/no"), (command) => cancel = true));
if(SecretsVault.IsAuthorized) if(SecretsVault.IsAuthorized)
dialog.Commands.Add(new UICommand("Add to 'Watch later' playlist", (command) => dialog.Commands.Add(new UICommand(resources.GetString("/Main/addLater"), (command) =>
{ {
try try
{ {
@@ -333,6 +354,9 @@ namespace FoxTube
if (cancel) if (cancel)
return; return;
if (videoPlaceholder.Content != null)
(videoPlaceholder.Content as VideoPage).player.close_Click(this, null);
videoPlaceholder.Content = null; videoPlaceholder.Content = null;
Fullscreen(false); Fullscreen(false);
@@ -390,14 +414,14 @@ namespace FoxTube
Dictionary<Type, Action> switchCase = new Dictionary<Type, Action>() Dictionary<Type, Action> switchCase = new Dictionary<Type, Action>()
{ {
{ typeof(Settings), () => nav.Header = "Settings" }, { typeof(Settings), () => nav.Header = resources.GetString("/Main/settings/Content") },
{ typeof(ChannelPage), () => nav.Header = "Channel" }, { typeof(ChannelPage), () => nav.Header = resources.GetString("/Main/channel") },
{ typeof(PlaylistPage), () => nav.Header = "Playlist" }, { typeof(PlaylistPage), () => nav.Header = resources.GetString("/Main/playlist") },
{ typeof(Search), () => nav.Header = "Search" }, { typeof(Search), () => nav.Header = resources.GetString("/Main/searchPlaceholder/PlaceholderText") },
{ typeof(Subscriptions), () => nav.Header = "Subscriptions" }, { typeof(Subscriptions), () => nav.Header = resources.GetString("/Main/subscriptions/Content") },
{ typeof(History), () => nav.Header = "History" }, { typeof(History), () => nav.Header = resources.GetString("/Main/history/Content") },
{ typeof(Home), () => nav.Header = "Home" }, { typeof(Home), () => nav.Header = resources.GetString("/Main/home/Content") },
{ typeof(Downloads), () => nav.Header = "Downloads" } { typeof(Downloads), () => nav.Header = resources.GetString("/Main/downloads/Content") }
}; };
if (content.SourcePageType == typeof(Home) || content.SourcePageType == typeof(Settings) || content.SourcePageType == typeof(Subscriptions)) if (content.SourcePageType == typeof(Home) || content.SourcePageType == typeof(Settings) || content.SourcePageType == typeof(Subscriptions))
@@ -425,7 +449,7 @@ namespace FoxTube
if (videoPlaceholder.Content != null) if (videoPlaceholder.Content != null)
{ {
nav.Header = "Video"; nav.Header = resources.GetString("/Main/video");
nav.ExpandedModeThresholdWidth = short.MaxValue; nav.ExpandedModeThresholdWidth = short.MaxValue;
nav.IsPaneOpen = false; nav.IsPaneOpen = false;
} }
@@ -437,24 +461,37 @@ namespace FoxTube
{ {
nav.CompactModeThresholdWidth = short.MaxValue; nav.CompactModeThresholdWidth = short.MaxValue;
nav.ExpandedModeThresholdWidth = short.MaxValue; nav.ExpandedModeThresholdWidth = short.MaxValue;
nav.OpenPaneLength = 0; try
{
nav.IsPaneVisible = false;
}
catch
{
nav.CompactPaneLength = 0; nav.CompactPaneLength = 0;
nav.OpenPaneLength = 0;
}
nav.Margin = new Thickness(0, -45, 0, 0); nav.Margin = new Thickness(0, -45, 0, 0);
} }
else else
{ {
nav.CompactModeThresholdWidth = 641; nav.CompactModeThresholdWidth = 641;
if(videoPlaceholder.Content == null)
nav.ExpandedModeThresholdWidth = 1008; nav.ExpandedModeThresholdWidth = 1008;
nav.Margin = new Thickness(0); nav.Margin = new Thickness(0);
try
{
nav.IsPaneVisible = true;
}
catch
{
nav.CompactPaneLength = new NavigationView().CompactPaneLength;
nav.OpenPaneLength = new NavigationView().OpenPaneLength; ;
}
if (videoPlaceholder.Content != null && nav.IsPaneOpen) if (videoPlaceholder.Content != null && nav.IsPaneOpen)
nav.IsPaneOpen = false; nav.IsPaneOpen = false;
else
{
nav.OpenPaneLength = 300;
nav.CompactPaneLength = 40;
}
SetTitleBar(); SetTitleBar();
} }
nav.UpdateLayout();
} }
public void CloseVideo() public void CloseVideo()
@@ -464,8 +501,8 @@ namespace FoxTube
ApplicationView.GetForCurrentView().ExitFullScreenMode(); ApplicationView.GetForCurrentView().ExitFullScreenMode();
Fullscreen(false); Fullscreen(false);
} }
(videoPlaceholder.Content as VideoPage).player.pointerCaptured = false;
videoPlaceholder.Content = null; videoPlaceholder.Content = null;
GC.Collect();
Window.Current.CoreWindow.PointerCursor = new CoreCursor(CoreCursorType.Arrow, 0); Window.Current.CoreWindow.PointerCursor = new CoreCursor(CoreCursorType.Arrow, 0);
MaximizeVideo(); MaximizeVideo();
@@ -544,14 +581,14 @@ namespace FoxTube
{ {
Dictionary<Type, Action> switchCase = new Dictionary<Type, Action>() Dictionary<Type, Action> switchCase = new Dictionary<Type, Action>()
{ {
{ typeof(Settings), () => nav.Header = "Settings" }, { typeof(Settings), () => nav.Header = resources.GetString("/Main/settings/Content") },
{ typeof(ChannelPage), () => nav.Header = "Channel" }, { typeof(ChannelPage), () => nav.Header = resources.GetString("/Main/channel") },
{ typeof(PlaylistPage), () => nav.Header = "Playlist" }, { typeof(PlaylistPage), () => nav.Header = resources.GetString("/Main/playlist") },
{ typeof(Search), () => nav.Header = "Search" }, { typeof(Search), () => nav.Header = resources.GetString("/Main/searchPlaceholder/PlaceholderText") },
{ typeof(Subscriptions), () => nav.Header = "Subscriptions" }, { typeof(Subscriptions), () => nav.Header = resources.GetString("/Main/subscriptions/Content") },
{ typeof(History), () => nav.Header = "History" }, { typeof(History), () => nav.Header = resources.GetString("/Main/history/Content") },
{ typeof(Home), () => nav.Header = "Home" }, { typeof(Home), () => nav.Header = resources.GetString("/Main/home/Content") },
{ typeof(Downloads), () => nav.Header = "Downloads" } { typeof(Downloads), () => nav.Header = resources.GetString("/Main/downloads/Content") }
}; };
try { switchCase[e.SourcePageType](); } try { switchCase[e.SourcePageType](); }
@@ -724,5 +761,10 @@ namespace FoxTube
{ {
((NavigationViewItem)sender).ContextFlyout.ShowAt((NavigationViewItem)sender); ((NavigationViewItem)sender).ContextFlyout.ShowAt((NavigationViewItem)sender);
} }
private void RemoveAds_Tapped(object sender, TappedRoutedEventArgs e)
{
SecretsVault.GetAdblock();
}
} }
} }
+4 -4
View File
@@ -63,16 +63,16 @@
</ScrollViewer> </ScrollViewer>
<CommandBar Grid.Row="2" Grid.ColumnSpan="2"> <CommandBar Grid.Row="2" Grid.ColumnSpan="2">
<AppBarButton Icon="Globe" Label="Open in browser" Name="inBrowser" Click="inBrowser_Click"/> <AppBarButton x:Uid="/Playlist/openWeb" Icon="Globe" Label="Open in browser" Name="inBrowser" Click="inBrowser_Click"/>
<AppBarButton Icon="Add" Label="Add to" IsEnabled="False"> <AppBarButton x:Uid="/Playlist/addTo" Icon="Add" Label="Add to" IsEnabled="False">
<AppBarButton.Flyout> <AppBarButton.Flyout>
<MenuFlyout> <MenuFlyout>
</MenuFlyout> </MenuFlyout>
</AppBarButton.Flyout> </AppBarButton.Flyout>
</AppBarButton> </AppBarButton>
<AppBarButton Icon="Refresh" Label="Refresh" Name="refresh" Click="refresh_Click"/> <AppBarButton x:Uid="/Playlist/refresh" Icon="Refresh" Label="Refresh" Name="refresh" Click="refresh_Click"/>
<AppBarButton Icon="Share" Label="Share" Name="share" Click="share_Click"/> <AppBarButton x:Uid="/Playlist/share" Icon="Share" Label="Share" Name="share" Click="share_Click"/>
</CommandBar> </CommandBar>
<foxtube:LoadingPage Grid.RowSpan="2" Visibility="Collapsed"/> <foxtube:LoadingPage Grid.RowSpan="2" Visibility="Collapsed"/>
+3 -2
View File
@@ -3,6 +3,7 @@ using Google.Apis.YouTube.v3;
using Google.Apis.YouTube.v3.Data; using Google.Apis.YouTube.v3.Data;
using System; using System;
using Windows.ApplicationModel.DataTransfer; using Windows.ApplicationModel.DataTransfer;
using Windows.ApplicationModel.Resources;
using Windows.Foundation; using Windows.Foundation;
using Windows.System; using Windows.System;
using Windows.UI.Xaml; using Windows.UI.Xaml;
@@ -57,7 +58,7 @@ namespace FoxTube.Pages
item = (await request.ExecuteAsync()).Items[0]; item = (await request.ExecuteAsync()).Items[0];
title.Text = item.Snippet.Title; title.Text = item.Snippet.Title;
info.Text = $"{item.ContentDetails.ItemCount} videos"; info.Text = $"{item.ContentDetails.ItemCount} {ResourceLoader.GetForCurrentView("Playlist").GetString("/Playlist/videos")}";
description.Text = item.Snippet.Description; description.Text = item.Snippet.Description;
channelName.Text = item.Snippet.ChannelTitle; channelName.Text = item.Snippet.ChannelTitle;
@@ -129,7 +130,7 @@ namespace FoxTube.Pages
item.Snippet.Thumbnails.Medium.Url, item.Snippet.Thumbnails.Medium.Url,
item.Snippet.Title, item.Snippet.Title,
$"https://www.youtube.com/playlist?list={item.Id}", $"https://www.youtube.com/playlist?list={item.Id}",
"playlist"); ResourceLoader.GetForCurrentView("Cards").GetString("/Cards/playlistShare"));
} }
} }
} }
+30 -30
View File
@@ -19,52 +19,52 @@
<TextBlock Name="searchTerm" Text="Search results for: [searchTerm]" FontSize="28"/> <TextBlock Name="searchTerm" Text="Search results for: [searchTerm]" FontSize="28"/>
<TextBlock Name="resultsCount" Text="Found: [resultCount] item(s)" FontSize="14" Foreground="Gray"/> <TextBlock Name="resultsCount" Text="Found: [resultCount] item(s)" FontSize="14" Foreground="Gray"/>
<HyperlinkButton Name="toggleFilters" Click="toggleFilters_Click" Content="Show filters &#xE71C;" FontFamily="Default, Segoe MDL2 Assets" Visibility="Visible"/> <HyperlinkButton x:Uid="/Search/filters" Name="toggleFilters" Click="toggleFilters_Click" Content="Show filters &#xE71C;" FontFamily="Default, Segoe MDL2 Assets" Visibility="Visible"/>
<StackPanel Name="filters" Visibility="Collapsed"> <StackPanel Name="filters" Visibility="Collapsed">
<GridView Padding="5" SelectionMode="None"> <GridView Padding="5" SelectionMode="None">
<ComboBox Name="order" Header="Sort by" Width="150" SelectedIndex="0"> <ComboBox x:Uid="/Search/order" Name="order" Header="Sort by" Width="150" SelectedIndex="0">
<ComboBoxItem Content="Relevance"/> <ComboBoxItem x:Uid="/Search/relevance" Content="Relevance"/>
<ComboBoxItem Content="Upload date"/> <ComboBoxItem x:Uid="/Search/update" Content="Upload date"/>
<ComboBoxItem Content="View count"/> <ComboBoxItem x:Uid="/Search/views" Content="View count"/>
<ComboBoxItem Content="Rating"/> <ComboBoxItem x:Uid="/Search/rating" Content="Rating"/>
<ComboBoxItem Content="Title"/> <ComboBoxItem x:Uid="/Search/title" Content="Title"/>
</ComboBox> </ComboBox>
<ComboBox Name="type" Header="Type" Width="150" SelectedIndex="0" SelectionChanged="type_SelectionChanged"> <ComboBox x:Uid="/Search/type" Name="type" Header="Type" Width="150" SelectedIndex="0" SelectionChanged="type_SelectionChanged">
<ComboBoxItem Content="All"/> <ComboBoxItem x:Uid="/Search/all" Content="All"/>
<ComboBoxItem Content="Video"/> <ComboBoxItem x:Uid="/Search/video" Content="Video"/>
<ComboBoxItem Content="Channel"/> <ComboBoxItem x:Uid="/Search/channel" Content="Channel"/>
<ComboBoxItem Content="Playlist"/> <ComboBoxItem x:Uid="/Search/playlist" Content="Playlist"/>
</ComboBox> </ComboBox>
<ComboBox Name="date" Header="Upload date" Width="150" SelectedIndex="0"> <ComboBox x:Uid="/Search/updateHeader" Name="date" Header="Upload date" Width="150" SelectedIndex="0">
<ComboBoxItem Content="Anytime"/> <ComboBoxItem x:Uid="/Search/anytime" Content="Anytime"/>
<ComboBoxItem Content="Last hour"/> <ComboBoxItem x:Uid="/Search/lasthr" Content="Last hour"/>
<ComboBoxItem Content="Today"/> <ComboBoxItem x:Uid="/Search/today" Content="Today"/>
<ComboBoxItem Content="This week"/> <ComboBoxItem x:Uid="/Search/week" Content="This week"/>
<ComboBoxItem Content="This month"/> <ComboBoxItem x:Uid="/Search/month" Content="This month"/>
<ComboBoxItem Content="This year"/> <ComboBoxItem x:Uid="/Search/year" Content="This year"/>
</ComboBox> </ComboBox>
<ComboBox Visibility="Collapsed" Name="duration" Header="Duration" Width="150" SelectedIndex="0"> <ComboBox x:Uid="/Search/duration" Visibility="Collapsed" Name="duration" Header="Duration" Width="150" SelectedIndex="0">
<ComboBoxItem Content="Any"/> <ComboBoxItem x:Uid="/Search/any" Content="Any"/>
<ComboBoxItem Content="Long (&#x3E; 20 minutes)"/> <ComboBoxItem x:Uid="/Search/long" Content="Long (&#x3E; 20 minutes)"/>
<ComboBoxItem Content="Medium"/> <ComboBoxItem x:Uid="/Search/medium" Content="Medium"/>
<ComboBoxItem Content="Short (&#x3C; 4 minutes)"/> <ComboBoxItem x:Uid="/Search/short" Content="Short (&#x3C; 4 minutes)"/>
</ComboBox> </ComboBox>
</GridView> </GridView>
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<Button Visibility="Collapsed" Content="Features" Name="featBtn" Margin="10,0,0,10"> <Button x:Uid="/Search/features" Visibility="Collapsed" Content="Features" Name="featBtn" Margin="10,0,0,10">
<Button.Flyout> <Button.Flyout>
<Flyout> <Flyout>
<ListView Name="features" SelectionMode="Multiple" Header="Features"> <ListView x:Uid="/Search/featuresHeader" Name="features" SelectionMode="Multiple" Header="Features">
<TextBlock Text="HD"/> <TextBlock Text="HD"/>
<TextBlock Text="3D"/> <TextBlock Text="3D"/>
<TextBlock Text="Subtitles/CC"/> <TextBlock x:Uid="/Search/subs" Text="Subtitles/CC"/>
<TextBlock Text="Live"/> <TextBlock x:Uid="/Search/live" Text="Live"/>
<TextBlock Text="Creative Commons"/> <TextBlock x:Uid="/Search/cc" Text="Creative Commons"/>
</ListView> </ListView>
</Flyout> </Flyout>
</Button.Flyout> </Button.Flyout>
</Button> </Button>
<Button Content="Apply" Margin="10,0,0,10" Name="apply" Click="apply_Click"/> <Button x:Uid="/Search/apply" Content="Apply" Margin="10,0,0,10" Name="apply" Click="apply_Click"/>
</StackPanel> </StackPanel>
</StackPanel> </StackPanel>
<pages:VideoGrid/> <pages:VideoGrid/>
+10 -8
View File
@@ -8,7 +8,7 @@ using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation; using Windows.UI.Xaml.Navigation;
using Windows.System; using Windows.System;
using System.Globalization; using Windows.ApplicationModel.Resources;
namespace FoxTube namespace FoxTube
{ {
@@ -17,6 +17,8 @@ namespace FoxTube
/// </summary> /// </summary>
public sealed partial class Search : Page public sealed partial class Search : Page
{ {
ResourceLoader resources = ResourceLoader.GetForCurrentView("Search");
public SearchParameters Parameters; public SearchParameters Parameters;
SearchResource.ListRequest request; SearchResource.ListRequest request;
string nextToken; string nextToken;
@@ -95,10 +97,10 @@ namespace FoxTube
(grid.Children[1] as CommandBar).Visibility = Visibility.Collapsed; (grid.Children[1] as CommandBar).Visibility = Visibility.Collapsed;
} }
request.Q = arg.Term; request.Q = arg.Term;
request.SafeSearch = (SearchResource.ListRequest.SafeSearchEnum)(int)settings.Values["safeSearch"]; request.SafeSearch = (SearchResource.ListRequest.SafeSearchEnum)SettingsStorage.SafeSearch;
request.RegionCode = CultureInfo.GetCultures(CultureTypes.AllCultures).Find(i => i.IetfLanguageTag == SettingsStorage.Region).IetfLanguageTag.Remove(0, 3); request.RegionCode = SettingsStorage.Region;
request.RelevanceLanguage = CultureInfo.GetCultures(CultureTypes.AllCultures).Find(i => i.IetfLanguageTag == SettingsStorage.Region).TwoLetterISOLanguageName; request.RelevanceLanguage = SettingsStorage.RelevanceLanguage;
request.MaxResults = 48; request.MaxResults = 48;
try try
@@ -130,8 +132,8 @@ namespace FoxTube
features.SelectedItems.Add(features.Items[4]); features.SelectedItems.Add(features.Items[4]);
SearchListResponse response = await request.ExecuteAsync(); SearchListResponse response = await request.ExecuteAsync();
searchTerm.Text = $"Search results for: {Parameters.Term}"; searchTerm.Text = $"{resources.GetString("/Search/header")} '{Parameters.Term}'";
resultsCount.Text = $"Found: {SetResults(response.PageInfo.TotalResults)} item(s)"; resultsCount.Text = $"{resources.GetString("/Search/found")}: {SetResults(response.PageInfo.TotalResults)} {resources.GetString("/Search/items")}";
if (!string.IsNullOrWhiteSpace(response.NextPageToken)) if (!string.IsNullOrWhiteSpace(response.NextPageToken))
nextToken = response.NextPageToken; nextToken = response.NextPageToken;
else else
@@ -158,12 +160,12 @@ namespace FoxTube
if(filters.Visibility == Visibility.Collapsed) if(filters.Visibility == Visibility.Collapsed)
{ {
filters.Visibility = Visibility.Visible; filters.Visibility = Visibility.Visible;
toggleFilters.Content = "Hide filters \xE014"; toggleFilters.Content = resources.GetString("/Search/hideFilters");
} }
else else
{ {
filters.Visibility = Visibility.Collapsed; filters.Visibility = Visibility.Collapsed;
toggleFilters.Content = "Show filters \xE015"; toggleFilters.Content = resources.GetString("/Search/filters/Content");
} }
} }
+1 -1
View File
@@ -44,7 +44,7 @@
<TextBlock Visibility="Collapsed" Margin="0,0,0,10"> <Run x:Uid="/About/myBlog">My blog (Russian language only):</Run> <Hyperlink NavigateUri="https://michael-xfox.com">https://michael-xfox.com</Hyperlink></TextBlock> <TextBlock Visibility="Collapsed" Margin="0,0,0,10"> <Run x:Uid="/About/myBlog">My blog (Russian language only):</Run> <Hyperlink NavigateUri="https://michael-xfox.com">https://michael-xfox.com</Hyperlink></TextBlock>
<TextBlock x:Uid="/About/legal" Text="Legal stuff" FontSize="22" FontWeight="SemiBold"/> <TextBlock x:Uid="/About/legal" Text="Legal stuff" FontSize="22" FontWeight="SemiBold"/>
<HyperlinkButton x:Uid="/About/ourPrivacy" Content="Our Privacy Policy" NavigateUri="https://michael-xfox.com/foxtubepp.txt" Padding="0,5,0,0"/> <HyperlinkButton x:Uid="/About/ourPrivacy" Content="Our Privacy Policy" NavigateUri="https://foxgame-studio.000webhostapp.com/FoxTubeAssets/PrivacyPolicy.txt" Padding="0,5,0,0"/>
<HyperlinkButton x:Uid="/About/ytPrivacy" Content="YouTube Privacy Policy" NavigateUri="https://youtube.com/t/privacy" Padding="0"/> <HyperlinkButton x:Uid="/About/ytPrivacy" Content="YouTube Privacy Policy" NavigateUri="https://youtube.com/t/privacy" Padding="0"/>
<HyperlinkButton x:Uid="/About/terms" Content="YouTube Terms of use" NavigateUri="https://youtube.com/t/terms" Padding="0"/> <HyperlinkButton x:Uid="/About/terms" Content="YouTube Terms of use" NavigateUri="https://youtube.com/t/terms" Padding="0"/>
<HyperlinkButton x:Uid="/About/guides" Content="YouTube Community Guidelines" NavigateUri="https://youtube.com/t/community_guidelines" Padding="0,0,0,10"/> <HyperlinkButton x:Uid="/About/guides" Content="YouTube Community Guidelines" NavigateUri="https://youtube.com/t/community_guidelines" Padding="0,0,0,10"/>
+2 -8
View File
@@ -19,6 +19,7 @@
<TextBlock x:Uid="/General/restart" Foreground="Red" Text="Reopen the app to apply settings"/> <TextBlock x:Uid="/General/restart" Foreground="Red" Text="Reopen the app to apply settings"/>
<Button x:Uid="/General/closeApp" Content="Close app" Background="Red" Margin="5" Click="Button_Click"/> <Button x:Uid="/General/closeApp" Content="Close app" Background="Red" Margin="5" Click="Button_Click"/>
</StackPanel> </StackPanel>
<ComboBox Header="Search relevance language" MinWidth="250" Name="relLanguage" SelectionChanged="RelLanguage_SelectionChanged"/>
<ComboBox x:Uid="/General/region" Header="Region" MinWidth="250" Name="region" SelectionChanged="region_SelectionChanged"/> <ComboBox x:Uid="/General/region" Header="Region" MinWidth="250" Name="region" SelectionChanged="region_SelectionChanged"/>
<ComboBox x:Uid="/General/safeSearch" Header="SafeSearch" MinWidth="250" Name="safeSearch" SelectionChanged="safeSearch_SelectionChanged"> <ComboBox x:Uid="/General/safeSearch" Header="SafeSearch" MinWidth="250" Name="safeSearch" SelectionChanged="safeSearch_SelectionChanged">
<ComboBoxItem x:Uid="/General/moderate" Content="Moderate"/> <ComboBoxItem x:Uid="/General/moderate" Content="Moderate"/>
@@ -29,20 +30,13 @@
<TextBlock x:Uid="/General/playback" Text="Playback" FontSize="22"/> <TextBlock x:Uid="/General/playback" Text="Playback" FontSize="22"/>
<ComboBox x:Uid="/General/quality" Width="250" Header="Default video playback quality" Name="quality" SelectionChanged="quality_SelectionChanged"> <ComboBox x:Uid="/General/quality" Width="250" Header="Default video playback quality" Name="quality" SelectionChanged="quality_SelectionChanged">
<ComboBoxItem Tag="remember" x:Uid="/General/remember" Content="Remember my choice"/> <ComboBoxItem Tag="remember" x:Uid="/General/remember" Content="Remember my choice"/>
<ComboBoxItem Tag="2160p" Content="2160p"/>
<ComboBoxItem Tag="1080p" Content="1080p"/>
<ComboBoxItem Tag="720p" Content="720p"/>
<ComboBoxItem Tag="480p" Content="480p"/>
<ComboBoxItem Tag="360p" Content="360p"/>
<ComboBoxItem Tag="240p" Content="240p"/>
<ComboBoxItem Tag="144p" Content="144p"/>
</ComboBox> </ComboBox>
<ToggleSwitch x:Uid="/General/metered" OnContent="Notify when playing on metered connection" OffContent="Notify when playing on metered connection" Name="mobileWarning" Toggled="mobileWarning_Toggled"/> <ToggleSwitch x:Uid="/General/metered" OnContent="Notify when playing on metered connection" OffContent="Notify when playing on metered connection" Name="mobileWarning" Toggled="mobileWarning_Toggled"/>
<ToggleSwitch x:Uid="/General/autoplay" OnContent="Play videos automatically" OffContent="Play videos automatically" Name="autoplay" Toggled="autoplay_Toggled"/> <ToggleSwitch x:Uid="/General/autoplay" OnContent="Play videos automatically" OffContent="Play videos automatically" Name="autoplay" Toggled="autoplay_Toggled"/>
<TextBlock x:Uid="/General/notifications" Text="Notifications" FontSize="22"/> <TextBlock x:Uid="/General/notifications" Text="Notifications" FontSize="22"/>
<ToggleSwitch x:Uid="/General/newVideo" Name="newVideo" OnContent="Notify when someone of your subscriptions uploaded new video" OffContent="Notify when someone of your subscriptions uploaded new video" Toggled="notification_IsEnabledChanged"/> <ToggleSwitch x:Uid="/General/newVideo" Name="newVideo" OnContent="Notify when someone of your subscriptions uploaded new video" OffContent="Notify when someone of your subscriptions uploaded new video" Toggled="notification_IsEnabledChanged"/>
<ToggleSwitch Name="devNews" OnContent="Recieve messages from developers" OffContent="Recieve messages from developers" Toggled="devNews_Toggled"/> <ToggleSwitch x:Uid="/General/devNotifications" Name="devNews" OnContent="Recieve messages from developers" OffContent="Recieve messages from developers" Toggled="devNews_Toggled"/>
<TextBlock x:Uid="/General/color" Text="Color mode" FontSize="22"/> <TextBlock x:Uid="/General/color" Text="Color mode" FontSize="22"/>
<RadioButton x:Uid="/General/colorLight" Content="Light" Name="light" GroupName="color" Checked="RadioButton_Checked"/> <RadioButton x:Uid="/General/colorLight" Content="Light" Name="light" GroupName="color" Checked="RadioButton_Checked"/>
+44 -13
View File
@@ -1,9 +1,12 @@
using System.Globalization; using System.Linq;
using System.Linq;
using Windows.ApplicationModel.Core; using Windows.ApplicationModel.Core;
using Windows.UI; using Windows.UI;
using Windows.UI.Xaml; using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls;
using Google.Apis.YouTube.v3;
using Google.Apis.YouTube.v3.Data;
using YoutubeExplode.Models.MediaStreams;
using System;
namespace FoxTube.Pages.SettingsPages namespace FoxTube.Pages.SettingsPages
{ {
@@ -17,18 +20,10 @@ namespace FoxTube.Pages.SettingsPages
InitializeComponent(); InitializeComponent();
language.SelectedItem = language.Items.Find(i => ((ComboBoxItem)i).Tag.ToString() == SettingsStorage.Language); language.SelectedItem = language.Items.Find(i => ((ComboBoxItem)i).Tag.ToString() == SettingsStorage.Language);
CultureInfo.GetCultures(CultureTypes.AllCultures).FindAll(i => !i.IsNeutralCulture).ForEach(i =>
{
region.Items.Add(new ComboBoxItem
{
Content = i.DisplayName,
Tag = i.IetfLanguageTag
});
if (i.IetfLanguageTag == SettingsStorage.Region)
region.SelectedItem = region.Items.Last();
});
safeSearch.SelectedIndex = SettingsStorage.SafeSearch; safeSearch.SelectedIndex = SettingsStorage.SafeSearch;
foreach (VideoQuality i in Enum.GetValues(typeof(VideoQuality)).ToReversedList())
quality.Items.Add(new ComboBoxItem() { Tag = i.GetVideoQualityLabel(), Content = i.GetVideoQualityLabel() });
quality.SelectedItem = quality.Items.ToList().Find(i => ((ComboBoxItem)i).Tag.ToString() == SettingsStorage.VideoQuality); quality.SelectedItem = quality.Items.ToList().Find(i => ((ComboBoxItem)i).Tag.ToString() == SettingsStorage.VideoQuality);
mobileWarning.IsOn = SettingsStorage.CheckConnection; mobileWarning.IsOn = SettingsStorage.CheckConnection;
autoplay.IsOn = SettingsStorage.Autoplay; autoplay.IsOn = SettingsStorage.Autoplay;
@@ -48,6 +43,37 @@ namespace FoxTube.Pages.SettingsPages
system.IsChecked = true; system.IsChecked = true;
break; break;
} }
InitializeRegions();
}
async void InitializeRegions()
{
I18nRegionsResource.ListRequest regRequest = SecretsVault.Service.I18nRegions.List("snippet");
I18nRegionListResponse regResponse = await regRequest.ExecuteAsync();
foreach(I18nRegion i in regResponse.Items)
{
region.Items.Add(new ComboBoxItem
{
Content = i.Snippet.Name,
Tag = i.Snippet.Gl
});
if (SettingsStorage.Region == i.Snippet.Gl)
region.SelectedItem = region.Items.Last();
}
I18nLanguagesResource.ListRequest langRequest = SecretsVault.Service.I18nLanguages.List("snippet");
I18nLanguageListResponse langResponse = await langRequest.ExecuteAsync();
foreach(I18nLanguage i in langResponse.Items)
{
relLanguage.Items.Add(new ComboBoxItem
{
Content = i.Snippet.Name,
Tag = i.Snippet.Hl
});
if (SettingsStorage.RelevanceLanguage == i.Snippet.Hl)
relLanguage.SelectedItem = relLanguage.Items.Last();
}
} }
private void language_SelectionChanged(object sender, SelectionChangedEventArgs e) private void language_SelectionChanged(object sender, SelectionChangedEventArgs e)
@@ -79,9 +105,14 @@ namespace FoxTube.Pages.SettingsPages
SettingsStorage.VideoNotifications = newVideo.IsOn; SettingsStorage.VideoNotifications = newVideo.IsOn;
} }
private void RelLanguage_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
SettingsStorage.RelevanceLanguage = ((ComboBoxItem)relLanguage.SelectedItem).Tag.ToString();
}
private void region_SelectionChanged(object sender, SelectionChangedEventArgs e) private void region_SelectionChanged(object sender, SelectionChangedEventArgs e)
{ {
SettingsStorage.Region = CultureInfo.GetCultures(CultureTypes.AllCultures)[region.SelectedIndex].Name; SettingsStorage.Region = ((ComboBoxItem)region.SelectedItem).Tag.ToString();
} }
private void safeSearch_SelectionChanged(object sender, SelectionChangedEventArgs e) private void safeSearch_SelectionChanged(object sender, SelectionChangedEventArgs e)
+9 -19
View File
@@ -2,56 +2,46 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; 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.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using FoxTube.Classes; using FoxTube.Classes;
using System.Xml;
using Windows.Storage; using Windows.Storage;
using System.Diagnostics; using System.Diagnostics;
using Windows.UI.Popups; using System.Xml;
// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238
namespace FoxTube.Pages.SettingsPages namespace FoxTube.Pages.SettingsPages
{ {
/// <summary> /// <summary>
/// An empty page that can be used on its own or navigated to within a Frame. /// Page with changelogs and dev messages
/// </summary> /// </summary>
public sealed partial class Inbox : Page public sealed partial class Inbox : Page
{ {
List<InboxItem> items = new List<InboxItem>(); List<InboxItem> items = new List<InboxItem>();
public Inbox() public Inbox()
{ {
this.InitializeComponent(); InitializeComponent();
} }
public void LoadItems() public async void LoadItems()
{ {
try try
{ {
XmlDocument doc = new XmlDocument(); XmlDocument doc = new XmlDocument();
doc.Load("http://foxgame-studio.000webhostapp.com/foxtube-changelog.xml"); StorageFile file = await (await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFolderAsync(@"Assets\Data")).GetFileAsync("Patchnotes.xml");
doc.Load(await file.OpenStreamForReadAsync());
foreach (XmlElement e in doc["items"].ChildNodes) foreach (XmlElement e in doc["items"].ChildNodes)
items.Add(new InboxItem( items.Add(new InboxItem(
e.GetAttribute("version"), e.GetAttribute("version"),
e["content"].InnerText, e["content"][SettingsStorage.Language].InnerText,
e.GetAttribute("time"))); e.GetAttribute("time")));
doc.Load("http://foxgame-studio.000webhostapp.com/foxtube-messages.xml"); doc.Load("http://foxgame-studio.000webhostapp.com/foxtube-messages.xml");
foreach (XmlElement e in doc["posts"].ChildNodes) foreach (XmlElement e in doc["posts"].ChildNodes)
items.Add(new InboxItem( items.Add(new InboxItem(
e["header"].InnerText, e["header"].InnerText,
e["content"].InnerText, e["content"][SettingsStorage.Language].InnerText,
DateTime.Parse(e["time"].InnerText), DateTime.Parse(e.GetAttribute("time")),
e["id"].InnerText e["id"].InnerText
)); ));
+5 -19
View File
@@ -1,39 +1,25 @@
using System; using FoxTube.Controls.Adverts;
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.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation; using Windows.UI.Xaml.Navigation;
using System.Diagnostics;
using System.Timers;
using Windows.UI.Core;
using Microsoft.Toolkit.Uwp.UI.Controls;
// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238
namespace FoxTube.Pages namespace FoxTube.Pages
{ {
/// <summary> /// <summary>
/// An empty page that can be used on its own or navigated to within a Frame. /// Items cards container
/// </summary> /// </summary>
public sealed partial class VideoGrid : Page public sealed partial class VideoGrid : Page
{ {
public VideoGrid() public VideoGrid()
{ {
this.InitializeComponent(); InitializeComponent();
} }
public void Add(UIElement card) public void Add(UIElement card)
{ {
list.Items.Add(card); list.Items.Add(card);
/*if (list.Items.Count % 10 == 0)
list.Items.Add(new CardAdvert());*/
empty.Visibility = Visibility.Collapsed; empty.Visibility = Visibility.Collapsed;
} }
+10 -37
View File
@@ -6,8 +6,6 @@
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:pages="using:FoxTube.Pages" xmlns:pages="using:FoxTube.Pages"
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
xmlns:ui="using:Microsoft.Advertising.WinRT.UI"
xmlns:controls1="using:FoxTube.Controls" xmlns:controls1="using:FoxTube.Controls"
mc:Ignorable="d"> mc:Ignorable="d">
@@ -37,12 +35,6 @@
<local:VideoPlayer/> <local:VideoPlayer/>
<PivotItem Header="Description" Name="descriptionPanel"> <PivotItem Header="Description" Name="descriptionPanel">
<StackPanel Margin="0,10"> <StackPanel Margin="0,10">
<Button Visibility="Collapsed">
<StackPanel Orientation="Horizontal">
<FontIcon Glyph="&#xE1AD;" Margin="0,0,10,0"/>
<TextBlock Text="Continue watching from HH:MM:SS"/>
</StackPanel>
</Button>
<TextBlock IsTextSelectionEnabled="True" Name="title" Text="[Video title]" FontSize="25" TextWrapping="WrapWholeWords" HorizontalTextAlignment="Start"/> <TextBlock IsTextSelectionEnabled="True" Name="title" Text="[Video title]" FontSize="25" TextWrapping="WrapWholeWords" HorizontalTextAlignment="Start"/>
<Grid> <Grid>
<Grid.RowDefinitions> <Grid.RowDefinitions>
@@ -55,7 +47,7 @@
<StackPanel Orientation="Vertical" Grid.Column="1" Padding="5" VerticalAlignment="Center"> <StackPanel Orientation="Vertical" Grid.Column="1" Padding="5" VerticalAlignment="Center">
<TextBlock Name="channelName" Text="[Channel name]" FontSize="18"/> <TextBlock Name="channelName" Text="[Channel name]" FontSize="18"/>
<TextBlock Name="subscribers" Text="[subscribers]" Foreground="Gray" Margin="0,0,0,5"/> <TextBlock Name="subscribers" Text="[subscribers]" Foreground="Gray" Margin="0,0,0,5"/>
<Button Click="subscribe_Click" Grid.Column="2" Height="30" Width="200" Background="Red" Foreground="White" FontSize="14" FontWeight="SemiBold" Content="Subscirbe" Name="subscribe"/> <Button x:Uid="/Cards/subscribe" Click="subscribe_Click" Grid.Column="2" Height="30" Width="200" Background="Red" Foreground="White" FontSize="14" FontWeight="SemiBold" Content="Subscirbe" Name="subscribe"/>
</StackPanel> </StackPanel>
</StackPanel> </StackPanel>
</Button> </Button>
@@ -82,38 +74,19 @@
</StackPanel> </StackPanel>
</Grid> </Grid>
<TextBlock Name="description" Text="[Description]" IsTextSelectionEnabled="True" TextWrapping="WrapWholeWords"/> <TextBlock Name="description" Text="[Description]" IsTextSelectionEnabled="True" TextWrapping="WrapWholeWords"/>
<Grid Margin="0,20,0,0"> <TextBlock Margin="0,20" Name="category" Text="Category: "/>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<TextBlock Text="Published at: "/>
<TextBlock Grid.Row="1" Text="Category: "/>
<TextBlock Grid.Row="2" Text="License: "/>
<TextBlock Name="publishedAt" Grid.Column="2" Text="[Publishing date]"/>
<TextBlock Name="category" Grid.Column="2" Grid.Row="1" Padding="0" Text="[Category]"/>
<TextBlock Name="license" Grid.Column="2" Grid.Row="2" Text="[License type]"/>
</Grid>
</StackPanel> </StackPanel>
</PivotItem> </PivotItem>
</StackPanel> </StackPanel>
</ScrollViewer> </ScrollViewer>
<CommandBar VerticalAlignment="Bottom" Name="commandbar"> <CommandBar VerticalAlignment="Bottom" Name="commandbar">
<AppBarButton Icon="Download" Label="Download video" Name="download"> <AppBarButton x:Uid="/VideoPage/download" Icon="Download" Label="Download video" Name="download">
<AppBarButton.Flyout> <AppBarButton.Flyout>
<MenuFlyout x:Name="downloadSelector"/> <MenuFlyout x:Name="downloadSelector"/>
</AppBarButton.Flyout> </AppBarButton.Flyout>
</AppBarButton> </AppBarButton>
<AppBarButton Name="addTo" Label="Add to" Icon="Add"> <AppBarButton x:Uid="/VideoPage/addTo" Name="addTo" Label="Add to" Icon="Add">
<AppBarButton.Flyout> <AppBarButton.Flyout>
<Flyout> <Flyout>
<ScrollViewer Margin="-12" MaxHeight="300"> <ScrollViewer Margin="-12" MaxHeight="300">
@@ -154,14 +127,14 @@
</Flyout> </Flyout>
</AppBarButton.Flyout> </AppBarButton.Flyout>
</AppBarButton> </AppBarButton>
<AppBarButton Name="refresh" Click="refresh_Click" Icon="Refresh" Label="Refresh page"/> <AppBarButton x:Uid="/VideoPage/refresh" Name="refresh" Click="refresh_Click" Icon="Refresh" Label="Refresh page"/>
<AppBarButton Name="share" Click="share_Click" Icon="Share" Label="Share"/> <AppBarButton x:Uid="/VideoPage/share" Name="share" Click="share_Click" Icon="Share" Label="Share"/>
<AppBarButton Name="openBrowser" Click="openBrowser_Click" Icon="Globe" Label="Open in browser"/> <AppBarButton x:Uid="/VideoPage/openWeb" Name="openBrowser" Click="openBrowser_Click" Icon="Globe" Label="Open in browser"/>
</CommandBar> </CommandBar>
<Grid Grid.Column="1" Name="tabsPlaceholder"> <Grid Grid.Column="1" Name="tabsPlaceholder">
<Pivot Grid.Row="1" Name="pivot" SelectedIndex="0" IsHeaderItemsCarouselEnabled="False"> <Pivot Grid.Row="1" Name="pivot" SelectedIndex="0" IsHeaderItemsCarouselEnabled="False">
<PivotItem Header="Suggestions"> <PivotItem x:Uid="/VideoPage/related" Header="Suggestions">
<ScrollViewer> <ScrollViewer>
<StackPanel> <StackPanel>
<controls1:Advert/> <controls1:Advert/>
@@ -169,10 +142,10 @@
</StackPanel> </StackPanel>
</ScrollViewer> </ScrollViewer>
</PivotItem> </PivotItem>
<PivotItem Header="Comments" Name="commentsPlaceholder"> <PivotItem x:Uid="/VideoPage/comments" Header="Comments" Name="commentsPlaceholder">
<pages:CommentsPage/> <pages:CommentsPage/>
</PivotItem> </PivotItem>
<PivotItem Header="Playlist" Name="playlist"> <PivotItem x:Uid="/VideoPage/playlist" Header="Playlist" Name="playlist">
<ScrollViewer> <ScrollViewer>
<StackPanel> <StackPanel>
<StackPanel Padding="8" Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}"> <StackPanel Padding="8" Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}">
+137 -73
View File
@@ -1,22 +1,25 @@
using System; using FoxTube.Controls;
using FoxTube.Controls.Adverts;
using Google.Apis.YouTube.v3;
using Google.Apis.YouTube.v3.Data;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq; using System.Linq;
using Windows.ApplicationModel.DataTransfer;
using Windows.ApplicationModel.Resources;
using Windows.Foundation; using Windows.Foundation;
using Windows.Storage;
using Windows.System;
using Windows.UI;
using Windows.UI.Xaml; using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using Windows.System;
using Google.Apis.YouTube.v3.Data;
using Google.Apis.YouTube.v3;
using Windows.UI.Xaml.Media.Imaging; using Windows.UI.Xaml.Media.Imaging;
using System.Diagnostics; using Windows.UI.Xaml.Navigation;
using Windows.ApplicationModel.DataTransfer;
using Windows.Storage;
using Windows.UI;
using FoxTube.Controls;
using YoutubeExplode.Models.MediaStreams;
using YoutubeExplode; using YoutubeExplode;
using YoutubeExplode.Models.MediaStreams;
namespace FoxTube.Pages namespace FoxTube.Pages
{ {
@@ -42,10 +45,10 @@ namespace FoxTube.Pages
/// </summary> /// </summary>
public sealed partial class VideoPage : Page public sealed partial class VideoPage : Page
{ {
ApplicationDataContainer settings = ApplicationData.Current.LocalSettings; ResourceLoader resources = ResourceLoader.GetForCurrentView("VideoPage");
public string videoId; public string videoId;
string playlistId = null; public string playlistId = null;
public Video item; public Video item;
bool wide; bool wide;
@@ -57,6 +60,8 @@ namespace FoxTube.Pages
public CommentsPage comments; public CommentsPage comments;
public LoadingPage loading; public LoadingPage loading;
DispatcherTimer liveTimer;
public VideoPage() public VideoPage()
{ {
InitializeComponent(); InitializeComponent();
@@ -84,8 +89,11 @@ namespace FoxTube.Pages
} }
} }
private void Player_NextClicked(object sender, params object[] e) private void Player_NextClicked()
{ {
if (playlistId != null)
playlistList.SelectedIndex++;
else
(relatedVideos.Children[0] as VideoCard).Button_Click(this, null); (relatedVideos.Children[0] as VideoCard).Button_Click(this, null);
} }
@@ -107,21 +115,47 @@ namespace FoxTube.Pages
videoId = ids[0]; videoId = ids[0];
if (ids[1] != null) if (ids[1] != null)
LoadPlaylist(ids[1]);
else
pivot.Items.Remove(playlist);
VideosResource.ListRequest request = SecretsVault.Service.Videos.List("snippet,statistics,status,contentDetails,liveStreamingDetails");
request.Id = ids[0];
item = (await request.ExecuteAsync()).Items[0];
if (item.Snippet.LiveBroadcastContent == "none")
LoadStats();
else
LoadStream();
LoadInfo();
loading.Close();
}
catch (System.Net.Http.HttpRequestException)
{ {
playlistId = ids[1]; loading.Error("System.Net.Http.HttpRequestException", "Unable to connect to Google servers.", true);
}
catch (Exception e)
{
loading.Error(e.GetType().ToString(), e.Message);
}
}
async void LoadPlaylist(string id)
{
playlistId = id;
List<VideoPlaylistItem> items = new List<VideoPlaylistItem>(); List<VideoPlaylistItem> items = new List<VideoPlaylistItem>();
VideoPlaylistItem selection = null; VideoPlaylistItem selection = null;
//Retrieving data
PlaylistsResource.ListRequest playlistRequest = SecretsVault.Service.Playlists.List("snippet,contentDetails"); PlaylistsResource.ListRequest playlistRequest = SecretsVault.Service.Playlists.List("snippet,contentDetails");
playlistRequest.Id = ids[1]; playlistRequest.Id = id;
Playlist playlistItem = (await playlistRequest.ExecuteAsync()).Items[0]; Playlist playlistItem = (await playlistRequest.ExecuteAsync()).Items[0];
playlistName.Text = playlistItem.Snippet.Title;
playlistChannel.Text = playlistItem.Snippet.ChannelTitle;
PlaylistItemsResource.ListRequest listRequest = SecretsVault.Service.PlaylistItems.List("snippet"); PlaylistItemsResource.ListRequest listRequest = SecretsVault.Service.PlaylistItems.List("snippet");
listRequest.MaxResults = 50; listRequest.MaxResults = 50;
listRequest.PlaylistId = ids[1]; listRequest.PlaylistId = id;
PlaylistItemListResponse listResponse = await listRequest.ExecuteAsync(); PlaylistItemListResponse listResponse = await listRequest.ExecuteAsync();
foreach (PlaylistItem i in listResponse.Items) foreach (PlaylistItem i in listResponse.Items)
@@ -132,7 +166,7 @@ namespace FoxTube.Pages
} }
string token = listResponse.NextPageToken; string token = listResponse.NextPageToken;
while(!string.IsNullOrWhiteSpace(token)) while (!string.IsNullOrWhiteSpace(token))
{ {
listRequest.PageToken = token; listRequest.PageToken = token;
listResponse = await listRequest.ExecuteAsync(); listResponse = await listRequest.ExecuteAsync();
@@ -150,39 +184,49 @@ namespace FoxTube.Pages
for (int k = 0; k < items.Count; k++) for (int k = 0; k < items.Count; k++)
items[k].Number = k + 1; items[k].Number = k + 1;
//Setting data
playlistName.Text = playlistItem.Snippet.Title;
playlistChannel.Text = playlistItem.Snippet.ChannelTitle;
playlistCounter.Text = $"{items.IndexOf(selection) + 1}/{playlistItem.ContentDetails.ItemCount}"; playlistCounter.Text = $"{items.IndexOf(selection) + 1}/{playlistItem.ContentDetails.ItemCount}";
playlistList.ItemsSource = items; playlistList.ItemsSource = items;
playlistList.SelectedItem = selection; playlistList.SelectedItem = selection;
pivot.SelectedItem = playlist; pivot.SelectedItem = playlist;
if (playlistList.SelectedIndex == playlistList.Items.Count - 1)
player.Next.Visibility = Visibility.Collapsed;
} }
else
pivot.Items.Remove(playlist);
VideosResource.ListRequest request = SecretsVault.Service.Videos.List("snippet,statistics,status,contentDetails");
request.Id = ids[0];
item = (await request.ExecuteAsync()).Items[0];
async void LoadInfo()
{
//Setting meta
title.Text = item.Snippet.Title; title.Text = item.Snippet.Title;
Methods.FormatText(ref description, item.Snippet.Description); Methods.FormatText(ref description, item.Snippet.Description);
publishedAt.Text = item.Snippet.PublishedAt.ToString(); //Setting channel button
if (item.Status.License == "youtube") ChannelsResource.ListRequest channelRequest = SecretsVault.Service.Channels.List("snippet, statistics");
license.Text = "Standard YouTube License"; channelRequest.Id = item.Snippet.ChannelId;
else license.Text = "Creative Commons Attribution license (reuse allowed)"; var item1 = (await channelRequest.ExecuteAsync()).Items[0];
VideoCategoriesResource.ListRequest categoryRequest = SecretsVault.Service.VideoCategories.List("snippet"); channelAvatar.ProfilePicture = new BitmapImage(new Uri(item1.Snippet.Thumbnails.Medium.Url));
categoryRequest.Id = item.Snippet.CategoryId; channelName.Text = item.Snippet.ChannelTitle;
category.Text = (await categoryRequest.ExecuteAsync()).Items[0].Snippet.Title; subscribers.Text = $"{item1.Statistics.SubscriberCount:0,0} {resources.GetString("/Cards/subscribers")}";
views.Text = $"{item.Statistics.ViewCount:0,0} views"; //Setting ratings
dislikes.Text = $"{item.Statistics.DislikeCount:0,0}"; dislikes.Text = $"{item.Statistics.DislikeCount:0,0}";
likes.Text = $"{item.Statistics.LikeCount:0,0}"; likes.Text = $"{item.Statistics.LikeCount:0,0}";
rating.Value = (double)item.Statistics.DislikeCount / (double)(item.Statistics.DislikeCount + item.Statistics.LikeCount) * 100; rating.Value = (double)item.Statistics.DislikeCount / (double)(item.Statistics.DislikeCount + item.Statistics.LikeCount) * 100;
//Setting category
VideoCategoriesResource.ListRequest categoryRequest = SecretsVault.Service.VideoCategories.List("snippet");
categoryRequest.Id = item.Snippet.CategoryId;
category.Text = (await categoryRequest.ExecuteAsync()).Items[0].Snippet.Title;
//Setting User's rate
if (SecretsVault.IsAuthorized) if (SecretsVault.IsAuthorized)
{ {
VideoGetRatingResponse ratingResponse = await SecretsVault.Service.Videos.GetRating(ids[0]).ExecuteAsync(); VideoGetRatingResponse ratingResponse = await SecretsVault.Service.Videos.GetRating(videoId).ExecuteAsync();
if (ratingResponse.Items[0].Rating == "like") if (ratingResponse.Items[0].Rating == "like")
{ {
userRating = Rating.Like; userRating = Rating.Like;
@@ -200,7 +244,7 @@ namespace FoxTube.Pages
{ {
subscribe.Background = new SolidColorBrush(Colors.Transparent); subscribe.Background = new SolidColorBrush(Colors.Transparent);
subscribe.Foreground = new SolidColorBrush(Colors.Gray); subscribe.Foreground = new SolidColorBrush(Colors.Gray);
subscribe.Content = "Subscribed"; subscribe.Content = resources.GetString("/Cards/unsubscribe");
} }
} }
subscribe.Visibility = Visibility.Visible; subscribe.Visibility = Visibility.Visible;
@@ -212,29 +256,45 @@ namespace FoxTube.Pages
subscribe.Visibility = Visibility.Collapsed; subscribe.Visibility = Visibility.Collapsed;
} }
ChannelsResource.ListRequest channelRequest = SecretsVault.Service.Channels.List("snippet, statistics"); //Initializing player
channelRequest.Id = item.Snippet.ChannelId; player.Initialize(item, item1.Snippet.Thumbnails.Medium.Url);
var item1 = (await channelRequest.ExecuteAsync()).Items[0];
channelAvatar.ProfilePicture = new BitmapImage(new Uri(item1.Snippet.Thumbnails.Medium.Url)); LoadRelatedVideos();
channelName.Text = item.Snippet.ChannelTitle; }
subscribers.Text = $"{item1.Statistics.SubscriberCount:0,0} subscribers";
void LoadStream()
{
liveTimer = new DispatcherTimer() { Interval = TimeSpan.FromSeconds(10) };
liveTimer.Tick += LiveStatsUpdate;
liveTimer.Start();
LiveStatsUpdate();
if(string.IsNullOrWhiteSpace(item.LiveStreamingDetails.ActiveLiveChatId))
pivot.Items.Remove(commentsPlaceholder);
else
{
commentsPlaceholder.Header = resources.GetString("/VideoPage/chat");
commentsPlaceholder.Content = new Chat(item.LiveStreamingDetails.ActiveLiveChatId);
pivot.SelectedItem = commentsPlaceholder;
}
download.Visibility = Visibility.Collapsed;
}
private async void LiveStatsUpdate(object sender = null, object e = null)
{
VideosResource.ListRequest request = SecretsVault.Service.Videos.List("liveStreamingDetails");
request.Id = videoId;
Video video = (await request.ExecuteAsync()).Items[0];
views.Text = $"{video.LiveStreamingDetails.ConcurrentViewers} {resources.GetString("/Cards/viewers")}";
}
void LoadStats()
{
views.Text = $"{item.Statistics.ViewCount:0,0} {resources.GetString("/Cards/views")}";
comments.Initialize(item); comments.Initialize(item);
player.Initialize(item, item1.Snippet.Thumbnails.Medium.Url);
LoadRelatedVideos();
LoadDownloads(); LoadDownloads();
loading.Close();
}
catch (System.Net.Http.HttpRequestException)
{
loading.Error("System.Net.Http.HttpRequestException", "Unable to connect to Google servers.", true);
}
catch (Exception e)
{
loading.Error(e.GetType().ToString(), e.Message);
}
} }
async void LoadDownloads() async void LoadDownloads()
@@ -255,8 +315,8 @@ namespace FoxTube.Pages
MenuFlyoutItem audioItem = new MenuFlyoutItem() MenuFlyoutItem audioItem = new MenuFlyoutItem()
{ {
Text = "Audio track", Text = resources.GetString("/VideoPage/audio"),
Tag = new object[] { infoSet.Audio[0], "Audio only" } Tag = new object[] { infoSet.Audio[0], resources.GetString("/Cards/audioOnly") }
}; };
audioItem.Click += downloadItemSelected; audioItem.Click += downloadItemSelected;
downloadSelector.Items.Add(audioItem); downloadSelector.Items.Add(audioItem);
@@ -275,8 +335,10 @@ namespace FoxTube.Pages
async void LoadRelatedVideos() async void LoadRelatedVideos()
{ {
SearchResource.ListRequest request = SecretsVault.Service.Search.List("snippet"); SearchResource.ListRequest request = SecretsVault.Service.Search.List("snippet");
request.RegionCode = SettingsStorage.Region;
request.RelevanceLanguage = SettingsStorage.RelevanceLanguage;
request.RelatedToVideoId = videoId; request.RelatedToVideoId = videoId;
request.SafeSearch = (SearchResource.ListRequest.SafeSearchEnum)(int)settings.Values["safeSearch"]; request.SafeSearch = (SearchResource.ListRequest.SafeSearchEnum)SettingsStorage.SafeSearch;
request.MaxResults = 20; request.MaxResults = 20;
request.Type = "video"; request.Type = "video";
@@ -320,10 +382,10 @@ namespace FoxTube.Pages
private async void openBrowser_Click(object sender, RoutedEventArgs e) private async void openBrowser_Click(object sender, RoutedEventArgs e)
{ {
player.Pause(); player.Pause();
string timecode = player.elapsed.TotalSeconds > 10 ? string timecode = player.Elapsed.TotalSeconds > 10 ?
"&t=" + (int)player.elapsed.TotalSeconds + "s" : string.Empty; "&t=" + (int)player.Elapsed.TotalSeconds + "s" : string.Empty;
await Launcher.LaunchUriAsync(new Uri($"https://www.youtube.com/watch?v={videoId}{timecode}")); await Launcher.LaunchUriAsync($"https://www.youtube.com/watch?v={videoId}{timecode}".ToUri());
} }
public void refresh_Click(object sender, RoutedEventArgs e) public void refresh_Click(object sender, RoutedEventArgs e)
@@ -344,6 +406,8 @@ namespace FoxTube.Pages
mainContent.Children.Remove(pivot); mainContent.Children.Remove(pivot);
tabsPlaceholder.Children.Add(pivot); tabsPlaceholder.Children.Add(pivot);
pivot.SelectedItem = descriptionPanel;
descriptionPanel.Opacity = 1;
pivot.Items.RemoveAt(0); pivot.Items.RemoveAt(0);
mainContent.Children.Add(descriptionPanel); mainContent.Children.Add(descriptionPanel);
@@ -373,7 +437,7 @@ namespace FoxTube.Pages
item.Snippet.Thumbnails.Medium.Url, item.Snippet.Thumbnails.Medium.Url,
item.Snippet.Title, item.Snippet.Title,
$"https://www.youtube.com/watch?v={videoId}", $"https://www.youtube.com/watch?v={videoId}",
"video"); resources.GetString("/Cards/videoShare"));
} }
private void share_Click(object sender, RoutedEventArgs e) private void share_Click(object sender, RoutedEventArgs e)
@@ -388,10 +452,10 @@ namespace FoxTube.Pages
{ {
case Rating.Like: case Rating.Like:
like.Foreground = new SolidColorBrush(Colors.Gray); like.Foreground = new SolidColorBrush(Colors.Gray);
likes.Text = (int.Parse(likes.Text, System.Globalization.NumberStyles.AllowThousands) - 1).ToString("0,0"); likes.Text = (int.Parse(likes.Text, NumberStyles.AllowThousands) - 1).ToString("0,0");
dislike.Foreground = new SolidColorBrush(Colors.Red); dislike.Foreground = new SolidColorBrush(Colors.Red);
dislikes.Text = (int.Parse(dislikes.Text, System.Globalization.NumberStyles.AllowThousands) + 1).ToString("0,0"); dislikes.Text = (int.Parse(dislikes.Text, NumberStyles.AllowThousands) + 1).ToString("0,0");
rating.Value--; rating.Value--;
await SecretsVault.Service.Videos.Rate(videoId, VideosResource.RateRequest.RatingEnum.Dislike).ExecuteAsync(); await SecretsVault.Service.Videos.Rate(videoId, VideosResource.RateRequest.RatingEnum.Dislike).ExecuteAsync();
@@ -400,7 +464,7 @@ namespace FoxTube.Pages
case Rating.None: case Rating.None:
dislike.Foreground = new SolidColorBrush(Colors.Red); dislike.Foreground = new SolidColorBrush(Colors.Red);
dislikes.Text = (int.Parse(dislikes.Text, System.Globalization.NumberStyles.AllowThousands) + 1).ToString("0,0"); dislikes.Text = (int.Parse(dislikes.Text, NumberStyles.AllowThousands) + 1).ToString("0,0");
rating.Maximum++; rating.Maximum++;
await SecretsVault.Service.Videos.Rate(videoId, VideosResource.RateRequest.RatingEnum.Dislike).ExecuteAsync(); await SecretsVault.Service.Videos.Rate(videoId, VideosResource.RateRequest.RatingEnum.Dislike).ExecuteAsync();
@@ -409,7 +473,7 @@ namespace FoxTube.Pages
case Rating.Dislike: case Rating.Dislike:
dislike.Foreground = new SolidColorBrush(Colors.Gray); dislike.Foreground = new SolidColorBrush(Colors.Gray);
dislikes.Text = (int.Parse(dislikes.Text, System.Globalization.NumberStyles.AllowThousands) - 1).ToString("0,0"); dislikes.Text = (int.Parse(dislikes.Text, NumberStyles.AllowThousands) - 1).ToString("0,0");
rating.Maximum--; rating.Maximum--;
await SecretsVault.Service.Videos.Rate(videoId, VideosResource.RateRequest.RatingEnum.None).ExecuteAsync(); await SecretsVault.Service.Videos.Rate(videoId, VideosResource.RateRequest.RatingEnum.None).ExecuteAsync();
break; break;
@@ -423,10 +487,10 @@ namespace FoxTube.Pages
{ {
case Rating.Dislike: case Rating.Dislike:
dislike.Foreground = new SolidColorBrush(Colors.Gray); dislike.Foreground = new SolidColorBrush(Colors.Gray);
dislikes.Text = (int.Parse(dislikes.Text, System.Globalization.NumberStyles.AllowThousands) - 1).ToString("0,0"); dislikes.Text = (int.Parse(dislikes.Text, NumberStyles.AllowThousands) - 1).ToString("0,0");
like.Foreground = new SolidColorBrush(Colors.Green); like.Foreground = new SolidColorBrush(Colors.Green);
likes.Text = (int.Parse(likes.Text, System.Globalization.NumberStyles.AllowThousands) + 1).ToString("0,0"); likes.Text = (int.Parse(likes.Text, NumberStyles.AllowThousands) + 1).ToString("0,0");
rating.Value++; rating.Value++;
await SecretsVault.Service.Videos.Rate(videoId, VideosResource.RateRequest.RatingEnum.Like).ExecuteAsync(); await SecretsVault.Service.Videos.Rate(videoId, VideosResource.RateRequest.RatingEnum.Like).ExecuteAsync();
@@ -435,7 +499,7 @@ namespace FoxTube.Pages
case Rating.None: case Rating.None:
like.Foreground = new SolidColorBrush(Colors.Green); like.Foreground = new SolidColorBrush(Colors.Green);
likes.Text = (int.Parse(likes.Text, System.Globalization.NumberStyles.AllowThousands) + 1).ToString("0,0"); likes.Text = (int.Parse(likes.Text, NumberStyles.AllowThousands) + 1).ToString("0,0");
rating.Maximum++; rating.Maximum++;
rating.Value++; rating.Value++;
await SecretsVault.Service.Videos.Rate(videoId, VideosResource.RateRequest.RatingEnum.Like).ExecuteAsync(); await SecretsVault.Service.Videos.Rate(videoId, VideosResource.RateRequest.RatingEnum.Like).ExecuteAsync();
@@ -445,7 +509,7 @@ namespace FoxTube.Pages
case Rating.Like: case Rating.Like:
like.Foreground = new SolidColorBrush(Colors.Gray); like.Foreground = new SolidColorBrush(Colors.Gray);
likes.Text = (int.Parse(likes.Text, System.Globalization.NumberStyles.AllowThousands) - 1).ToString("0,0"); likes.Text = (int.Parse(likes.Text, NumberStyles.AllowThousands) - 1).ToString("0,0");
rating.Maximum--; rating.Maximum--;
rating.Value--; rating.Value--;
await SecretsVault.Service.Videos.Rate(videoId, VideosResource.RateRequest.RatingEnum.None).ExecuteAsync(); await SecretsVault.Service.Videos.Rate(videoId, VideosResource.RateRequest.RatingEnum.None).ExecuteAsync();
@@ -469,13 +533,13 @@ namespace FoxTube.Pages
{ {
subscribe.Background = new SolidColorBrush(Colors.Transparent); subscribe.Background = new SolidColorBrush(Colors.Transparent);
subscribe.Foreground = new SolidColorBrush(Colors.Gray); subscribe.Foreground = new SolidColorBrush(Colors.Gray);
subscribe.Content = "Subscribed"; subscribe.Content = resources.GetString("/Cards/unsubscribe");
} }
else else
{ {
subscribe.Background = new SolidColorBrush(Colors.Red); subscribe.Background = new SolidColorBrush(Colors.Red);
subscribe.Foreground = new SolidColorBrush(Colors.White); subscribe.Foreground = new SolidColorBrush(Colors.White);
subscribe.Content = "Subscribe"; subscribe.Content = resources.GetString("/Cards/subscribe/Content");
} }
} }
} }
+189
View File
@@ -0,0 +1,189 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="channel.Text" xml:space="preserve">
<value>View channel</value>
</data>
<data name="channelShare" xml:space="preserve">
<value>channel</value>
</data>
<data name="getLink.Text" xml:space="preserve">
<value>Copy link</value>
</data>
<data name="goesLive" xml:space="preserve">
<value>Goes live in</value>
</data>
<data name="incognitoPlay.Text" xml:space="preserve">
<value>Play incognito</value>
</data>
<data name="live.Text" xml:space="preserve">
<value>LIVE</value>
</data>
<data name="login.Text" xml:space="preserve">
<value>Log in</value>
</data>
<data name="more.Content" xml:space="preserve">
<value>Show more</value>
</data>
<data name="openWeb.Text" xml:space="preserve">
<value>Open in browser</value>
</data>
<data name="play.Text" xml:space="preserve">
<value>Play</value>
</data>
<data name="playlist.Text" xml:space="preserve">
<value>View playlist</value>
</data>
<data name="playlistShare" xml:space="preserve">
<value>playlist</value>
</data>
<data name="share.Text" xml:space="preserve">
<value>Share</value>
</data>
<data name="subscribe.Content" xml:space="preserve">
<value>Subscribe</value>
</data>
<data name="subscribers" xml:space="preserve">
<value>subscribers</value>
</data>
<data name="tomanage.Text" xml:space="preserve">
<value>to manage your subscriptions</value>
</data>
<data name="unsubscribe" xml:space="preserve">
<value>Subscribed</value>
</data>
<data name="upcoming" xml:space="preserve">
<value>Upcoming</value>
</data>
<data name="videos" xml:space="preserve">
<value>videos</value>
</data>
<data name="videoShare" xml:space="preserve">
<value>video</value>
</data>
<data name="viewers" xml:space="preserve">
<value>viewers</value>
</data>
<data name="views" xml:space="preserve">
<value>views</value>
</data>
<data name="watched.Text" xml:space="preserve">
<value>Watched</value>
</data>
</root>
+159
View File
@@ -0,0 +1,159 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="about.Header" xml:space="preserve">
<value>About channel</value>
</data>
<data name="aboutTitle.Text" xml:space="preserve">
<value>About this channel</value>
</data>
<data name="desc.Text" xml:space="preserve">
<value>Description</value>
</data>
<data name="openWeb.Label" xml:space="preserve">
<value>Open in browser</value>
</data>
<data name="playlists.Header" xml:space="preserve">
<value>Playlists</value>
</data>
<data name="playlistTitle.Text" xml:space="preserve">
<value>Playlists</value>
</data>
<data name="refresh.Label" xml:space="preserve">
<value>Refresh</value>
</data>
<data name="regDate.Text" xml:space="preserve">
<value>Registration date:</value>
</data>
<data name="search.PlaceholderText" xml:space="preserve">
<value>Search on channel</value>
</data>
<data name="share.Label" xml:space="preserve">
<value>Share</value>
</data>
<data name="stats.Text" xml:space="preserve">
<value>Statistics</value>
</data>
<data name="videos.Header" xml:space="preserve">
<value>Videos</value>
</data>
<data name="views.Text" xml:space="preserve">
<value>Views:</value>
</data>
</root>
@@ -117,28 +117,22 @@
<resheader name="writer"> <resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader> </resheader>
<data name="description" xml:space="preserve"> <data name="box.PlaceholderText" xml:space="preserve">
<value>You can help us make this app even better by contributing to its development by translating this app. You can choose a brand new language to translate or edit mistakes in existing translations.</value> <value>Send a message</value>
</data> </data>
<data name="export" xml:space="preserve"> <data name="moder.Text" xml:space="preserve">
<value>Export to PC (.zip)</value> <value>Moderator</value>
</data> </data>
<data name="guide0" xml:space="preserve"> <data name="owner.Text" xml:space="preserve">
<value>It's quite simple:</value> <value>Chat owner</value>
</data> </data>
<data name="guide1" xml:space="preserve"> <data name="sponsor.Text" xml:space="preserve">
<value>1. Choose language you you want to translate on</value> <value>Sponsor</value>
</data> </data>
<data name="guide2" xml:space="preserve"> <data name="verified.Text" xml:space="preserve">
<value>2. Import language pack to your PC</value> <value>Verified</value>
</data> </data>
<data name="header" xml:space="preserve"> <data name="welcome.Text" xml:space="preserve">
<value>Help us translate this app</value> <value>Welcome to the chat room</value>
</data>
<data name="langPlaceholder" xml:space="preserve">
<value>Choose language...</value>
</data>
<data name="warning" xml:space="preserve">
<value>Attention! This tool is used to help us to provide our app to more people from other countries. Please, don't send not done language packs. Thanks in advance ;)</value>
</data> </data>
</root> </root>
+45
View File
@@ -117,19 +117,64 @@
<resheader name="writer"> <resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader> </resheader>
<data name="comments" xml:space="preserve">
<value>comments</value>
</data>
<data name="date.Text" xml:space="preserve"> <data name="date.Text" xml:space="preserve">
<value>Date</value> <value>Date</value>
</data> </data>
<data name="deleteContent" xml:space="preserve">
<value>Are you sure? This action cannot be undone</value>
</data>
<data name="deleteHeader" xml:space="preserve">
<value>Delete comment</value>
</data>
<data name="edit.Text" xml:space="preserve">
<value>Edit</value>
</data>
<data name="edited" xml:space="preserve">
<value>(edited)</value>
</data>
<data name="editorCancel.Content" xml:space="preserve">
<value>Cancel</value>
</data>
<data name="editorDelete.Content" xml:space="preserve">
<value>Delete comment</value>
</data>
<data name="editorSubmin.Content" xml:space="preserve">
<value>Submit</value>
</data>
<data name="failedEdit" xml:space="preserve">
<value>Failed to edit your commentary. Please, try again later.</value>
</data>
<data name="failedReply" xml:space="preserve">
<value>Failed to send your reply. Please, try again later.</value>
</data>
<data name="more.Content" xml:space="preserve"> <data name="more.Content" xml:space="preserve">
<value>Show more</value> <value>Show more</value>
</data> </data>
<data name="no" xml:space="preserve">
<value>No</value>
</data>
<data name="publish" xml:space="preserve">
<value>Publish date</value>
</data>
<data name="relevance.Text" xml:space="preserve"> <data name="relevance.Text" xml:space="preserve">
<value>Relevance</value> <value>Relevance</value>
</data> </data>
<data name="reply.Text" xml:space="preserve">
<value>Reply</value>
</data>
<data name="replyBox.PlaceholderText" xml:space="preserve">
<value>Enter your reply...</value>
</data>
<data name="sortBy.Text" xml:space="preserve"> <data name="sortBy.Text" xml:space="preserve">
<value>Sort by: </value> <value>Sort by: </value>
</data> </data>
<data name="textbox.PlaceholderText" xml:space="preserve"> <data name="textbox.PlaceholderText" xml:space="preserve">
<value>Add a public comment</value> <value>Add a public comment</value>
</data> </data>
<data name="yes" xml:space="preserve">
<value>Yes</value>
</data>
</root> </root>

Some files were not shown because too many files have changed in this diff Show More