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>
</PackageReference>
</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>
<ItemGroup />
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '14.0' ">
<VisualStudioVersion>14.0</VisualStudioVersion>
</PropertyGroup>
<PropertyGroup>
<SignAssembly>false</SignAssembly>
</PropertyGroup>
<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.
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;
namespace FoxTube.Background
{
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)
{
XmlDocument template = new XmlDocument();
@@ -14,8 +43,8 @@ namespace FoxTube.Background
<binding template='ToastGeneric'>
<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'/>
<text>Changelog</text>
<text>See what's new in version {version}</text>
<text>{languagePack["changelog"]}</text>
<text>{languagePack["changelogHeader"]} {version}</text>
</binding>
</visual>
</toast>");
@@ -33,13 +62,13 @@ namespace FoxTube.Background
<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"}'/>
<text>{title}</text>
<text>{channel} uploaded a new video</text>
<text>{channel} {languagePack["videoContent"]}</text>
</binding>
</visual>
<actions>
<action content='Add to Watch later' activationType='background' arguments='later|{id}'/>
<action content='Go to channel' activationType='foreground' arguments='channel|{channelId}'/>
<action content='{languagePack["addLater"]}' activationType='background' arguments='later|{id}'/>
<action content='{languagePack["goChannel"]}' activationType='foreground' arguments='channel|{channelId}'/>
</actions>
</toast>");
+35 -5
View File
@@ -1,9 +1,39 @@
<?xml version="1.0" encoding="utf-8" ?>
<items>
<item time="2018-07-29T23:00:00-03" version="1.0.1">
<content>Announcement body (beware of special characters)</content>
<item time="2019-01-05" version="0.2.19012">
<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>
</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.Xml;
using Windows.ApplicationModel.Resources;
namespace FoxTube.Classes
{
@@ -14,6 +15,8 @@ namespace FoxTube.Classes
public string Content { get; set; }
public string Id { get; set; }
private ResourceLoader resources = ResourceLoader.GetForCurrentView("Inbox");
public string Icon
{
get
@@ -29,9 +32,9 @@ namespace FoxTube.Classes
get
{
if (Type == InboxItemType.PatchNote)
return "Patch note";
return resources.GetString("changelog");
else
return "Developer's message";
return resources.GetString("dev");
}
}
@@ -40,7 +43,7 @@ namespace FoxTube.Classes
get
{
if (Type == InboxItemType.PatchNote)
return $"What's new in v{Id}";
return $"{resources.GetString("whatsnew")}{Id}";
else
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.Collections.Generic;
using System.Diagnostics;
@@ -6,8 +9,10 @@ using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Web;
using System.Xml;
using Windows.ApplicationModel.Core;
using Windows.ApplicationModel.DataTransfer;
using Windows.ApplicationModel.Resources;
using Windows.Storage;
using Windows.Storage.Streams;
using Windows.System;
@@ -16,11 +21,15 @@ using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Documents;
using Windows.UI.Xaml.Media;
using YoutubeExplode.Models.MediaStreams;
namespace FoxTube
{
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 MainPage MainPage
{
@@ -37,6 +46,30 @@ namespace FoxTube
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)
{
array.ToList().ForEach(action);
@@ -64,36 +97,56 @@ namespace FoxTube
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)
{
TimeSpan span = DateTime.Now - dateTime;
if (span.TotalMinutes < 1)
return "Just now";
return resources.GetString("/Methods/now");
else if (Math.Round(span.TotalMinutes) == 1)
return "1 minute ago";
return resources.GetString("/Methods/oneMinute");
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)
return "1 hour ago";
return resources.GetString("/Methods/oneHr");
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)
return "1 day ago";
return resources.GetString("/Methods/oneDay");
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)
return "1 week ago";
return resources.GetString("/Methods/oneWeek");
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)
return "1 month ago";
return resources.GetString("/Methods/oneMonth");
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)
return "1 year ago";
return resources.GetString("/Methods/oneYear");
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)
@@ -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)
{
switch(quality)
@@ -242,7 +326,7 @@ namespace FoxTube
{
DataRequest request = args.Request;
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.SetWebLink(url.ToUri());
+32 -6
View File
@@ -8,6 +8,7 @@ using Google.Apis.YouTube.v3;
using Google.Apis.YouTube.v3.Data;
using Newtonsoft.Json;
using Windows.Storage;
using Windows.Services.Store;
namespace FoxTube
{
@@ -17,7 +18,7 @@ namespace FoxTube
//Events
public static event ObjectEventHandler AuthorizationStateChanged;
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 static ClientSecrets Secrets => new ClientSecrets()
@@ -36,6 +37,8 @@ namespace FoxTube
ApplicationName = "FoxTube"
};
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;
//User info
@@ -193,15 +196,38 @@ namespace FoxTube
/// <summary>
/// Connects to MS Store and checks if user has bought ad-free
/// </summary>
public static void CheckAddons()
public static async void CheckAddons()
{
//TODO: Check addons list
bool purchased = true;
try
{
StoreContext store = StoreContext.GetDefault();
StoreProductQueryResult requset = await store.GetAssociatedStoreProductsAsync(new[] { "Consumable", "Durable", "UnmanagedConsumable" });
if(!purchased)
if (!requset.Products["foxtube-adsremove"].IsInUserCollection)
{
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
+78 -11
View File
@@ -7,6 +7,8 @@ using Windows.Storage;
namespace FoxTube
{
public enum MatureState { Blocked, Allowed, AllowedOnce }
public static class SettingsStorage
{
public static string VideoQuality
@@ -84,7 +86,7 @@ namespace FoxTube
SaveData();
}
}
public static string Region
public static string RelevanceLanguage
{
get { return (string)settings[8]; }
set
@@ -93,17 +95,16 @@ namespace FoxTube
SaveData();
}
}
public static int SafeSearch
public static string Region
{
get { return Convert.ToInt32(settings[9]); }
get { return (string)settings[9]; }
set
{
settings[9] = value;
SaveData();
}
}
public static int Theme
public static int SafeSearch
{
get { return Convert.ToInt32(settings[10]); }
set
@@ -112,15 +113,25 @@ namespace FoxTube
SaveData();
}
}
public static bool HasAccount
public static int Theme
{
get { return (bool)settings[11]; }
get { return Convert.ToInt32(settings[11]); }
set
{
settings[11] = value;
SaveData();
}
}
public static bool HasAccount
{
get { return (bool)settings[12]; }
set
{
settings[12] = value;
SaveData();
}
}
public static string Version
{
@@ -139,9 +150,25 @@ namespace FoxTube
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
private static readonly ApplicationDataContainer storage = ApplicationData.Current.LocalSettings;
private static readonly ApplicationDataContainer storage = ApplicationData.Current.RoamingSettings;
//Predefined preferences
private static object[] settings = new object[]
@@ -157,7 +184,8 @@ namespace FoxTube
100,
(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,
2,
@@ -166,14 +194,53 @@ namespace FoxTube
public static void LoadData()
{
/*if(true && (storage.Values["forceUpdate"] == null || storage.Values["forceUpdate"].ToString() != Version))
{
SaveData();
storage.Values["forceUpdate"] = Version;
return;
}*/
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) { }
}
public static async void SaveData()
public static void SaveData()
{
storage.Values["settings"] = JsonConvert.SerializeObject(settings);
ExportSettings();
+1 -1
View File
@@ -36,7 +36,7 @@ namespace FoxTube.Controls
Visibility = Visibility.Visible;
else
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)
+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"/>
<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="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>
<Grid Grid.Row="1">
<Grid.RowDefinitions>
@@ -36,20 +36,29 @@
<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"/>
<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">
<TextBlock Name="subs" Text="[Subscribers counter]" Foreground="Gray"/>
<TextBlock Name="uploads" Text="[Uploads counter]" Foreground="Gray"/>
</StackPanel>
</Grid>
<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>
<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"/>
</Grid>
</Grid>
</Grid>
</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>
+28 -20
View File
@@ -1,34 +1,30 @@
using Google.Apis.YouTube.v3;
using Google.Apis.YouTube.v3.Data;
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.ApplicationModel.DataTransfer;
using Windows.ApplicationModel.Resources;
using Windows.System;
using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.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
{
/// <summary>
/// Channel item card
/// </summary>
public sealed partial class ChannelCard : UserControl
{
ResourceLoader resources = ResourceLoader.GetForCurrentView("Cards");
string channelId;
Channel item;
public ChannelCard(string id, string live = "null")
{
this.InitializeComponent();
InitializeComponent();
Initialize(id, live);
}
@@ -48,8 +44,8 @@ namespace FoxTube.Controls
title.Text = item.Snippet.Title;
subs.Text = $"{item.Statistics.SubscriberCount:0,0} subscribers";
uploads.Text = $"{item.Statistics.VideoCount:0,0} videos";
subs.Text = $"{item.Statistics.SubscriberCount:0,0} {resources.GetString("/Cards/subscribers")}";
uploads.Text = $"{item.Statistics.VideoCount:0,0} {resources.GetString("/Cards/videos")}";
if (live == "live")
liveTag.Visibility = Visibility.Visible;
@@ -62,7 +58,7 @@ namespace FoxTube.Controls
{
subscribe.Background = new SolidColorBrush(Colors.Transparent);
subscribe.Foreground = new SolidColorBrush(Colors.Gray);
subscribe.Content = "Subscribed";
subscribe.Content = resources.GetString("/Cards/unsubscribe");
}
}
subscriptionPane.Visibility = Visibility.Visible;
@@ -74,7 +70,7 @@ namespace FoxTube.Controls
{
if (item.BrandingSettings.Image.BannerImageUrl.Contains("default"))
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 { }
}
@@ -95,14 +91,26 @@ namespace FoxTube.Controls
{
subscribe.Background = new SolidColorBrush(Colors.Transparent);
subscribe.Foreground = new SolidColorBrush(Colors.Gray);
subscribe.Content = "Subscribed";
subscribe.Content = resources.GetString("/Cards/unsubscribe");
}
else
{
subscribe.Background = new SolidColorBrush(Colors.Red);
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"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:FoxTube.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
mc:Ignorable="d"
d:DesignWidth="400">
@@ -38,8 +36,9 @@
<StackPanel Grid.Row="2" Name="editor" Visibility="Collapsed">
<TextBox Name="editorText" Text="[Content]" AcceptsReturn="True" TextWrapping="Wrap" TextChanged="editorText_TextChanged"/>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,5,0,5">
<Button Name="editorClose" Content="Cancel" Click="editorClose_Click"/>
<Button Name="editorSend" Content="Submit" Margin="5,0,0,0" Click="editorSend_Click"/>
<Button x:Uid="/CommentsPage/editorDelete" Content="Delete comment" Background="Red" Name="deleteComment" Click="DeleteComment_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>
<ProgressBar Name="editorSending" Foreground="Red" IsIndeterminate="True" Visibility="Collapsed"/>
</StackPanel>
@@ -69,7 +68,7 @@
Height="35">
<StackPanel Orientation="Horizontal">
<TextBlock FontFamily="Segoe MDL2 Assets" Text="&#xEE35;" FontSize="20"/>
<TextBlock Text="Reply"/>
<TextBlock x:Uid="/CommentsPage/reply" Text="Reply"/>
</StackPanel>
</Button>
@@ -78,7 +77,7 @@
Height="35">
<StackPanel Orientation="Horizontal">
<TextBlock FontFamily="Segoe MDL2 Assets" Text="&#xE104;" FontSize="20"/>
<TextBlock Text="Edit"/>
<TextBlock x:Uid="/CommentsPage/edit" Text="Edit"/>
</StackPanel>
</Button>
</StackPanel>
@@ -86,7 +85,7 @@
</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"
PlaceholderText="Enter your reply..."/>
<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.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using Google.Apis.YouTube.v3;
using Google.Apis.YouTube.v3.Data;
using Windows.UI.Xaml.Media.Imaging;
using Windows.System;
using Windows.UI.Popups;
// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236
using Windows.ApplicationModel.Resources;
namespace FoxTube.Controls
{
public enum CommentType { TopLevel, Reply }
/// <summary>
/// Control represents video comment entity
/// </summary>
public sealed partial class CommentCard : UserControl
{
ResourceLoader resources = ResourceLoader.GetForCurrentView("CommentsPage");
Comment item;
CommentThread thread;
bool repliesLoaded = false;
@@ -33,7 +28,7 @@ namespace FoxTube.Controls
public CommentCard(CommentThread comment)
{
this.InitializeComponent();
InitializeComponent();
Initialize(comment);
}
@@ -72,7 +67,7 @@ namespace FoxTube.Controls
else
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);
try { avatar.ProfilePicture = new BitmapImage(new Uri(comment.Snippet.TopLevelComment.Snippet.AuthorProfileImageUrl)); }
@@ -118,7 +113,7 @@ namespace FoxTube.Controls
else
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);
try { avatar.ProfilePicture = new BitmapImage(new Uri(comment.Snippet.AuthorProfileImageUrl)); }
@@ -209,7 +204,7 @@ namespace FoxTube.Controls
}
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;
reply.IsEnabled = true;
@@ -251,7 +246,7 @@ namespace FoxTube.Controls
}
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;
@@ -274,5 +269,26 @@ namespace FoxTube.Controls
editorText.Text = text.Text;
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">
<StackPanel>
<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>
</Button>
<Button Name="gotoOriginal" Click="gotoOriginal_Click" Width="80" Height="80" Padding="0" Background="Transparent">
<StackPanel>
<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>
</Button>
</StackPanel>
@@ -47,7 +47,7 @@
<TextBlock Name="status" Text="Downloading..." HorizontalAlignment="Left"/>
<ProgressBar Name="progressBar" Width="200" Maximum="1" IsIndeterminate="True" Foreground="Red"/>
<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>
</Grid>
</UserControl>
+21 -18
View File
@@ -15,11 +15,14 @@ using Windows.UI.Popups;
using Windows.UI.Notifications;
using Microsoft.Toolkit.Uwp.Notifications;
using System.Threading.Tasks;
using Windows.ApplicationModel.Resources;
namespace FoxTube.Controls
{
public sealed partial class DownloadItem : UserControl
{
ResourceLoader resources = ResourceLoader.GetForCurrentView("Downloads");
public DownloadItemContainer Container { get; private set; }
public StorageFile file;
public bool InProgress { get; set; } = false;
@@ -62,10 +65,10 @@ namespace FoxTube.Controls
title.Text = Container.Title;
path.Text = file.Name;
thumbnail.Source = new BitmapImage(Container.Thumbnail);
quality.Text = $"Quality: {Container.Quality}";
duration.Text = $"Duration: {Container.Duration}";
channel.Text = $"Author: {Container.Channel}";
ext.Text = $"Extension: {Container.Extension}";
quality.Text = $"{resources.GetString("/Downloads/quality")}: {Container.Quality}";
duration.Text = $"{resources.GetString("/Downloads/duration")}: {Container.Duration}";
channel.Text = $"{resources.GetString("/Downloads/author")}: {Container.Channel}";
ext.Text = $"{resources.GetString("/Downloads/ext")}: {Container.Extension}";
progressPanel.Visibility = Visibility.Collapsed;
donePanel.Visibility = Visibility.Visible;
@@ -93,11 +96,11 @@ namespace FoxTube.Controls
{
Children =
{
new AdaptiveText() { Text = "Downloading a video" },
new AdaptiveText() { Text = resources.GetString("/Downloads/toastStartHeader") },
new AdaptiveProgressBar()
{
Title = meta.Snippet.Title,
Status = "Downloading...",
Status = resources.GetString("/Downloads/downloading/Text"),
Value = new BindableProgressBarValue("value")
}
}
@@ -108,7 +111,7 @@ namespace FoxTube.Controls
{
Buttons =
{
new ToastButton("Cancel", $"dcancel|{Container.Id}")
new ToastButton(resources.GetString("/Downloads/cancel/Content"), $"dcancel|{Container.Id}")
{
ActivationType = ToastActivationType.Background
}
@@ -131,10 +134,10 @@ namespace FoxTube.Controls
thumbnail.Source = new BitmapImage(new Uri(meta.Snippet.Thumbnails.Medium.Url));
title.Text = meta.Snippet.Title;
ext.Text = $"Extension: {info.Container.GetFileExtension()}";
quality.Text = $"Quality: {q}";
duration.Text = $"Duration: {XmlConvert.ToTimeSpan(meta.ContentDetails.Duration)}";
channel.Text = $"Author: {meta.Snippet.ChannelTitle}";
ext.Text = $"{resources.GetString("/Downloads/ext")}: {info.Container.GetFileExtension()}";
quality.Text = $"{resources.GetString("/Downloads/quality")}: {q}";
duration.Text = $"{resources.GetString("/Downloads/duration")}: {XmlConvert.ToTimeSpan(meta.ContentDetails.Duration)}";
channel.Text = $"{resources.GetString("/Downloads/author")}: {meta.Snippet.ChannelTitle}";
path.Text = file.Name;
progressPanel.Visibility = Visibility.Visible;
@@ -170,13 +173,13 @@ namespace FoxTube.Controls
template.LoadXml($@"<toast activationType='background' launch='download|{file.Path}'>
<visual>
<binding template='ToastGeneric'>
<text>Download complete</text>
<text>{resources.GetString("/Downloads/toastCompleteHeader")}</text>
<text>{Container.Title}</text>
</binding>
</visual>
<actions>
<action content='Go to original'
<action content='{resources.GetString("/Downloads/gotoOrign/Text")}'
activationType='foreground'
arguments='video|{Container.Id}'/>
</actions>
@@ -196,7 +199,7 @@ namespace FoxTube.Controls
public async void Cancel()
{
status.Text = "Cancelling...";
status.Text = resources.GetString("/Downloads/cancelling");
progressBar.IsIndeterminate = true;
cancel.IsEnabled = false;
cts.Cancel();
@@ -210,7 +213,7 @@ namespace FoxTube.Controls
template.LoadXml($@"<toast activationType='foreground' launch='download'>
<visual>
<binding template='ToastGeneric'>
<text>Download canceled</text>
<text>{resources.GetString("/Downloads/toastCanceledHeader")}</text>
<text>{Container.Title}</text>
</binding>
</visual>
@@ -224,10 +227,10 @@ namespace FoxTube.Controls
{
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("No"));
dialog.Commands.Add(new UICommand(resources.GetString("/Downloads/yes"), (command) => Cancel()));
dialog.Commands.Add(new UICommand(resources.GetString("/Downloads/no")));
dialog.DefaultCommandIndex = 1;
await dialog.ShowAsync();
+26 -39
View File
@@ -1,36 +1,32 @@
using FoxTube.Classes;
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 System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using System.Xml;
using System.Diagnostics;
// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236
using Windows.Media;
using YoutubeExplode.Models.ClosedCaptions;
namespace FoxTube.Controls
{
/// <summary>
/// Control for displaying closed captions
/// </summary>
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;
DispatcherTimer timer = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(10) };
List<Caption> captions = new List<Caption>();
Caption currentCaption = null;
ClosedCaption currentCaption = null;
ClosedCaptionTrack track = null;
public LiveCaptions()
{
this.InitializeComponent();
InitializeComponent();
timer.Tick += UpdateCaption;
}
@@ -40,11 +36,11 @@ namespace FoxTube.Controls
bool found = false;
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;
Visibility = Visibility.Visible;
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();
XmlDocument doc = new XmlDocument();
doc.Load(source);
track = await new YoutubeExplode.YoutubeClient().GetClosedCaptionTrackAsync(info);
if (!isAutoGenerated)
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) =>
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;
Visibility = Visibility.Visible;
}
@@ -86,7 +73,7 @@ namespace FoxTube.Controls
public void Close()
{
captions.Clear();
track = null;
currentCaption = null;
Visibility = Visibility.Collapsed;
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}"/>
<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"/>
</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>
</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>
+20 -1
View File
@@ -1,6 +1,8 @@
using Google.Apis.YouTube.v3;
using Google.Apis.YouTube.v3.Data;
using System;
using Windows.ApplicationModel.DataTransfer;
using Windows.System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media.Imaging;
@@ -40,7 +42,7 @@ namespace FoxTube.Controls
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));
} catch { }
}
@@ -54,5 +56,22 @@ namespace FoxTube.Controls
{
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">
<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"/>
</Grid>
</UserControl>
+16 -10
View File
@@ -20,7 +20,7 @@
<Image Name="thumbnail" Source="/Assets/videoThumbSample.png" Stretch="Fill"/>
<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">
<TextBlock Text="Watched" Foreground="Gray" FontSize="12"/>
<TextBlock x:Uid="/Cards/watched" Text="Watched" Foreground="Gray" FontSize="12"/>
</StackPanel>
<ProgressBar VerticalAlignment="Bottom" Margin="54,0,0,0" Foreground="Red" Name="leftOn"/>
</Grid>
@@ -29,7 +29,7 @@
</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">
<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>
<Grid Grid.Row="1">
<Grid.RowDefinitions>
@@ -44,22 +44,28 @@
<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"/>
<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"/>
</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>
</Button>
<UserControl.ContextFlyout>
<MenuFlyout>
<MenuFlyoutItem Icon="Play" Text="Play"/>
<MenuFlyoutItem Icon="Contact" Text="View channel"/>
<MenuFlyoutItem x:Uid="/Cards/play" Icon="Play" Text="Play" Name="play" Click="Button_Click"/>
<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/>
<MenuFlyoutItem Icon="Link" Text="Copy link"/>
<MenuFlyoutItem Icon="Share" Text="Share"/>
<MenuFlyoutSeparator/>
<MenuFlyoutItem Icon="Download" Text="Download"/>
<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"/>
<MenuFlyoutSeparator Visibility="Collapsed"/>
<MenuFlyoutItem Icon="Download" Text="Download" Visibility="Collapsed"/>
</MenuFlyout>
</UserControl.ContextFlyout>
</UserControl>
+32 -26
View File
@@ -4,22 +4,26 @@ using Windows.UI.Xaml.Controls;
using Google.Apis.YouTube.v3;
using Google.Apis.YouTube.v3.Data;
using Windows.UI.Xaml.Media.Imaging;
using System.Xml;
using Windows.System;
using Windows.UI.Popups;
using Windows.ApplicationModel.DataTransfer;
using Windows.ApplicationModel.Resources;
namespace FoxTube.Controls
{
/// <summary>
/// Video item card
/// </summary>
public sealed partial class VideoCard : UserControl
{
ResourceLoader resources = ResourceLoader.GetForCurrentView("Cards");
public string playlistId;
public string videoId;
Video item;
bool embed = true;
public VideoCard(string id, string playlist = null)
{
this.InitializeComponent();
InitializeComponent();
Initialize(id, playlist);
}
@@ -42,7 +46,7 @@ namespace FoxTube.Controls
channelName.Text = item.Snippet.ChannelTitle;
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)
info.Text = $"{item.LiveStreamingDetails.ScheduledEndTime - item.LiveStreamingDetails.ScheduledStartTime} | {Methods.GetAgo(item.LiveStreamingDetails.ActualStartTime.Value)}";
else
@@ -59,14 +63,13 @@ namespace FoxTube.Controls
liveTag.Visibility = Visibility.Visible;
if (item.LiveStreamingDetails.ScheduledStartTime.HasValue && (item.LiveStreamingDetails.ScheduledStartTime - DateTime.Now).Value.TotalMilliseconds > 0)
liveContent.Text = $"Goes live in {item.LiveStreamingDetails.ScheduledStartTime}";
else liveContent.Text = "Upcoming";
liveContent.Text = $"{resources.GetString("/Cards/goesLive")} {item.LiveStreamingDetails.ScheduledStartTime}";
else liveContent.Text = resources.GetString("/Cards/upcoming");
}
else
{
views.Text = $"{item.Statistics.ViewCount:0,0} views";
info.Text = $"{XmlConvert.ToTimeSpan(item.ContentDetails.Duration)} | {Methods.GetAgo(item.Snippet.PublishedAt.Value)}";
embed = false;
views.Text = $"{item.Statistics.ViewCount:0,0} {resources.GetString("/Cards/views")}";
info.Text = $"{item.ContentDetails.Duration.GetDuration()} | {Methods.GetAgo(item.Snippet.PublishedAt.Value)}";
}
var request1 = SecretsVault.Service.Channels.List("snippet");
@@ -76,7 +79,7 @@ namespace FoxTube.Controls
try
{
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 { }
@@ -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);
}
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"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:FoxTube"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
xmlns:controls1="using:FoxTube.Controls"
mc:Ignorable="d"
d:DesignHeight="1080"
@@ -16,10 +14,9 @@
PointerEntered="UserControl_PointerEntered">
<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"/>
<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"/>
<controls1:LiveCaptions Player="{x:Bind videoSource}" Visibility="Collapsed"/>
<MediaPlayerElement IsDoubleTapEnabled="False" 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"/>
<Grid Name="controls" Visibility="Visible">
<Grid.RowDefinitions>
@@ -27,21 +24,37 @@
<RowDefinition/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0" Name="header" Height="50" Background="#7F000000">
<Grid Name="header" Height="50" Background="#7F000000">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition/>
<ColumnDefinition Width="auto"/>
</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">
<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"/>
</StackPanel>
<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="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"/>
<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"/>
<Button Name="closeHeader" Click="close_Click" Background="Transparent" FontFamily="Segoe MDL2 Assets" Content="&#xE10A;" Foreground="White" Width="50" Height="50" FontSize="25">
<ToolTipService.ToolTip>
<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>
</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="&#xED3D;" FontFamily="Segoe MDL2 Assets" Background="Transparent" FontSize="40" Foreground="WhiteSmoke" Name="touchFwd30" Click="fwd30_Click"/>
</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" 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"/>
<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>
<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"
VerticalAlignment="Top" HorizontalAlignment="Left"
Name="maximize" Click="maximize_Click"
Background="Transparent" FontFamily="Segoe MDL2 Assets" Foreground="White" FontSize="25"
Content="&#xE010;"
Width="45" Height="45"
ToolTipService.ToolTip="Maximize"/>
Width="45" Height="45">
<ToolTipService.ToolTip>
<TextBlock x:Uid="/VideoPage/maximize"/>
</ToolTipService.ToolTip>
</Button>
<ProgressBar VerticalAlignment="Bottom" Foreground="Red" Name="seekIndicator" Visibility="Collapsed"/>
</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 Orientation="Horizontal">
<TextBlock FontFamily="Segoe MDL2 Assets" FontSize="30" Margin="0,0,10,0" Text="&#xE101;" VerticalAlignment="Center"/>
<TextBlock Text="Skip ad" FontSize="30" TextWrapping="WrapWholeWords" MaxWidth="250"/>
<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">
<FontIcon Glyph="&#xE704;" FontSize="30" Margin="0,0,10,0" VerticalAlignment="Top"/>
<StackPanel>
<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>
</Button>
<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.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
@@ -81,53 +110,102 @@
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<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 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"/>
<Button Name="openVolume" Background="Transparent" FontFamily="Segoe MDL2 Assets" Content="&#xE995;" Foreground="White" Width="50" Height="50" FontSize="25" ToolTipService.ToolTip="Volume">
<Button Click="play_Click" Name="play" Background="Transparent" FontFamily="Segoe MDL2 Assets" Content="&#xE768;" Foreground="White" Width="50" Height="50" FontSize="25">
<ToolTipService.ToolTip>
<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>
<Flyout>
<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"/>
</StackPanel>
</Flyout>
</Button.Flyout>
</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>
<Grid Grid.Column="1">
<TextBlock Name="elapsedTime" Foreground="White" Text="[Elapsed]" VerticalAlignment="Bottom" HorizontalAlignment="Left" ToolTipService.ToolTip="Time elapsed"/>
<TextBlock Name="remainingTime" Foreground="White" Text="[Remaining]" VerticalAlignment="Bottom" HorizontalAlignment="Right" ToolTipService.ToolTip="Time remaining"/>
<Grid Grid.Column="1" Name="seekPanel">
<TextBlock Name="elapsedTime" Foreground="White" Text="[Elapsed]" VerticalAlignment="Bottom" HorizontalAlignment="Left"/>
<TextBlock Name="remainingTime" Foreground="White" Text="[Remaining]" VerticalAlignment="Bottom" HorizontalAlignment="Right"/>
<Grid VerticalAlignment="Top" Margin="0,15,0,0" Height="2">
<ProgressBar Background="#66FFFFFF" Foreground="LightGray" Name="bufferingLevel"/>
</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>
<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"/>
<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"/>
<TextBlock Text="1:12:32" Name="liveElapsed" Visibility="Collapsed" Margin="10,0" FontSize="20" VerticalAlignment="Center">
<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"/>
<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>
<Flyout>
<StackPanel Width="225">
<ToggleSwitch 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"/>
<ToggleSwitch x:Uid="/VideoPage/subsSwitch" Name="subsSwitch" Toggled="subsSwitch_Toggled" OnContent="Subtitles" OffContent="Subtitles"/>
<ComboBox x:Uid="/VideoPage/subsSelector" Name="subsLang" Header="Language" PlaceholderText="No subtitles are available" Visibility="Collapsed" HorizontalAlignment="Stretch" SelectionChanged="subsLang_SelectionChanged"/>
</StackPanel>
</Flyout>
</Button.Flyout>
</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>
<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>
</Button.Flyout>
</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>
</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"/>
</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>
</UserControl>
File diff suppressed because it is too large Load Diff
+39 -7
View File
@@ -17,11 +17,12 @@
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WindowsXamlEnableOverview>true</WindowsXamlEnableOverview>
<PackageCertificateKeyFile>FoxTube_TemporaryKey.pfx</PackageCertificateKeyFile>
<PackageCertificateThumbprint>E33236F6F6066A373DFA92A7B7C1467B1EF0BA81</PackageCertificateThumbprint>
<PackageCertificateKeyFile>
</PackageCertificateKeyFile>
<PackageCertificateThumbprint>E888C12EC9A02B902D03CDA4515BDBE9F5E71F1F</PackageCertificateThumbprint>
<GenerateAppInstallerFile>False</GenerateAppInstallerFile>
<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>
<AppxBundlePlatforms>x86|x64|arm</AppxBundlePlatforms>
<AppInstallerUpdateFrequency>1</AppInstallerUpdateFrequency>
@@ -103,7 +104,6 @@
<Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon>
</Compile>
<Compile Include="Classes\Caption.cs" />
<Compile Include="Classes\DownloadItemContainer.cs" />
<Compile Include="Classes\InboxItem.cs" />
<Compile Include="Classes\Methods.cs" />
@@ -112,9 +112,15 @@
<Compile Include="Controls\Advert.xaml.cs">
<DependentUpon>Advert.xaml</DependentUpon>
</Compile>
<Compile Include="Controls\Adverts\CardAdvert.xaml.cs">
<DependentUpon>CardAdvert.xaml</DependentUpon>
</Compile>
<Compile Include="Controls\ChannelCard.xaml.cs">
<DependentUpon>ChannelCard.xaml</DependentUpon>
</Compile>
<Compile Include="Controls\Chat.xaml.cs">
<DependentUpon>Chat.xaml</DependentUpon>
</Compile>
<Compile Include="Controls\CommentCard.xaml.cs">
<DependentUpon>CommentCard.xaml</DependentUpon>
</Compile>
@@ -280,10 +286,18 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Controls\Adverts\CardAdvert.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Controls\ChannelCard.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Controls\Chat.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Controls\CommentCard.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
@@ -403,7 +417,7 @@
<Version>6.1.9</Version>
</PackageReference>
<PackageReference Include="Microsoft.Toolkit.Uwp.Notifications">
<Version>4.0.0</Version>
<Version>5.0.0</Version>
</PackageReference>
<PackageReference Include="Microsoft.Toolkit.Uwp.UI.Controls">
<Version>4.0.0</Version>
@@ -412,7 +426,7 @@
<Version>4.3.2</Version>
</PackageReference>
<PackageReference Include="YoutubeExplode">
<Version>4.5.1</Version>
<Version>4.6.1</Version>
</PackageReference>
<PackageReference Include="YoutubeExtractor">
<Version>0.10.11</Version>
@@ -420,6 +434,25 @@
</ItemGroup>
<ItemGroup>
<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\ru-RU\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\About.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\About.resw" />
<PRIResource Include="Strings\en-US\General.resw" />
+3 -3
View File
@@ -1,6 +1,6 @@
<?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">
<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" />
<Properties>
<DisplayName>FoxTube</DisplayName>
@@ -15,7 +15,7 @@
</Resources>
<Applications>
<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:ShowNameOnTiles>
<uap:ShowOn Tile="square150x150Logo" />
@@ -23,7 +23,7 @@
<uap:ShowOn Tile="square310x310Logo" />
</uap:ShowNameOnTiles>
</uap:DefaultTile>
<uap:SplashScreen Image="Assets\SplashScreen.png" BackgroundColor="red" />
<uap:SplashScreen Image="Assets\SplashScreen.png" BackgroundColor="#282828" />
</uap:VisualElements>
<Extensions>
<Extension Category="windows.backgroundTasks" EntryPoint="FoxTube.Background.BackgroundProcessor">
+15 -15
View File
@@ -17,7 +17,7 @@
</Grid.RowDefinitions>
<Pivot SelectedIndex="0" Name="content" IsHeaderItemsCarouselEnabled="False" SelectionChanged="content_SelectionChanged">
<PivotItem Header="Videos">
<PivotItem x:Uid="/Channel/videos" Header="Videos">
<ScrollViewer>
<StackPanel Name="videos">
<Image Name="channelCover" Stretch="Uniform" Source="/Assets/ChannelCoverTemplate.png"/>
@@ -35,11 +35,11 @@
<TextBlock Name="videosCount" Foreground="Gray" Text="563,000 videos"/>
</StackPanel>
<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>
<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>
<pages:VideoGrid/>
@@ -47,11 +47,11 @@
</StackPanel>
</ScrollViewer>
</PivotItem>
<PivotItem Header="Playlists">
<PivotItem x:Uid="/Channel/playlists" Header="Playlists">
<ScrollViewer>
<Grid Name="playlists">
<StackPanel Margin="10" Visibility="Visible">
<TextBlock FontSize="28" Text="Playlists"/>
<TextBlock x:Uid="/Channel/playlistTitle" FontSize="28" Text="Playlists"/>
<pages:VideoGrid/>
<controls:ShowMore Clicked="showMorePlaylists_Click"/>
</StackPanel>
@@ -59,10 +59,10 @@
</Grid>
</ScrollViewer>
</PivotItem>
<PivotItem Header="About channel">
<PivotItem x:Uid="/Channel/about" Header="About channel">
<ScrollViewer>
<StackPanel Margin="10">
<TextBlock FontSize="28" Text="About this channel"/>
<TextBlock x:Uid="/Channel/aboutTitle" FontSize="28" Text="About this channel"/>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
@@ -70,7 +70,7 @@
</Grid.ColumnDefinitions>
<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"/>
</StackPanel>
@@ -85,12 +85,12 @@
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
</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="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"/>
</Grid>
</Grid>
@@ -99,14 +99,14 @@
</PivotItem>
<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>
<CommandBar Grid.Row="1" VerticalAlignment="Bottom" Name="commandBar">
<AppBarButton Icon="Globe" Label="Open in browser" Name="inBrowser" Click="inBrowser_Click"/>
<AppBarButton Icon="Refresh" Label="Refresh" Name="refresh" Click="refresh_Click"/>
<AppBarButton Icon="Share" Label="Share" Name="share" Click="share_Click"/>
<AppBarButton x:Uid="/Channel/openWeb" Icon="Globe" Label="Open in browser" Name="inBrowser" Click="inBrowser_Click"/>
<AppBarButton x:Uid="/Channel/refresh" Icon="Refresh" Label="Refresh" Name="refresh" Click="refresh_Click"/>
<AppBarButton x:Uid="/Channel/share" Icon="Share" Label="Share" Name="share" Click="share_Click"/>
</CommandBar>
<local:LoadingPage Grid.RowSpan="2" Visibility="Collapsed"/>
+9 -6
View File
@@ -12,6 +12,7 @@ using FoxTube.Controls;
using Windows.ApplicationModel.DataTransfer;
using Windows.System;
using Windows.UI;
using Windows.ApplicationModel.Resources;
namespace FoxTube.Pages
{
@@ -20,6 +21,8 @@ namespace FoxTube.Pages
/// </summary>
public sealed partial class ChannelPage : Page
{
ResourceLoader resources = ResourceLoader.GetForCurrentView("Cards");
public string channelId;
public Channel item;
@@ -78,8 +81,8 @@ namespace FoxTube.Pages
item = (await request.ExecuteAsync()).Items[0];
title.Text = item.Snippet.Title;
subscribers.Text = $"{item.Statistics.SubscriberCount:0,0} subscribers";
videosCount.Text = $"{item.Statistics.VideoCount:0,0} videos";
subscribers.Text = $"{item.Statistics.SubscriberCount:0,0} {resources.GetString("/Cards/subscribers")}";
videosCount.Text = $"{item.Statistics.VideoCount:0,0} {resources.GetString("/Cards/videos")}";
try
{
@@ -121,7 +124,7 @@ namespace FoxTube.Pages
{
subscribe.Background = new SolidColorBrush(Colors.Transparent);
subscribe.Foreground = new SolidColorBrush(Colors.Gray);
subscribe.Content = "Subscribed";
subscribe.Content = resources.GetString("/Cards/unsubscribe");
}
subscriptionPane.Visibility = Visibility.Visible;
}
@@ -228,13 +231,13 @@ namespace FoxTube.Pages
{
subscribe.Background = new SolidColorBrush(Colors.Transparent);
subscribe.Foreground = new SolidColorBrush(Colors.Gray);
subscribe.Content = "Subscribed";
subscribe.Content = resources.GetString("/Cards/unsubscribe");
}
else
{
subscribe.Background = new SolidColorBrush(Colors.Red);
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.Title,
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"/>
<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"/>
<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>
<MenuFlyout>
@@ -44,7 +44,7 @@
<ScrollViewer Grid.Row="1" Name="scroll">
<StackPanel>
<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"/>
</StackPanel>
</ScrollViewer>
+14 -7
View File
@@ -1,21 +1,21 @@
using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Google.Apis.YouTube.v3;
using Google.Apis.YouTube.v3.Data;
using FoxTube.Controls;
using Windows.UI.Popups;
// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238
using Windows.ApplicationModel.Resources;
namespace FoxTube.Pages
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// Comments placeholder
/// </summary>
public sealed partial class CommentsPage : Page
{
ResourceLoader resources = ResourceLoader.GetForCurrentView("CommentsPage");
string threadId;
string nextPageToken;
@@ -29,13 +29,15 @@ namespace FoxTube.Pages
public async void Initialize(Video video)
{
threadId = video.Id;
Methods.CommentsPage = this;
if (!SecretsVault.IsAuthorized)
grid.RowDefinitions[0].Height = new GridLength(0);
else
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");
request.Order = order;
@@ -53,6 +55,11 @@ namespace FoxTube.Pages
placeholder.Children.Add(new CommentCard(comment));
}
public void RemoveComment(CommentCard commentCard)
{
placeholder.Children.Remove(commentCard);
}
private async void more_Click(object sender, RoutedEventArgs e)
{
more.Visibility = Visibility.Collapsed;
@@ -84,7 +91,7 @@ namespace FoxTube.Pages
moreLoading.Visibility = Visibility.Visible;
order = CommentThreadsResource.ListRequest.OrderEnum.Relevance;
orderBtn.Content = "Relevance";
orderBtn.Content = resources.GetString("/CommentsPage/relevance/Text");
placeholder.Children.Clear();
@@ -111,7 +118,7 @@ namespace FoxTube.Pages
moreLoading.Visibility = Visibility.Visible;
order = CommentThreadsResource.ListRequest.OrderEnum.Time;
orderBtn.Content = "Publish date";
orderBtn.Content = resources.GetString("/CommentsPage/publish");
placeholder.Children.Clear();
+3 -3
View File
@@ -21,17 +21,17 @@
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<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>
<ScrollViewer Grid.Row="1">
<StackPanel Name="stack"/>
</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">
<AppBarButton Label="Refresh" Icon="Refresh" Click="Refresh"/>
<AppBarButton x:Uid="/Downloads/refresh" Label="Refresh" Icon="Refresh" Click="Refresh"/>
</CommandBar>
</Grid>
</Page>
+4 -4
View File
@@ -16,12 +16,12 @@
</Grid.RowDefinitions>
<Pivot Name="pivot" SelectionChanged="pivot_SelectionChanged">
<PivotItem Header="Recommended" Name="recommended">
<PivotItem x:Uid="/Home/recommended" Header="Recommended" Name="recommended">
<ScrollViewer>
<StackPanel/>
</ScrollViewer>
</PivotItem>
<PivotItem Header="Trending" Name="trending">
<PivotItem x:Uid="/Home/trending" Header="Trending" Name="trending">
<ScrollViewer>
<StackPanel>
<pages:VideoGrid/>
@@ -29,7 +29,7 @@
</StackPanel>
</ScrollViewer>
</PivotItem>
<PivotItem Header="Subscriptions" Name="subscriptions">
<PivotItem x:Uid="/Home/subs" Header="Subscriptions" Name="subscriptions">
<ScrollViewer>
<StackPanel/>
</ScrollViewer>
@@ -37,7 +37,7 @@
</Pivot>
<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>
<local:LoadingPage Grid.RowSpan="2" Margin="0,50,0,0" Visibility="Visible" RefreshPage="refreshPage"/>
</Grid>
+2 -4
View File
@@ -25,12 +25,10 @@ namespace FoxTube
string trendToken;
Dictionary<string, string> subsTokens = new Dictionary<string, string>();
string reg;
public Home()
{
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;
trendMore = ((trending.Content as ScrollViewer).Content as StackPanel).Children[1] as ShowMore;
@@ -54,7 +52,7 @@ namespace FoxTube
request.PageToken = trendToken;
request.Chart = VideosResource.ListRequest.ChartEnum.MostPopular;
request.RegionCode = reg;
request.RegionCode = SettingsStorage.Region;
VideoListResponse response = await request.ExecuteAsync();
if (!string.IsNullOrWhiteSpace(response.NextPageToken))
@@ -108,7 +106,7 @@ namespace FoxTube
request.MaxResults = 48;
request.Chart = VideosResource.ListRequest.ChartEnum.MostPopular;
request.RegionCode = reg;
request.RegionCode = SettingsStorage.Region;
VideoListResponse response = await request.ExecuteAsync();
if (!string.IsNullOrWhiteSpace(response.NextPageToken))
+12 -13
View File
@@ -2,7 +2,6 @@
x:Class="FoxTube.LoadingPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:FoxTube"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
@@ -12,28 +11,28 @@
<StackPanel Name="wifiTrouble" Visibility="Collapsed" VerticalAlignment="Center">
<FontIcon FontFamily="Segoe MDL2 Assets" Glyph="&#xEB5E;" FontSize="100" HorizontalAlignment="Center"/>
<TextBlock Text="Check your internet connection" FontSize="48" HorizontalAlignment="Center"/>
<TextBlock Text="Please, make sure you are connected to the internet and try again." HorizontalAlignment="Center"/>
<TextBlock x:Uid="/LoadingPage/checkConnection" Text="Check your internet connection" TextWrapping="WrapWholeWords" FontSize="48" HorizontalAlignment="Center" HorizontalTextAlignment="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">
<Button 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/openWifi" Content="Open network settings" Margin="5" Name="openWifi" Click="openWifi_Click"/>
<Button x:Uid="/LoadingPage/openTroubleshooter" Content="Open troubleshooter" Background="Red" Foreground="White" Margin="5" Name="openTroubleshoot" Click="openTroubleshoot_Click"/>
</StackPanel>
<TextBlock Text="OR" FontSize="20" HorizontalAlignment="Center"/>
<Button Name="wifiRefresh" Click="wifiRefresh_Click" Content="Refresh page" HorizontalAlignment="Center" Background="Red" Foreground="White" Margin="5"/>
<TextBlock x:Uid="/LoadingPage/or" Text="OR" FontSize="20" HorizontalAlignment="Center"/>
<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="wifiMessage" Foreground="Gray" Text="Message:" HorizontalAlignment="Center" IsTextSelectionEnabled="True"/>
<TextBlock Name="wifiMessage" Foreground="Gray" Text="Message:" HorizontalAlignment="Center" IsTextSelectionEnabled="True" TextWrapping="WrapWholeWords"/>
</StackPanel>
<StackPanel Name="trouble" Visibility="Collapsed" VerticalAlignment="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 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/err" Text="We are unable to display the page" FontSize="48" HorizontalAlignment="Center" TextWrapping="WrapWholeWords" HorizontalTextAlignment="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">
<Button 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/refresh" Name="refresh" Click="wifiRefresh_Click" Content="Refresh page" Margin="5"/>
<Button x:Uid="/LoadingPage/feedback" Content="Leave feedback" Background="Red" Foreground="White" Margin="5" Name="feedback" Click="feedback_Click"/>
</StackPanel>
<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>
<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.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.ApplicationModel.Resources;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238
namespace FoxTube
{
public enum LoadingState { Loadnig, Loaded, Error, Blocked }
/// <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>
public sealed partial class LoadingPage : Page
{
ResourceLoader resources = ResourceLoader.GetForCurrentView("LoadingPage");
public event RoutedEventHandler RefreshPage;
public LoadingState State { get; private set; } = LoadingState.Loadnig;
public LoadingPage()
{
this.InitializeComponent();
InitializeComponent();
}
public void Error(string exceptionId = "Unknown", string details = "N/A", bool isWifiTrouble = false)
@@ -41,15 +31,15 @@ namespace FoxTube
if (isWifiTrouble)
{
wifiException.Text = $"ID: {exceptionId}";
wifiMessage.Text = $"Details: {details}";
wifiException.Text = $"{resources.GetString("/LoadingPage/ex")}: {exceptionId}";
wifiMessage.Text = $"{resources.GetString("/LoadingPage/details")}: {details}";
wifiTrouble.Visibility = Visibility.Visible;
}
else
{
exception.Text = $"ID: {exceptionId}";
message.Text = $"Details: {details}";
exception.Text = $"{resources.GetString("/LoadingPage/ex")}: {exceptionId}";
message.Text = $"{resources.GetString("/LoadingPage/details")}: {details}";
trouble.Visibility = Visibility.Visible;
}
+1 -1
View File
@@ -36,7 +36,7 @@
</NavigationViewItem.Icon>
</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>
<FontIcon Glyph="&#xE14D;"/>
</NavigationViewItem.Icon>
+87 -45
View File
@@ -21,8 +21,9 @@ using System.Net;
using Windows.UI.Popups;
using Windows.Networking.Connectivity;
using Windows.UI.Core;
using System.Threading;
using System.Threading.Tasks;
using Windows.ApplicationModel.Resources;
using Windows.Storage;
using System.IO;
namespace FoxTube
{
@@ -34,18 +35,39 @@ namespace FoxTube
public sealed partial class MainPage : Page
{
Sender s = Sender.None;
ResourceLoader resources = ResourceLoader.GetForCurrentView("Main");
public MainPage()
{
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;
if (SettingsStorage.Version != $"{ver.Major}.{ver.Minor}")
{
try
{
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;
ToastNotificationManager.CreateToastNotifier().Show(FoxTube.Background.Notification.GetChangelogToast(e.GetAttribute("version")));
@@ -57,14 +79,6 @@ namespace FoxTube
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()
@@ -73,6 +87,12 @@ namespace FoxTube
catch { return null; }
}
public string GetPlaylist()
{
try { return (videoPlaceholder.Content as VideoPage).playlistId; }
catch { return null; }
}
public void SetTitleBar()
{
var titleBar = ApplicationView.GetForCurrentView().TitleBar;
@@ -200,6 +220,9 @@ namespace FoxTube
}
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;
avatar.Visibility = Visibility.Collapsed;
@@ -212,18 +235,16 @@ namespace FoxTube
subsHeader.Visibility = Visibility.Collapsed;
subsHeader.Visibility = Visibility.Collapsed;
for(int k = 9; k < nav.MenuItems.Count; k++)
nav.MenuItems.RemoveAt(k);
}
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();
}));
dialog.Commands.Add(new UICommand("Quit", (command) =>
dialog.Commands.Add(new UICommand(resources.GetString("/Main/quit"), (command) =>
{
Methods.CloseApp();
}));
@@ -292,15 +313,15 @@ namespace FoxTube
var connection = NetworkInformation.GetInternetConnectionProfile().GetConnectionCost();
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,
CancelCommandIndex = 1
};
dialog.Commands.Add(new UICommand("Yes"));
dialog.Commands.Add(new UICommand("No", (command) => cancel = true));
dialog.Commands.Add(new UICommand(resources.GetString("/Main/yes")));
dialog.Commands.Add(new UICommand(resources.GetString("/Main/no"), (command) => cancel = true));
if(SecretsVault.IsAuthorized)
dialog.Commands.Add(new UICommand("Add to 'Watch later' playlist", (command) =>
dialog.Commands.Add(new UICommand(resources.GetString("/Main/addLater"), (command) =>
{
try
{
@@ -333,6 +354,9 @@ namespace FoxTube
if (cancel)
return;
if (videoPlaceholder.Content != null)
(videoPlaceholder.Content as VideoPage).player.close_Click(this, null);
videoPlaceholder.Content = null;
Fullscreen(false);
@@ -390,14 +414,14 @@ namespace FoxTube
Dictionary<Type, Action> switchCase = new Dictionary<Type, Action>()
{
{ typeof(Settings), () => nav.Header = "Settings" },
{ typeof(ChannelPage), () => nav.Header = "Channel" },
{ typeof(PlaylistPage), () => nav.Header = "Playlist" },
{ typeof(Search), () => nav.Header = "Search" },
{ typeof(Subscriptions), () => nav.Header = "Subscriptions" },
{ typeof(History), () => nav.Header = "History" },
{ typeof(Home), () => nav.Header = "Home" },
{ typeof(Downloads), () => nav.Header = "Downloads" }
{ typeof(Settings), () => nav.Header = resources.GetString("/Main/settings/Content") },
{ typeof(ChannelPage), () => nav.Header = resources.GetString("/Main/channel") },
{ typeof(PlaylistPage), () => nav.Header = resources.GetString("/Main/playlist") },
{ typeof(Search), () => nav.Header = resources.GetString("/Main/searchPlaceholder/PlaceholderText") },
{ typeof(Subscriptions), () => nav.Header = resources.GetString("/Main/subscriptions/Content") },
{ typeof(History), () => nav.Header = resources.GetString("/Main/history/Content") },
{ typeof(Home), () => nav.Header = resources.GetString("/Main/home/Content") },
{ typeof(Downloads), () => nav.Header = resources.GetString("/Main/downloads/Content") }
};
if (content.SourcePageType == typeof(Home) || content.SourcePageType == typeof(Settings) || content.SourcePageType == typeof(Subscriptions))
@@ -425,7 +449,7 @@ namespace FoxTube
if (videoPlaceholder.Content != null)
{
nav.Header = "Video";
nav.Header = resources.GetString("/Main/video");
nav.ExpandedModeThresholdWidth = short.MaxValue;
nav.IsPaneOpen = false;
}
@@ -437,24 +461,37 @@ namespace FoxTube
{
nav.CompactModeThresholdWidth = short.MaxValue;
nav.ExpandedModeThresholdWidth = short.MaxValue;
nav.OpenPaneLength = 0;
try
{
nav.IsPaneVisible = false;
}
catch
{
nav.CompactPaneLength = 0;
nav.OpenPaneLength = 0;
}
nav.Margin = new Thickness(0, -45, 0, 0);
}
else
{
nav.CompactModeThresholdWidth = 641;
if(videoPlaceholder.Content == null)
nav.ExpandedModeThresholdWidth = 1008;
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)
nav.IsPaneOpen = false;
else
{
nav.OpenPaneLength = 300;
nav.CompactPaneLength = 40;
}
SetTitleBar();
}
nav.UpdateLayout();
}
public void CloseVideo()
@@ -464,8 +501,8 @@ namespace FoxTube
ApplicationView.GetForCurrentView().ExitFullScreenMode();
Fullscreen(false);
}
(videoPlaceholder.Content as VideoPage).player.pointerCaptured = false;
videoPlaceholder.Content = null;
GC.Collect();
Window.Current.CoreWindow.PointerCursor = new CoreCursor(CoreCursorType.Arrow, 0);
MaximizeVideo();
@@ -544,14 +581,14 @@ namespace FoxTube
{
Dictionary<Type, Action> switchCase = new Dictionary<Type, Action>()
{
{ typeof(Settings), () => nav.Header = "Settings" },
{ typeof(ChannelPage), () => nav.Header = "Channel" },
{ typeof(PlaylistPage), () => nav.Header = "Playlist" },
{ typeof(Search), () => nav.Header = "Search" },
{ typeof(Subscriptions), () => nav.Header = "Subscriptions" },
{ typeof(History), () => nav.Header = "History" },
{ typeof(Home), () => nav.Header = "Home" },
{ typeof(Downloads), () => nav.Header = "Downloads" }
{ typeof(Settings), () => nav.Header = resources.GetString("/Main/settings/Content") },
{ typeof(ChannelPage), () => nav.Header = resources.GetString("/Main/channel") },
{ typeof(PlaylistPage), () => nav.Header = resources.GetString("/Main/playlist") },
{ typeof(Search), () => nav.Header = resources.GetString("/Main/searchPlaceholder/PlaceholderText") },
{ typeof(Subscriptions), () => nav.Header = resources.GetString("/Main/subscriptions/Content") },
{ typeof(History), () => nav.Header = resources.GetString("/Main/history/Content") },
{ typeof(Home), () => nav.Header = resources.GetString("/Main/home/Content") },
{ typeof(Downloads), () => nav.Header = resources.GetString("/Main/downloads/Content") }
};
try { switchCase[e.SourcePageType](); }
@@ -724,5 +761,10 @@ namespace FoxTube
{
((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>
<CommandBar Grid.Row="2" Grid.ColumnSpan="2">
<AppBarButton Icon="Globe" Label="Open in browser" Name="inBrowser" Click="inBrowser_Click"/>
<AppBarButton Icon="Add" Label="Add to" IsEnabled="False">
<AppBarButton x:Uid="/Playlist/openWeb" Icon="Globe" Label="Open in browser" Name="inBrowser" Click="inBrowser_Click"/>
<AppBarButton x:Uid="/Playlist/addTo" Icon="Add" Label="Add to" IsEnabled="False">
<AppBarButton.Flyout>
<MenuFlyout>
</MenuFlyout>
</AppBarButton.Flyout>
</AppBarButton>
<AppBarButton Icon="Refresh" Label="Refresh" Name="refresh" Click="refresh_Click"/>
<AppBarButton Icon="Share" Label="Share" Name="share" Click="share_Click"/>
<AppBarButton x:Uid="/Playlist/refresh" Icon="Refresh" Label="Refresh" Name="refresh" Click="refresh_Click"/>
<AppBarButton x:Uid="/Playlist/share" Icon="Share" Label="Share" Name="share" Click="share_Click"/>
</CommandBar>
<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 System;
using Windows.ApplicationModel.DataTransfer;
using Windows.ApplicationModel.Resources;
using Windows.Foundation;
using Windows.System;
using Windows.UI.Xaml;
@@ -57,7 +58,7 @@ namespace FoxTube.Pages
item = (await request.ExecuteAsync()).Items[0];
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;
channelName.Text = item.Snippet.ChannelTitle;
@@ -129,7 +130,7 @@ namespace FoxTube.Pages
item.Snippet.Thumbnails.Medium.Url,
item.Snippet.Title,
$"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="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">
<GridView Padding="5" SelectionMode="None">
<ComboBox Name="order" Header="Sort by" Width="150" SelectedIndex="0">
<ComboBoxItem Content="Relevance"/>
<ComboBoxItem Content="Upload date"/>
<ComboBoxItem Content="View count"/>
<ComboBoxItem Content="Rating"/>
<ComboBoxItem Content="Title"/>
<ComboBox x:Uid="/Search/order" Name="order" Header="Sort by" Width="150" SelectedIndex="0">
<ComboBoxItem x:Uid="/Search/relevance" Content="Relevance"/>
<ComboBoxItem x:Uid="/Search/update" Content="Upload date"/>
<ComboBoxItem x:Uid="/Search/views" Content="View count"/>
<ComboBoxItem x:Uid="/Search/rating" Content="Rating"/>
<ComboBoxItem x:Uid="/Search/title" Content="Title"/>
</ComboBox>
<ComboBox Name="type" Header="Type" Width="150" SelectedIndex="0" SelectionChanged="type_SelectionChanged">
<ComboBoxItem Content="All"/>
<ComboBoxItem Content="Video"/>
<ComboBoxItem Content="Channel"/>
<ComboBoxItem Content="Playlist"/>
<ComboBox x:Uid="/Search/type" Name="type" Header="Type" Width="150" SelectedIndex="0" SelectionChanged="type_SelectionChanged">
<ComboBoxItem x:Uid="/Search/all" Content="All"/>
<ComboBoxItem x:Uid="/Search/video" Content="Video"/>
<ComboBoxItem x:Uid="/Search/channel" Content="Channel"/>
<ComboBoxItem x:Uid="/Search/playlist" Content="Playlist"/>
</ComboBox>
<ComboBox Name="date" Header="Upload date" Width="150" SelectedIndex="0">
<ComboBoxItem Content="Anytime"/>
<ComboBoxItem Content="Last hour"/>
<ComboBoxItem Content="Today"/>
<ComboBoxItem Content="This week"/>
<ComboBoxItem Content="This month"/>
<ComboBoxItem Content="This year"/>
<ComboBox x:Uid="/Search/updateHeader" Name="date" Header="Upload date" Width="150" SelectedIndex="0">
<ComboBoxItem x:Uid="/Search/anytime" Content="Anytime"/>
<ComboBoxItem x:Uid="/Search/lasthr" Content="Last hour"/>
<ComboBoxItem x:Uid="/Search/today" Content="Today"/>
<ComboBoxItem x:Uid="/Search/week" Content="This week"/>
<ComboBoxItem x:Uid="/Search/month" Content="This month"/>
<ComboBoxItem x:Uid="/Search/year" Content="This year"/>
</ComboBox>
<ComboBox Visibility="Collapsed" Name="duration" Header="Duration" Width="150" SelectedIndex="0">
<ComboBoxItem Content="Any"/>
<ComboBoxItem Content="Long (&#x3E; 20 minutes)"/>
<ComboBoxItem Content="Medium"/>
<ComboBoxItem Content="Short (&#x3C; 4 minutes)"/>
<ComboBox x:Uid="/Search/duration" Visibility="Collapsed" Name="duration" Header="Duration" Width="150" SelectedIndex="0">
<ComboBoxItem x:Uid="/Search/any" Content="Any"/>
<ComboBoxItem x:Uid="/Search/long" Content="Long (&#x3E; 20 minutes)"/>
<ComboBoxItem x:Uid="/Search/medium" Content="Medium"/>
<ComboBoxItem x:Uid="/Search/short" Content="Short (&#x3C; 4 minutes)"/>
</ComboBox>
</GridView>
<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>
<Flyout>
<ListView Name="features" SelectionMode="Multiple" Header="Features">
<ListView x:Uid="/Search/featuresHeader" Name="features" SelectionMode="Multiple" Header="Features">
<TextBlock Text="HD"/>
<TextBlock Text="3D"/>
<TextBlock Text="Subtitles/CC"/>
<TextBlock Text="Live"/>
<TextBlock Text="Creative Commons"/>
<TextBlock x:Uid="/Search/subs" Text="Subtitles/CC"/>
<TextBlock x:Uid="/Search/live" Text="Live"/>
<TextBlock x:Uid="/Search/cc" Text="Creative Commons"/>
</ListView>
</Flyout>
</Button.Flyout>
</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>
<pages:VideoGrid/>
+10 -8
View File
@@ -8,7 +8,7 @@ using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
using Windows.System;
using System.Globalization;
using Windows.ApplicationModel.Resources;
namespace FoxTube
{
@@ -17,6 +17,8 @@ namespace FoxTube
/// </summary>
public sealed partial class Search : Page
{
ResourceLoader resources = ResourceLoader.GetForCurrentView("Search");
public SearchParameters Parameters;
SearchResource.ListRequest request;
string nextToken;
@@ -95,10 +97,10 @@ namespace FoxTube
(grid.Children[1] as CommandBar).Visibility = Visibility.Collapsed;
}
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.RelevanceLanguage = CultureInfo.GetCultures(CultureTypes.AllCultures).Find(i => i.IetfLanguageTag == SettingsStorage.Region).TwoLetterISOLanguageName;
request.RegionCode = SettingsStorage.Region;
request.RelevanceLanguage = SettingsStorage.RelevanceLanguage;
request.MaxResults = 48;
try
@@ -130,8 +132,8 @@ namespace FoxTube
features.SelectedItems.Add(features.Items[4]);
SearchListResponse response = await request.ExecuteAsync();
searchTerm.Text = $"Search results for: {Parameters.Term}";
resultsCount.Text = $"Found: {SetResults(response.PageInfo.TotalResults)} item(s)";
searchTerm.Text = $"{resources.GetString("/Search/header")} '{Parameters.Term}'";
resultsCount.Text = $"{resources.GetString("/Search/found")}: {SetResults(response.PageInfo.TotalResults)} {resources.GetString("/Search/items")}";
if (!string.IsNullOrWhiteSpace(response.NextPageToken))
nextToken = response.NextPageToken;
else
@@ -158,12 +160,12 @@ namespace FoxTube
if(filters.Visibility == Visibility.Collapsed)
{
filters.Visibility = Visibility.Visible;
toggleFilters.Content = "Hide filters \xE014";
toggleFilters.Content = resources.GetString("/Search/hideFilters");
}
else
{
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 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/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"/>
+2 -8
View File
@@ -19,6 +19,7 @@
<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"/>
</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/safeSearch" Header="SafeSearch" MinWidth="250" Name="safeSearch" SelectionChanged="safeSearch_SelectionChanged">
<ComboBoxItem x:Uid="/General/moderate" Content="Moderate"/>
@@ -29,20 +30,13 @@
<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">
<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>
<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"/>
<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 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"/>
<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.UI;
using Windows.UI.Xaml;
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
{
@@ -17,18 +20,10 @@ namespace FoxTube.Pages.SettingsPages
InitializeComponent();
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;
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);
mobileWarning.IsOn = SettingsStorage.CheckConnection;
autoplay.IsOn = SettingsStorage.Autoplay;
@@ -48,6 +43,37 @@ namespace FoxTube.Pages.SettingsPages
system.IsChecked = true;
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)
@@ -79,9 +105,14 @@ namespace FoxTube.Pages.SettingsPages
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)
{
SettingsStorage.Region = CultureInfo.GetCultures(CultureTypes.AllCultures)[region.SelectedIndex].Name;
SettingsStorage.Region = ((ComboBoxItem)region.SelectedItem).Tag.ToString();
}
private void safeSearch_SelectionChanged(object sender, SelectionChangedEventArgs e)
+9 -19
View File
@@ -2,56 +2,46 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using FoxTube.Classes;
using System.Xml;
using Windows.Storage;
using System.Diagnostics;
using Windows.UI.Popups;
// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238
using System.Xml;
namespace FoxTube.Pages.SettingsPages
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// Page with changelogs and dev messages
/// </summary>
public sealed partial class Inbox : Page
{
List<InboxItem> items = new List<InboxItem>();
public Inbox()
{
this.InitializeComponent();
InitializeComponent();
}
public void LoadItems()
public async void LoadItems()
{
try
{
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)
items.Add(new InboxItem(
e.GetAttribute("version"),
e["content"].InnerText,
e["content"][SettingsStorage.Language].InnerText,
e.GetAttribute("time")));
doc.Load("http://foxgame-studio.000webhostapp.com/foxtube-messages.xml");
foreach (XmlElement e in doc["posts"].ChildNodes)
items.Add(new InboxItem(
e["header"].InnerText,
e["content"].InnerText,
DateTime.Parse(e["time"].InnerText),
e["content"][SettingsStorage.Language].InnerText,
DateTime.Parse(e.GetAttribute("time")),
e["id"].InnerText
));
+5 -19
View File
@@ -1,39 +1,25 @@
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 FoxTube.Controls.Adverts;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
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
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// Items cards container
/// </summary>
public sealed partial class VideoGrid : Page
{
public VideoGrid()
{
this.InitializeComponent();
InitializeComponent();
}
public void Add(UIElement card)
{
list.Items.Add(card);
/*if (list.Items.Count % 10 == 0)
list.Items.Add(new CardAdvert());*/
empty.Visibility = Visibility.Collapsed;
}
+10 -37
View File
@@ -6,8 +6,6 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
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"
mc:Ignorable="d">
@@ -37,12 +35,6 @@
<local:VideoPlayer/>
<PivotItem Header="Description" Name="descriptionPanel">
<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"/>
<Grid>
<Grid.RowDefinitions>
@@ -55,7 +47,7 @@
<StackPanel Orientation="Vertical" Grid.Column="1" Padding="5" VerticalAlignment="Center">
<TextBlock Name="channelName" Text="[Channel name]" FontSize="18"/>
<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>
</Button>
@@ -82,38 +74,19 @@
</StackPanel>
</Grid>
<TextBlock Name="description" Text="[Description]" IsTextSelectionEnabled="True" TextWrapping="WrapWholeWords"/>
<Grid Margin="0,20,0,0">
<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>
<TextBlock Margin="0,20" Name="category" Text="Category: "/>
</StackPanel>
</PivotItem>
</StackPanel>
</ScrollViewer>
<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>
<MenuFlyout x:Name="downloadSelector"/>
</AppBarButton.Flyout>
</AppBarButton>
<AppBarButton Name="addTo" Label="Add to" Icon="Add">
<AppBarButton x:Uid="/VideoPage/addTo" Name="addTo" Label="Add to" Icon="Add">
<AppBarButton.Flyout>
<Flyout>
<ScrollViewer Margin="-12" MaxHeight="300">
@@ -154,14 +127,14 @@
</Flyout>
</AppBarButton.Flyout>
</AppBarButton>
<AppBarButton Name="refresh" Click="refresh_Click" Icon="Refresh" Label="Refresh page"/>
<AppBarButton 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/refresh" Name="refresh" Click="refresh_Click" Icon="Refresh" Label="Refresh page"/>
<AppBarButton x:Uid="/VideoPage/share" Name="share" Click="share_Click" Icon="Share" Label="Share"/>
<AppBarButton x:Uid="/VideoPage/openWeb" Name="openBrowser" Click="openBrowser_Click" Icon="Globe" Label="Open in browser"/>
</CommandBar>
<Grid Grid.Column="1" Name="tabsPlaceholder">
<Pivot Grid.Row="1" Name="pivot" SelectedIndex="0" IsHeaderItemsCarouselEnabled="False">
<PivotItem Header="Suggestions">
<PivotItem x:Uid="/VideoPage/related" Header="Suggestions">
<ScrollViewer>
<StackPanel>
<controls1:Advert/>
@@ -169,10 +142,10 @@
</StackPanel>
</ScrollViewer>
</PivotItem>
<PivotItem Header="Comments" Name="commentsPlaceholder">
<PivotItem x:Uid="/VideoPage/comments" Header="Comments" Name="commentsPlaceholder">
<pages:CommentsPage/>
</PivotItem>
<PivotItem Header="Playlist" Name="playlist">
<PivotItem x:Uid="/VideoPage/playlist" Header="Playlist" Name="playlist">
<ScrollViewer>
<StackPanel>
<StackPanel Padding="8" Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}">
+136 -72
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.Diagnostics;
using System.Globalization;
using System.Linq;
using Windows.ApplicationModel.DataTransfer;
using Windows.ApplicationModel.Resources;
using Windows.Foundation;
using Windows.Storage;
using Windows.System;
using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
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 System.Diagnostics;
using Windows.ApplicationModel.DataTransfer;
using Windows.Storage;
using Windows.UI;
using FoxTube.Controls;
using YoutubeExplode.Models.MediaStreams;
using Windows.UI.Xaml.Navigation;
using YoutubeExplode;
using YoutubeExplode.Models.MediaStreams;
namespace FoxTube.Pages
{
@@ -42,10 +45,10 @@ namespace FoxTube.Pages
/// </summary>
public sealed partial class VideoPage : Page
{
ApplicationDataContainer settings = ApplicationData.Current.LocalSettings;
ResourceLoader resources = ResourceLoader.GetForCurrentView("VideoPage");
public string videoId;
string playlistId = null;
public string playlistId = null;
public Video item;
bool wide;
@@ -57,6 +60,8 @@ namespace FoxTube.Pages
public CommentsPage comments;
public LoadingPage loading;
DispatcherTimer liveTimer;
public VideoPage()
{
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);
}
@@ -107,21 +115,47 @@ namespace FoxTube.Pages
videoId = ids[0];
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>();
VideoPlaylistItem selection = null;
//Retrieving data
PlaylistsResource.ListRequest playlistRequest = SecretsVault.Service.Playlists.List("snippet,contentDetails");
playlistRequest.Id = ids[1];
playlistRequest.Id = id;
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");
listRequest.MaxResults = 50;
listRequest.PlaylistId = ids[1];
listRequest.PlaylistId = id;
PlaylistItemListResponse listResponse = await listRequest.ExecuteAsync();
foreach (PlaylistItem i in listResponse.Items)
@@ -150,39 +184,49 @@ namespace FoxTube.Pages
for (int k = 0; k < items.Count; k++)
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}";
playlistList.ItemsSource = items;
playlistList.SelectedItem = selection;
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;
Methods.FormatText(ref description, item.Snippet.Description);
publishedAt.Text = item.Snippet.PublishedAt.ToString();
if (item.Status.License == "youtube")
license.Text = "Standard YouTube License";
else license.Text = "Creative Commons Attribution license (reuse allowed)";
//Setting channel button
ChannelsResource.ListRequest channelRequest = SecretsVault.Service.Channels.List("snippet, statistics");
channelRequest.Id = item.Snippet.ChannelId;
var item1 = (await channelRequest.ExecuteAsync()).Items[0];
VideoCategoriesResource.ListRequest categoryRequest = SecretsVault.Service.VideoCategories.List("snippet");
categoryRequest.Id = item.Snippet.CategoryId;
category.Text = (await categoryRequest.ExecuteAsync()).Items[0].Snippet.Title;
channelAvatar.ProfilePicture = new BitmapImage(new Uri(item1.Snippet.Thumbnails.Medium.Url));
channelName.Text = item.Snippet.ChannelTitle;
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}";
likes.Text = $"{item.Statistics.LikeCount:0,0}";
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)
{
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")
{
userRating = Rating.Like;
@@ -200,7 +244,7 @@ namespace FoxTube.Pages
{
subscribe.Background = new SolidColorBrush(Colors.Transparent);
subscribe.Foreground = new SolidColorBrush(Colors.Gray);
subscribe.Content = "Subscribed";
subscribe.Content = resources.GetString("/Cards/unsubscribe");
}
}
subscribe.Visibility = Visibility.Visible;
@@ -212,29 +256,45 @@ namespace FoxTube.Pages
subscribe.Visibility = Visibility.Collapsed;
}
ChannelsResource.ListRequest channelRequest = SecretsVault.Service.Channels.List("snippet, statistics");
channelRequest.Id = item.Snippet.ChannelId;
var item1 = (await channelRequest.ExecuteAsync()).Items[0];
//Initializing player
player.Initialize(item, item1.Snippet.Thumbnails.Medium.Url);
channelAvatar.ProfilePicture = new BitmapImage(new Uri(item1.Snippet.Thumbnails.Medium.Url));
channelName.Text = item.Snippet.ChannelTitle;
subscribers.Text = $"{item1.Statistics.SubscriberCount:0,0} subscribers";
LoadRelatedVideos();
}
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);
player.Initialize(item, item1.Snippet.Thumbnails.Medium.Url);
LoadRelatedVideos();
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()
@@ -255,8 +315,8 @@ namespace FoxTube.Pages
MenuFlyoutItem audioItem = new MenuFlyoutItem()
{
Text = "Audio track",
Tag = new object[] { infoSet.Audio[0], "Audio only" }
Text = resources.GetString("/VideoPage/audio"),
Tag = new object[] { infoSet.Audio[0], resources.GetString("/Cards/audioOnly") }
};
audioItem.Click += downloadItemSelected;
downloadSelector.Items.Add(audioItem);
@@ -275,8 +335,10 @@ namespace FoxTube.Pages
async void LoadRelatedVideos()
{
SearchResource.ListRequest request = SecretsVault.Service.Search.List("snippet");
request.RegionCode = SettingsStorage.Region;
request.RelevanceLanguage = SettingsStorage.RelevanceLanguage;
request.RelatedToVideoId = videoId;
request.SafeSearch = (SearchResource.ListRequest.SafeSearchEnum)(int)settings.Values["safeSearch"];
request.SafeSearch = (SearchResource.ListRequest.SafeSearchEnum)SettingsStorage.SafeSearch;
request.MaxResults = 20;
request.Type = "video";
@@ -320,10 +382,10 @@ namespace FoxTube.Pages
private async void openBrowser_Click(object sender, RoutedEventArgs e)
{
player.Pause();
string timecode = player.elapsed.TotalSeconds > 10 ?
"&t=" + (int)player.elapsed.TotalSeconds + "s" : string.Empty;
string timecode = player.Elapsed.TotalSeconds > 10 ?
"&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)
@@ -344,6 +406,8 @@ namespace FoxTube.Pages
mainContent.Children.Remove(pivot);
tabsPlaceholder.Children.Add(pivot);
pivot.SelectedItem = descriptionPanel;
descriptionPanel.Opacity = 1;
pivot.Items.RemoveAt(0);
mainContent.Children.Add(descriptionPanel);
@@ -373,7 +437,7 @@ namespace FoxTube.Pages
item.Snippet.Thumbnails.Medium.Url,
item.Snippet.Title,
$"https://www.youtube.com/watch?v={videoId}",
"video");
resources.GetString("/Cards/videoShare"));
}
private void share_Click(object sender, RoutedEventArgs e)
@@ -388,10 +452,10 @@ namespace FoxTube.Pages
{
case Rating.Like:
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);
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--;
await SecretsVault.Service.Videos.Rate(videoId, VideosResource.RateRequest.RatingEnum.Dislike).ExecuteAsync();
@@ -400,7 +464,7 @@ namespace FoxTube.Pages
case Rating.None:
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++;
await SecretsVault.Service.Videos.Rate(videoId, VideosResource.RateRequest.RatingEnum.Dislike).ExecuteAsync();
@@ -409,7 +473,7 @@ namespace FoxTube.Pages
case Rating.Dislike:
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--;
await SecretsVault.Service.Videos.Rate(videoId, VideosResource.RateRequest.RatingEnum.None).ExecuteAsync();
break;
@@ -423,10 +487,10 @@ namespace FoxTube.Pages
{
case Rating.Dislike:
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);
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++;
await SecretsVault.Service.Videos.Rate(videoId, VideosResource.RateRequest.RatingEnum.Like).ExecuteAsync();
@@ -435,7 +499,7 @@ namespace FoxTube.Pages
case Rating.None:
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.Value++;
await SecretsVault.Service.Videos.Rate(videoId, VideosResource.RateRequest.RatingEnum.Like).ExecuteAsync();
@@ -445,7 +509,7 @@ namespace FoxTube.Pages
case Rating.Like:
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.Value--;
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.Foreground = new SolidColorBrush(Colors.Gray);
subscribe.Content = "Subscribed";
subscribe.Content = resources.GetString("/Cards/unsubscribe");
}
else
{
subscribe.Background = new SolidColorBrush(Colors.Red);
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">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="description" 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>
<data name="box.PlaceholderText" xml:space="preserve">
<value>Send a message</value>
</data>
<data name="export" xml:space="preserve">
<value>Export to PC (.zip)</value>
<data name="moder.Text" xml:space="preserve">
<value>Moderator</value>
</data>
<data name="guide0" xml:space="preserve">
<value>It's quite simple:</value>
<data name="owner.Text" xml:space="preserve">
<value>Chat owner</value>
</data>
<data name="guide1" xml:space="preserve">
<value>1. Choose language you you want to translate on</value>
<data name="sponsor.Text" xml:space="preserve">
<value>Sponsor</value>
</data>
<data name="guide2" xml:space="preserve">
<value>2. Import language pack to your PC</value>
<data name="verified.Text" xml:space="preserve">
<value>Verified</value>
</data>
<data name="header" xml:space="preserve">
<value>Help us translate this app</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 name="welcome.Text" xml:space="preserve">
<value>Welcome to the chat room</value>
</data>
</root>
+45
View File
@@ -117,19 +117,64 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="comments" xml:space="preserve">
<value>comments</value>
</data>
<data name="date.Text" xml:space="preserve">
<value>Date</value>
</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">
<value>Show more</value>
</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">
<value>Relevance</value>
</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">
<value>Sort by: </value>
</data>
<data name="textbox.PlaceholderText" xml:space="preserve">
<value>Add a public comment</value>
</data>
<data name="yes" xml:space="preserve">
<value>Yes</value>
</data>
</root>

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