Archived
1
0

Merged PR 26: Submission #6

##Potential 1.0 release candidate. If there is no critical issues will be found this submission will be pushed to public
- Updated package version
- In-video advert now doesn't appear on minimized playback
- Fixed small header appearing on channel page
- Fixed home page loading after in long active sessions
- Optimization, bugfixes and refactoring
- Fixed crash when local watch history reaches 87 entries (now its capacity is 200)
- Added backward navigation to video page
- Improved authentication process
- Removed outdated logo from 'About' page and updated Twitter link
- Updated package version
This commit is contained in:
Michael Gordeev
2019-05-27 18:23:39 +00:00
63 changed files with 1194 additions and 1263 deletions
+2 -1
View File
@@ -258,4 +258,5 @@ paket-files/
# Python Tools for Visual Studio (PTVS) # Python Tools for Visual Studio (PTVS)
__pycache__/ __pycache__/
*.pyc *.pyc
/Src/Trailer
+61 -61
View File
@@ -10,7 +10,6 @@ using System.Xml;
using Windows.ApplicationModel; using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation; using Windows.ApplicationModel.Activation;
using Windows.ApplicationModel.Background; using Windows.ApplicationModel.Background;
using Windows.ApplicationModel.Core;
using Windows.Globalization; using Windows.Globalization;
using Windows.Storage; using Windows.Storage;
using Windows.System.Power; using Windows.System.Power;
@@ -57,7 +56,7 @@ namespace FoxTube
public async void CheckVersion() public async void CheckVersion()
{ {
PackageVersion ver = Package.Current.Id.Version; PackageVersion ver = Package.Current.Id.Version;
if (SettingsStorage.Version != $"{ver.Major}.{ver.Minor}") if (SettingsStorage.Version != $"{ver.Major}.{ver.Minor}.{ver.Build}")
{ {
try try
{ {
@@ -68,40 +67,34 @@ namespace FoxTube
ToastNotificationManager.CreateToastNotifier().Show(Background.Notification.GetChangelogToast(e.GetAttribute("version"))); ToastNotificationManager.CreateToastNotifier().Show(Background.Notification.GetChangelogToast(e.GetAttribute("version")));
SettingsStorage.Version = $"{ver.Major}.{ver.Minor}"; SettingsStorage.Version = $"{ver.Major}.{ver.Minor}.{ver.Build}";
} }
catch catch (Exception e)
{ {
Debug.WriteLine("Unable to retrieve changelog"); Analytics.TrackEvent("Unable to retrieve changelog", new Dictionary<string, string>
{
{ "Exception", e.GetType().ToString() },
{ "Message", e.Message },
{ "App version", $"{ver.Major}.{ver.Minor}.{ver.Revision}.{ver.Build}" }
});
} }
} }
} }
protected override void OnLaunched(LaunchActivatedEventArgs e) protected override void OnLaunched(LaunchActivatedEventArgs e)
{ {
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (!(Window.Current.Content is Frame rootFrame)) if (!(Window.Current.Content is Frame rootFrame))
{ {
// Create a Frame to act as the navigation context and navigate to the first page
rootFrame = new Frame(); rootFrame = new Frame();
rootFrame.NavigationFailed += OnNavigationFailed; rootFrame.NavigationFailed += OnNavigationFailed;
// Place the frame in the current Window
Window.Current.Content = rootFrame; Window.Current.Content = rootFrame;
} }
if (e.PrelaunchActivated == false) if (e.PrelaunchActivated == false)
{ {
if (rootFrame.Content == null) if (rootFrame.Content == null)
{
// When the navigation stack isn't restored navigate to the first page,
// configuring the new page by passing required information as a navigation
// parameter
rootFrame.Navigate(typeof(MainPage), e.Arguments); rootFrame.Navigate(typeof(MainPage), e.Arguments);
}
// Ensure the current window is active
Window.Current.Activate(); Window.Current.Activate();
} }
@@ -153,7 +146,7 @@ namespace FoxTube
BackgroundTaskRegistration registration = builder.Register(); BackgroundTaskRegistration registration = builder.Register();
} }
protected async override void OnBackgroundActivated(BackgroundActivatedEventArgs args) protected override void OnBackgroundActivated(BackgroundActivatedEventArgs args)
{ {
var deferral = args.TaskInstance.GetDeferral(); var deferral = args.TaskInstance.GetDeferral();
base.OnBackgroundActivated(args); base.OnBackgroundActivated(args);
@@ -167,29 +160,36 @@ namespace FoxTube
case "later": case "later":
try try
{ {
if (!SecretsVault.IsAuthorized) SecretsVault.AuthorizationStateChanged += async (s, e) =>
SecretsVault.CheckAuthorization(false);
if (!SecretsVault.IsAuthorized)
throw new Exception("Not authenticated");
PlaylistItem item = new PlaylistItem()
{ {
Snippet = new PlaylistItemSnippet() if ((bool)e[0])
{ {
ResourceId = new ResourceId() PlaylistItem item = new PlaylistItem()
{ {
Kind = "youtube#video", Snippet = new PlaylistItemSnippet()
VideoId = arguments[1] {
}, ResourceId = new ResourceId()
PlaylistId = "WL" {
Kind = "youtube#video",
VideoId = arguments[1]
},
PlaylistId = "WL"
}
};
await SecretsVault.Service.PlaylistItems.Insert(item, "snippet").ExecuteAsync();
} }
}; };
SecretsVault.CheckAuthorization(false);
await SecretsVault.Service.PlaylistItems.Insert(item, "snippet").ExecuteAsync();
} }
catch (Exception e) catch (Exception e)
{ {
Debug.WriteLine(e.Message); Analytics.TrackEvent("Failed to add video to WL from toast", new Dictionary<string, string>
{
{ "Exception", e.GetType().ToString() },
{ "Message", e.Message },
{ "Video ID", arguments[1] }
});
} }
break; break;
} }
@@ -211,46 +211,46 @@ namespace FoxTube
} }
if (rootFrame.Content == null) if (rootFrame.Content == null)
{
rootFrame.Navigate(typeof(MainPage)); rootFrame.Navigate(typeof(MainPage));
}
Window.Current.Activate(); Window.Current.Activate();
switch (e.Kind) switch (e.Kind)
{ {
case ActivationKind.Protocol:
break;
case ActivationKind.ToastNotification: case ActivationKind.ToastNotification:
string[] args = (e as ToastNotificationActivatedEventArgs).Argument.Split('|'); if (SecretsVault.IsAuthorized)
switch (args[0]) ProcessToast((e as ToastNotificationActivatedEventArgs).Argument);
{ else
case "changelog": SecretsVault.AuthorizationStateChanged += (s, arg) => ProcessToast((e as ToastNotificationActivatedEventArgs).Argument);
case "inbox":
Methods.MainPage.GoToDeveloper(args[1]);
break;
case "video":
Methods.MainPage.GoToVideo(args[1]);
break;
case "channel":
Methods.MainPage.GoToChannel(args[1]);
break;
case "download":
Methods.MainPage.GoToDownloads();
break;
case "dcancel":
DownloadAgent.Cancel(args[1]);
break;
}
break; break;
} }
} }
void Launch(string e = null) private void ProcessToast(string arg)
{ {
string[] args = arg.Split('|');
switch (args[0])
{
case "changelog":
case "inbox":
Methods.MainPage.GoToDeveloper(args[1]);
break;
case "video":
Methods.MainPage.GoToVideo(args[1]);
break;
case "channel":
Methods.MainPage.GoToChannel(args[1]);
break;
case "download":
Methods.MainPage.GoToDownloads();
break;
case "dcancel":
DownloadAgent.Cancel(args[1]);
break;
}
} }
void OnNavigationFailed(object sender, NavigationFailedEventArgs e) void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
@@ -265,6 +265,7 @@ namespace FoxTube
sw.Stop(); sw.Stop();
SettingsStorage.Uptime += sw.Elapsed; SettingsStorage.Uptime += sw.Elapsed;
HistorySet.Save();
SettingsStorage.SaveData(); SettingsStorage.SaveData();
DownloadAgent.QuitPrompt(); DownloadAgent.QuitPrompt();
Controls.Player.ManifestGenerator.ClearRoaming(); Controls.Player.ManifestGenerator.ClearRoaming();
@@ -277,7 +278,6 @@ namespace FoxTube
Analytics.TrackEvent("The app crashed", new Dictionary<string, string>() Analytics.TrackEvent("The app crashed", new Dictionary<string, string>()
{ {
{ "Exception", e.Exception.GetType().ToString() }, { "Exception", e.Exception.GetType().ToString() },
{ "Class", e.ToString() },
{ "Details", e.Message } { "Details", e.Message }
}); });
} }
+28 -2
View File
@@ -1,6 +1,32 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<items> <items>
<item time="2019-04-28" version="0.6"> <item time="2019-05-21" version="0.6.2">
<content>
<en-US>##[Patch #1]
### What's new:
- In-video advert now doesn't appear on minimized playback
- Fixed small header appearing on channel page
- Fixed home page loading in long active sessions
- Optimization and bugfixes
- Fixed crash when local watch history reaches 87 entries (now its capacity is 200)
- Added backward navigation to video page
- Improved authentication process
- Removed outdated logo from 'About' page and updated Twitter link
</en-US>
<ru-RU>##[Патч #1]
### Что нового:
- Теперь реклама в видео не появляется в компактном режиме
- Исправлено появление меленького заголовка на странице канала
- Исправлено отображение видео на домашней странице при долгой активной сессии
- Оптимизация и исправление ошибок
- Исправлен сбой приложения при достижении локальной историей 87 записей (текущая емкость журнала - 200 записей)
- Добавлена обратная навигация для страниц просмотра
- Улучшен процесс аутентификации
- Удален старый логотип с страницы 'О приложении' и обновлена ссылка на Твиттер
</ru-RU>
</content>
</item>
<item time="2019-05-20" version="0.6">
<content> <content>
<en-US>##[Final pre-release version] <en-US>##[Final pre-release version]
### What's new: ### What's new:
@@ -70,7 +96,7 @@ This is the final pre-release minor version. That means that until 1.0 release t
- Fixed header titles - Fixed header titles
- Some items were moved from menu to header - Some items were moved from menu to header
- Added "Share" button to video cards - Added "Share" button to video cards
- Added "Delete video from playlist" button to video cards on playlist page\ - Added "Delete video from playlist" button to video cards on playlist page
- Improved channel cover quality - Improved channel cover quality
- If available, shows localized titles and descriptions (based on "Search relevance language" parameter set in settings) - If available, shows localized titles and descriptions (based on "Search relevance language" parameter set in settings)
- Updated russian localization - Updated russian localization
+22 -14
View File
@@ -6,13 +6,14 @@ using YoutubeExplode.Models.MediaStreams;
using Google.Apis.YouTube.v3.Data; using Google.Apis.YouTube.v3.Data;
using FoxTube.Controls; using FoxTube.Controls;
using FoxTube.Pages; using FoxTube.Pages;
using Microsoft.AppCenter.Analytics;
namespace FoxTube namespace FoxTube
{ {
public static class DownloadAgent public static class DownloadAgent
{ {
public static List<DownloadItem> items = new List<DownloadItem>(); public static List<DownloadItem> Items { get; set; } = new List<DownloadItem>();
private static ApplicationDataContainer settings = ApplicationData.Current.LocalSettings; private static readonly ApplicationDataContainer settings = ApplicationData.Current.LocalSettings;
public static Downloads Page { get; set; } public static Downloads Page { get; set; }
public static StorageFolder Downloads { get; set; } public static StorageFolder Downloads { get; set; }
@@ -21,45 +22,52 @@ namespace FoxTube
Downloads = await KnownFolders.VideosLibrary.CreateFolderAsync("FoxTube", CreationCollisionOption.OpenIfExists); Downloads = await KnownFolders.VideosLibrary.CreateFolderAsync("FoxTube", CreationCollisionOption.OpenIfExists);
try try
{ {
List<DownloadItemContainer> containers = JsonConvert.DeserializeObject<List<DownloadItemContainer>>((string)settings.Values["downloads"]); List<DownloadItemContainer> containers = JsonConvert.DeserializeObject<List<DownloadItemContainer>>((string)settings.Values[$"downloads"]);
containers.ForEach(i => items.Add(new DownloadItem(i))); containers.ForEach(i => Items.Add(new DownloadItem(i)));
}
catch (Exception e)
{
Analytics.TrackEvent("Failed to load downloads history", new Dictionary<string, string>
{
{ "Exception", e.GetType().ToString() },
{ "Message", e.Message }
});
} }
catch { }
} }
public static void Add(MediaStreamInfo info, Video meta, string qualty) public static void Add(MediaStreamInfo info, Video meta, string qualty)
{ {
items.Insert(0, new DownloadItem(info, meta, qualty)); Items.Insert(0, new DownloadItem(info, meta, qualty));
} }
public static void Remove(DownloadItem item) public static void Remove(DownloadItem item)
{ {
try { Page.Remove(item); } Page?.Remove(item);
catch { } Items.Remove(item);
items.Remove(item);
} }
public static void Cancel(string id) public static void Cancel(string id)
{ {
DownloadItem item = items.Find(i => i.Container.Id == id); DownloadItem item = Items.Find(i => i.Container.Id == id);
if (item != null) if (item != null)
item.Cancel(); item.Cancel();
} }
public static void QuitPrompt() public static void QuitPrompt()
{ {
foreach (DownloadItem i in items.FindAll(i => !i.Container.IsDownloaded)) foreach (DownloadItem i in Items.FindAll(i => !i.Container.IsDownloaded))
{ {
i.Cancel(); i.Cancel();
items.Remove(i); Items.Remove(i);
} }
List<DownloadItemContainer> containers = new List<DownloadItemContainer>(); List<DownloadItemContainer> containers = new List<DownloadItemContainer>();
items.ForEach(i => containers.Add(i.Container)); Items.ForEach(i => containers.Add(i.Container));
string data = JsonConvert.SerializeObject(containers); string data = JsonConvert.SerializeObject(containers);
settings.Values["downloads"] = data; settings.Values[$"downloads"] = data;
} }
} }
} }
+87
View File
@@ -0,0 +1,87 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using Windows.Storage;
namespace FoxTube
{
public class HistoryItem
{
public string Id { get; set; }
public TimeSpan LeftOn { get; set; } = TimeSpan.FromSeconds(0);
}
public static class HistorySet
{
public static List<HistoryItem> Items { get; set; } = new List<HistoryItem>();
public static void Update(HistoryItem item)
{
if (!SecretsVault.IsAuthorized)
return;
Items.RemoveAll(i => i.Id == item.Id);
Items.Insert(0, item);
if (Items.Count > 200)
Items.RemoveRange(200, Items.Count - 200);
Save();
}
public static void Delete(HistoryItem item)
{
if (!SecretsVault.IsAuthorized)
return;
Items.Remove(item);
Save();
}
public static void Clear()
{
if (!SecretsVault.IsAuthorized)
return;
Items.Clear();
Save();
}
public static void Save()
{
List<HistoryItem>[] parts = new List<HistoryItem>[4]
{
new List<HistoryItem>(), new List<HistoryItem>(),
new List<HistoryItem>(), new List<HistoryItem>()
};
foreach(HistoryItem i in Items)
if (parts[0].Count < 50)
parts[0].Add(i);
else
{
if (parts[1].Count < 50)
parts[1].Add(i);
else
{
if (parts[2].Count < 50)
parts[2].Add(i);
else
parts[3].Add(i);
}
}
for(int k = 0; k < parts.Length; k++)
ApplicationData.Current.RoamingSettings.Values[$"history-{SecretsVault.AccountId}-level{k}"] = JsonConvert.SerializeObject(parts[k]);
}
public static void Load()
{
try
{
for (int k = 0; k < 4; k++)
Items.AddRange(JsonConvert.DeserializeObject<List<HistoryItem>>(ApplicationData.Current.RoamingSettings.Values[$"history-{SecretsVault.AccountId}-level{k}"] as string));
}
catch { }
}
}
}
+3 -3
View File
@@ -3,7 +3,7 @@ using Windows.ApplicationModel.Resources;
namespace FoxTube.Classes namespace FoxTube.Classes
{ {
public enum InboxItemType { Default, PatchNote} public enum InboxItemType { Default, PatchNote }
public class InboxItem public class InboxItem
{ {
@@ -59,11 +59,11 @@ namespace FoxTube.Classes
} }
public InboxItem(string version, string content, string timeStamp) public InboxItem(string version, string content, DateTime timeStamp)
{ {
Type = InboxItemType.PatchNote; Type = InboxItemType.PatchNote;
Content = content; Content = content;
TimeStamp = DateTime.Parse(timeStamp); TimeStamp = timeStamp;
Id = version; Id = version;
} }
+12 -10
View File
@@ -1,6 +1,7 @@
using AngleSharp.Dom.Html; using AngleSharp.Dom.Html;
using AngleSharp.Parser.Html; using AngleSharp.Parser.Html;
using Google.Apis.YouTube.v3.Data; using Google.Apis.YouTube.v3.Data;
using Microsoft.AppCenter.Analytics;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -23,17 +24,11 @@ namespace FoxTube.Controls.Player
public static async Task<Uri> GetManifest(Video meta, VideoStreamInfo requestedQuality, MediaStreamInfoSet list) public static async Task<Uri> GetManifest(Video meta, VideoStreamInfo requestedQuality, MediaStreamInfoSet list)
{ {
StorageFile manifest; StorageFile manifest;
try try { manifest = await roaming.CreateFileAsync("manifest.mpd", CreationCollisionOption.ReplaceExisting); }
{ catch { manifest = await roaming.CreateFileAsync("manifest.mpd", CreationCollisionOption.GenerateUniqueName); }
manifest = await roaming.CreateFileAsync("manifest.mpd", CreationCollisionOption.ReplaceExisting);
}
catch
{
manifest = await roaming.CreateFileAsync("manifest.mpd", CreationCollisionOption.GenerateUniqueName);
}
try
{
try
{
XmlDocument doc = new XmlDocument(); XmlDocument doc = new XmlDocument();
XmlElement mpd = doc.CreateElement("MPD"); XmlElement mpd = doc.CreateElement("MPD");
@@ -75,6 +70,13 @@ namespace FoxTube.Controls.Player
} }
catch (Exception e) catch (Exception e)
{ {
Analytics.TrackEvent("Failed to generate manifest", new Dictionary<string, string>
{
{ "Exception", e.GetType().ToString() },
{ "Message", e.Message },
{ "Video ID", meta.Id },
{ "Requested quality", requestedQuality.VideoQualityLabel }
});
return null; return null;
} }
} }
+30 -80
View File
@@ -1,4 +1,5 @@
using FoxTube.Pages; using FoxTube.Pages;
using Microsoft.AppCenter.Analytics;
using Newtonsoft.Json; using Newtonsoft.Json;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -10,7 +11,6 @@ using System.Xml;
using Windows.ApplicationModel.Core; using Windows.ApplicationModel.Core;
using Windows.ApplicationModel.DataTransfer; using Windows.ApplicationModel.DataTransfer;
using Windows.ApplicationModel.Resources; using Windows.ApplicationModel.Resources;
using Windows.Storage;
using Windows.Storage.Streams; using Windows.Storage.Streams;
using Windows.System; using Windows.System;
using Windows.UI.Xaml; using Windows.UI.Xaml;
@@ -21,64 +21,21 @@ using YoutubeExplode.Models.MediaStreams;
namespace FoxTube namespace FoxTube
{ {
public interface NavigationPage public delegate void Event();
public delegate void ObjectEventHandler(object sender = null, params object[] args);
public interface INavigationPage
{ {
object Parameter { get; set; } object Parameter { get; set; }
} }
public class HistoryItem
{
public string Id { get; set; }
public TimeSpan LeftOn { get; set; } = TimeSpan.FromSeconds(0);
}
public static class HistorySet
{
public static List<HistoryItem> Items { get; set; } = new List<HistoryItem>();
public static void Update(HistoryItem item)
{
if(Items.Exists(i => i.Id == item.Id))
Items.RemoveAll(i => i.Id == item.Id);
Items.Insert(0, item);
Save();
}
public static void Delete(HistoryItem item)
{
Items.Remove(item);
Save();
}
public static void Clear()
{
Items.Clear();
Save();
}
private static void Save()
{
try { ApplicationData.Current.RoamingSettings.Values[$"history-{SecretsVault.AccountId}"] = JsonConvert.SerializeObject(Items); }
catch { }
}
public static void Load()
{
if (ApplicationData.Current.RoamingSettings.Values[$"history-{SecretsVault.AccountId}"] != null)
Items = JsonConvert.DeserializeObject<List<HistoryItem>>(ApplicationData.Current.RoamingSettings.Values[$"history-{SecretsVault.AccountId}"] as string);
}
}
public static class Methods public static class Methods
{ {
private static ResourceLoader resources = ResourceLoader.GetForCurrentView("Methods"); private static readonly ResourceLoader resources = ResourceLoader.GetForCurrentView("Methods");
public static CommentsPage CommentsPage { get; set; }
public static MainPage MainPage public static CommentsPage CommentsPage { get; set; }
{ public static MainPage MainPage => (Window.Current.Content as Frame).Content as MainPage;
get { return (Window.Current.Content as Frame).Content as MainPage; }
}
public static void CloseApp() public static void CloseApp()
{ {
@@ -87,20 +44,15 @@ namespace FoxTube
public static Uri ToUri(this string url) public static Uri ToUri(this string url)
{ {
if (string.IsNullOrWhiteSpace(url)) return string.IsNullOrWhiteSpace(url) ? null : new Uri(url);
return null;
else
return new Uri(url);
} }
public static string GuardFromNull(string str) public static string GuardFromNull(string str)
{ {
if (string.IsNullOrWhiteSpace(str)) return str ?? string.Empty;
return string.Empty;
else
return str;
} }
[Obsolete]
public static string GetChars(this string str, int count) public static string GetChars(this string str, int count)
{ {
try try
@@ -140,6 +92,7 @@ namespace FoxTube
return array.ToList().FindAll(match); return array.ToList().FindAll(match);
} }
[Obsolete]
public static string ReplaceInvalidChars(this string str, char newValue) public static string ReplaceInvalidChars(this string str, char newValue)
{ {
foreach (char i in Path.GetInvalidFileNameChars()) foreach (char i in Path.GetInvalidFileNameChars())
@@ -147,6 +100,7 @@ namespace FoxTube
return str; return str;
} }
[Obsolete]
public static string Last(this string[] arr) public static string Last(this string[] arr)
{ {
return arr[arr.Length - 1]; return arr[arr.Length - 1];
@@ -161,13 +115,18 @@ namespace FoxTube
catch (FormatException) catch (FormatException)
{ {
TimeSpan time = XmlConvert.ToTimeSpan("PT" + str.Split('T')[1]); TimeSpan time = XmlConvert.ToTimeSpan("PT" + str.Split('T')[1]);
TimeSpan date = TimeSpan.FromDays(int.Parse(str.Split('W')[0].Replace("P", "")) * 7); TimeSpan date = TimeSpan.FromDays(int.Parse(str.Split('W')[0].Remove('P')) * 7);
date.Add(time); date.Add(time);
return date; return date;
} }
catch catch (Exception e)
{ {
Analytics.TrackEvent("Failed to parse duration", new Dictionary<string, string>
{
{ "Exception", e.GetType().ToString() },
{ "Message", e.Message }
});
return TimeSpan.FromMilliseconds(0); return TimeSpan.FromMilliseconds(0);
} }
} }
@@ -204,7 +163,7 @@ namespace FoxTube
return Math.Round(span.TotalDays / 365) + " " + resources.GetString("/Methods/years"); return Math.Round(span.TotalDays / 365) + " " + resources.GetString("/Methods/years");
} }
public static void FormatText(ref TextBlock block, string text) public static void FormatText(this TextBlock block, string text)
{ {
block.Inlines.Clear(); block.Inlines.Clear();
Regex filter = new Regex(@"\b((?:https?://|www\.)\S+)|(\S+@\S+)\b", RegexOptions.IgnoreCase); Regex filter = new Regex(@"\b((?:https?://|www\.)\S+)|(\S+@\S+)\b", RegexOptions.IgnoreCase);
@@ -268,10 +227,9 @@ namespace FoxTube
public async static void ProcessLink(string url) public async static void ProcessLink(string url)
{ {
string output;
string type; string type;
if (YoutubeClient.TryParseChannelId(url, out output)) if (YoutubeClient.TryParseChannelId(url, out string output))
{ {
type = "channel"; type = "channel";
goto LinkFound; goto LinkFound;
@@ -295,7 +253,7 @@ namespace FoxTube
await Launcher.LaunchUriAsync(new Uri(url)); await Launcher.LaunchUriAsync(new Uri(url));
return; return;
LinkFound: LinkFound:
switch (type) switch (type)
{ {
case "channel": case "channel":
@@ -313,32 +271,23 @@ namespace FoxTube
} }
} }
public static async void Share(DataRequestedEventArgs args, string thumbnail, string title, string url, string type) public static void Share(DataRequestedEventArgs args, string thumbnail, string title, string url, string type)
{ {
DataRequest request = args.Request; DataRequest request = args.Request;
request.Data.Properties.Title = title; request.Data.Properties.Title = title;
request.Data.Properties.Description = $"{resources.GetString("/Methods/sharing")} {type}"; request.Data.Properties.Description = $"{resources.GetString("/Methods/sharing")} {type}";
request.Data.SetText(title + "\n" + "#YouTube #FoxTube #SharedWithFoxTube"); request.Data.SetText(title + "\n" + "#YouTube #FoxTube #SharedWithFoxTube");
request.Data.SetWebLink(url.ToUri()); request.Data.SetWebLink(url.ToUri());
DataRequestDeferral deferral = request.GetDeferral(); request.Data.Properties.Thumbnail = RandomAccessStreamReference.CreateFromUri(thumbnail.ToUri());
try request.Data.SetBitmap(RandomAccessStreamReference.CreateFromUri(thumbnail.ToUri()));
{
StorageFile thumbnailFile = await StorageFile.CreateStreamedFileFromUriAsync("tempThumb.jpg", thumbnail.ToUri(), null);
request.Data.Properties.Thumbnail = RandomAccessStreamReference.CreateFromFile(thumbnailFile);
StorageFile imageFile = thumbnailFile;
request.Data.SetBitmap(RandomAccessStreamReference.CreateFromFile(imageFile));
}
finally
{
deferral.Complete();
}
} }
public static async Task<List<string>> GetHistory() public static async Task<List<string>> GetHistory()
{ {
SecretsVault.RefreshToken();
List<string> list = new List<string>(); List<string> list = new List<string>();
string output = await SecretsVault.HttpClient.GetStringAsync($"https://www.youtube.com/list_ajax?style=json&action_get_list=1&list=HL&hl={SettingsStorage.RelevanceLanguage}"); string output = await SecretsVault.HttpClient.GetStringAsync($"https://www.youtube.com/list_ajax?style=json&action_get_list=1&list=HL&hl={SettingsStorage.RelevanceLanguage}");
@@ -352,6 +301,7 @@ namespace FoxTube
public static async Task<List<string>> GetLater() public static async Task<List<string>> GetLater()
{ {
SecretsVault.RefreshToken();
List<string> list = new List<string>(); List<string> list = new List<string>();
string output = await SecretsVault.HttpClient.GetStringAsync($"https://www.youtube.com/list_ajax?style=json&action_get_list=1&list=WL&hl={SettingsStorage.RelevanceLanguage}"); string output = await SecretsVault.HttpClient.GetStringAsync($"https://www.youtube.com/list_ajax?style=json&action_get_list=1&list=WL&hl={SettingsStorage.RelevanceLanguage}");
-4
View File
@@ -4,10 +4,6 @@ using static Google.Apis.YouTube.v3.SearchResource.ListRequest;
namespace FoxTube namespace FoxTube
{ {
public delegate void Event();
public delegate void ObjectEventHandler(object sender = null, params object[] args);
public class SearchParameters public class SearchParameters
{ {
public class Filters public class Filters
+58 -52
View File
@@ -13,6 +13,7 @@ using System.Net.Http;
using Google.Apis.Oauth2.v2.Data; using Google.Apis.Oauth2.v2.Data;
using Google.Apis.Oauth2.v2; using Google.Apis.Oauth2.v2;
using static Google.Apis.Auth.OAuth2.UwpCodeReceiver; using static Google.Apis.Auth.OAuth2.UwpCodeReceiver;
using Microsoft.AppCenter.Analytics;
namespace FoxTube namespace FoxTube
{ {
@@ -24,7 +25,7 @@ namespace FoxTube
public static event ObjectEventHandler SubscriptionsChanged; public static event ObjectEventHandler SubscriptionsChanged;
public static event ObjectEventHandler Purchased; //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 //Properties
private static ClientSecrets Secrets => new ClientSecrets() private static ClientSecrets Secrets => new ClientSecrets()
{ {
ClientId = "349735264870-2ekqlm0a4mkg3mmrfcv90s3qp3o15dq0.apps.googleusercontent.com", ClientId = "349735264870-2ekqlm0a4mkg3mmrfcv90s3qp3o15dq0.apps.googleusercontent.com",
@@ -41,15 +42,16 @@ namespace FoxTube
ApplicationName = "FoxTube" ApplicationName = "FoxTube"
}; };
public static YouTubeService Service => IsAuthorized ? new YouTubeService(Initializer) : NoAuthService; public static YouTubeService Service => IsAuthorized ? new YouTubeService(Initializer) : NoAuthService;
public static HttpClient HttpClient { get; } = new HttpClient(); public static HttpClient HttpClient { get; } = new HttpClient();
private static bool TestAds => true; //Change this bool private static bool TestAds => true; //TODO: Change this bool
public static string AppId => TestAds ? "d25517cb-12d4-4699-8bdc-52040c712cab" : "9ncqqxjtdlfh"; public static string AppId => TestAds ? "d25517cb-12d4-4699-8bdc-52040c712cab" : "9ncqqxjtdlfh";
public static string AdUnitId => TestAds ? "test" : "1100044398"; public static string AdUnitId => TestAds ? "test" : "1100044398";
public static bool AdsDisabled { get; private set; } = true; public static bool AdsDisabled { get; private set; } = true;
//User info //User info
public static bool IsAuthorized => Credential != null; public static bool IsAuthorized => Credential != null;
private static UserCredential Credential { get; set; } private static UserCredential Credential { get; set; } = null;
public static string AccountId => UserChannel?.Id; public static string AccountId => UserChannel?.Id;
public static Channel UserChannel { get; private set; } public static Channel UserChannel { get; private set; }
@@ -61,6 +63,11 @@ namespace FoxTube
#endregion #endregion
#region Methods #region Methods
public static void RefreshToken()
{
Credential?.RefreshTokenAsync(CancellationToken.None);
}
/// <summary> /// <summary>
/// Subscribes or unsibscribes authorized user from the channel /// Subscribes or unsibscribes authorized user from the channel
/// </summary> /// </summary>
@@ -68,9 +75,6 @@ namespace FoxTube
/// <returns>Returns 'true' if channel is in subscriptions now; 'false' if it's not</returns> /// <returns>Returns 'true' if channel is in subscriptions now; 'false' if it's not</returns>
public static async Task<bool> ChangeSubscriptionState(string id) public static async Task<bool> ChangeSubscriptionState(string id)
{ {
if (!IsAuthorized)
return false;
if(Subscriptions.Exists(x => x.Snippet.ResourceId.ChannelId == id)) if(Subscriptions.Exists(x => x.Snippet.ResourceId.ChannelId == id))
{ {
Subscription s = Subscriptions.Find(x => x.Snippet.ResourceId.ChannelId == id); Subscription s = Subscriptions.Find(x => x.Snippet.ResourceId.ChannelId == id);
@@ -78,7 +82,7 @@ namespace FoxTube
try { await Service.Subscriptions.Delete(s.Id).ExecuteAsync(); } try { await Service.Subscriptions.Delete(s.Id).ExecuteAsync(); }
catch { return true; } catch { return true; }
SubscriptionsChanged?.Invoke(null, "remove", s); SubscriptionsChanged?.Invoke(null, "remove", s.Snippet.ResourceId.ChannelId);
Subscriptions.Remove(s); Subscriptions.Remove(s);
return false; return false;
} }
@@ -124,19 +128,19 @@ namespace FoxTube
try try
{ {
Credential = await GoogleWebAuthorizationBroker.AuthorizeAsync( Credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
Secrets, Secrets,
new[] new[]
{ {
Oauth2Service.Scope.UserinfoProfile, Oauth2Service.Scope.UserinfoProfile,
Oauth2Service.Scope.UserinfoEmail, Oauth2Service.Scope.UserinfoEmail,
YouTubeService.Scope.YoutubeForceSsl, YouTubeService.Scope.YoutubeForceSsl,
YouTubeService.Scope.Youtube, YouTubeService.Scope.Youtube,
YouTubeService.Scope.YoutubeUpload, YouTubeService.Scope.YoutubeUpload,
YouTubeService.Scope.YoutubeReadonly, YouTubeService.Scope.YoutubeReadonly,
YouTubeService.Scope.Youtubepartner YouTubeService.Scope.Youtubepartner
}, },
"user", "user",
CancellationToken.None); CancellationToken.None);
await Credential.RefreshTokenAsync(CancellationToken.None); await Credential.RefreshTokenAsync(CancellationToken.None);
} }
@@ -145,15 +149,19 @@ namespace FoxTube
if (e.Message.Contains("UserCancel")) if (e.Message.Contains("UserCancel"))
return; return;
else else
throw e; Analytics.TrackEvent("Failed to authorize", new Dictionary<string, string>
{
{ "Exception", e.GetType().ToString() },
{ "Message", e.Message }
});
} }
if (Credential == null || !retrieveSubs) if (Credential == null || !retrieveSubs)
return; return;
SettingsStorage.HasAccount = true;
HttpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", Credential.Token.AccessToken); HttpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", Credential.Token.AccessToken);
SettingsStorage.HasAccount = true;
#endregion #endregion
try try
@@ -161,12 +169,8 @@ namespace FoxTube
#region Retrieving user's data #region Retrieving user's data
UserInfo = await new Oauth2Service(Initializer).Userinfo.Get().ExecuteAsync(); UserInfo = await new Oauth2Service(Initializer).Userinfo.Get().ExecuteAsync();
try WatchLater = await Methods.GetLater();
{ History = await Methods.GetHistory();
WatchLater = await Methods.GetLater();
History = await Methods.GetHistory();
}
catch { }
SubscriptionsResource.ListRequest subRequest = Service.Subscriptions.List("snippet"); SubscriptionsResource.ListRequest subRequest = Service.Subscriptions.List("snippet");
subRequest.Mine = true; subRequest.Mine = true;
@@ -196,9 +200,14 @@ namespace FoxTube
AuthorizationStateChanged?.Invoke(args: true); AuthorizationStateChanged?.Invoke(args: true);
} }
catch catch (Exception e)
{ {
AuthorizationStateChanged?.Invoke(args: new bool?[] { null }); AuthorizationStateChanged?.Invoke(args: new bool?[] { null });
Analytics.TrackEvent("Failed to retrieve user's info", new Dictionary<string, string>
{
{ "Exception", e.GetType().ToString() },
{ "Message", e.Message }
});
} }
} }
@@ -217,14 +226,19 @@ namespace FoxTube
/// </summary> /// </summary>
public static async void Deauthenticate() public static async void Deauthenticate()
{ {
if(await Credential.RevokeTokenAsync(CancellationToken.None)) if (!await Credential.RevokeTokenAsync(CancellationToken.None))
{ return;
Credential = null;
AuthorizationStateChanged?.Invoke(args: false); Credential = null;
SettingsStorage.HasAccount = false; UserChannel = null;
UserInfo = null;
History.Clear();
WatchLater.Clear();
Subscriptions.Clear();
ApplicationData.Current.RoamingSettings.Values["subscriptions"] = "";
ApplicationData.Current.RoamingSettings.Values["subscriptions"] = ""; AuthorizationStateChanged?.Invoke(args: false);
} SettingsStorage.HasAccount = false;
} }
/// <summary> /// <summary>
@@ -249,32 +263,24 @@ namespace FoxTube
{ {
try try
{ {
StoreContext store = StoreContext.GetDefault(); StoreProductQueryResult requset = await StoreContext.GetDefault().GetAssociatedStoreProductsAsync(new[] { "Durable" });
StoreProductQueryResult requset = await store.GetAssociatedStoreProductsAsync(new[] { "Durable" });
Dictionary<string, StoreProduct> l = new Dictionary<string, StoreProduct>();
requset.Products.ForEach(i => l.Add(i.Key, i.Value));
if (!requset.Products["9NP1QK556625"].IsInUserCollection) if (requset.Products["9NP1QK556625"].IsInUserCollection)
{ return;
AdsDisabled = false;
Purchased?.Invoke(null, false, requset.Products["9NP1QK556625"].Price.FormattedPrice); AdsDisabled = false;
} Purchased?.Invoke(null, false, requset.Products["9NP1QK556625"].Price.FormattedPrice);
} }
catch { } catch { }
} }
public static async void GetAdblock() public static async void GetAdblock()
{ {
StoreContext store = StoreContext.GetDefault(); StorePurchaseResult request = await StoreContext.GetDefault().RequestPurchaseAsync("9NP1QK556625");
StorePurchaseResult request = await store.RequestPurchaseAsync("9NP1QK556625");
switch (request.Status) switch (request.Status)
{ {
case StorePurchaseStatus.AlreadyPurchased: case StorePurchaseStatus.AlreadyPurchased:
Purchased?.Invoke(args: true);
AdsDisabled = true;
break;
case StorePurchaseStatus.Succeeded: case StorePurchaseStatus.Succeeded:
Purchased?.Invoke(args: true); Purchased?.Invoke(args: true);
AdsDisabled = true; AdsDisabled = true;
+11 -4
View File
@@ -1,5 +1,7 @@
using Newtonsoft.Json; using Microsoft.AppCenter.Analytics;
using Newtonsoft.Json;
using System; using System;
using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
using Windows.ApplicationModel; using Windows.ApplicationModel;
@@ -221,7 +223,7 @@ namespace FoxTube
//Settings storage //Settings storage
private static readonly ApplicationDataContainer storage = ApplicationData.Current.RoamingSettings; private static readonly ApplicationDataContainer storage = ApplicationData.Current.RoamingSettings;
private static SettingsContainer Container; private static SettingsContainer Container = new SettingsContainer();
public static void LoadData() public static void LoadData()
{ {
@@ -229,10 +231,15 @@ namespace FoxTube
{ {
Container = JsonConvert.DeserializeObject<SettingsContainer>(storage.Values["settings"] as string); Container = JsonConvert.DeserializeObject<SettingsContainer>(storage.Values["settings"] as string);
} }
catch catch (Exception e)
{ {
Container = new SettingsContainer();
SaveData(); SaveData();
if (storage.Values["settings"] != null)
Analytics.TrackEvent("Failed to retrieve settings", new Dictionary<string, string>
{
{ "Exception", e.GetType().ToString() },
{ "Message", e.Message }
});
} }
} }
+1 -8
View File
@@ -13,21 +13,14 @@ namespace FoxTube.Controls.Adverts
{ {
NativeAdsManagerV2 manager = new NativeAdsManagerV2(SecretsVault.AppId, SecretsVault.AdUnitId); NativeAdsManagerV2 manager = new NativeAdsManagerV2(SecretsVault.AppId, SecretsVault.AdUnitId);
public NativeAdV2 advert; public NativeAdV2 advert;
public CardAdvert(bool isOnVideoPage = false) public CardAdvert()
{ {
InitializeComponent(); InitializeComponent();
if(!isOnVideoPage)
MainPage.VideoPageSizeChanged += Methods_VideoPageSizeChanged;
manager.AdReady += AdReady; manager.AdReady += AdReady;
manager.ErrorOccurred += ErrorOccurred; manager.ErrorOccurred += ErrorOccurred;
manager.RequestAd(); manager.RequestAd();
} }
private void Methods_VideoPageSizeChanged(object sender = null, params object[] args)
{
Visibility = !(bool)args[0] && advert != null ? Visibility.Visible : Visibility.Collapsed;
}
private void ErrorOccurred(object sender, NativeAdErrorEventArgs e) private void ErrorOccurred(object sender, NativeAdErrorEventArgs e)
{ {
System.Diagnostics.Debug.WriteLine("Error has occured while loading ad"); System.Diagnostics.Debug.WriteLine("Error has occured while loading ad");
+6 -10
View File
@@ -9,22 +9,18 @@
VerticalAlignment="Top" VerticalAlignment="Top"
d:DesignHeight="290" d:DesignHeight="290"
d:DesignWidth="384" d:DesignWidth="384"
MaxWidth="700"
Opacity="0" Opacity="0"
Name="card"> Name="card"
SizeChanged="Card_SizeChanged">
<UserControl.Resources> <UserControl.Resources>
<Storyboard x:Name="show"> <Storyboard x:Name="show">
<DoubleAnimation Storyboard.TargetName="card" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="{StaticResource CardOpacityDuration}"/> <DoubleAnimation Storyboard.TargetName="card" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="{StaticResource CardOpacityDuration}"/>
</Storyboard> </Storyboard>
<Storyboard x:Name="hide">
<DoubleAnimation Storyboard.TargetName="card" Storyboard.TargetProperty="Opacity" From="1" To="0" Duration="{StaticResource CardOpacityDuration}"/>
</Storyboard>
<Storyboard x:Name="showThumb"> <Storyboard x:Name="showThumb">
<DoubleAnimation Storyboard.TargetName="cover" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="{StaticResource CardOpacityDuration}"/> <DoubleAnimation Storyboard.TargetName="cover" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="{StaticResource CardOpacityDuration}"/>
</Storyboard> </Storyboard>
<Storyboard x:Name="hideThumb">
<DoubleAnimation Storyboard.TargetName="cover" Storyboard.TargetProperty="Opacity" From="1" To="0" Duration="{StaticResource CardOpacityDuration}"/>
</Storyboard>
</UserControl.Resources> </UserControl.Resources>
<Button Padding="0" Margin="1" Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}" Click="Button_Click"> <Button Padding="0" Margin="1" Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}" Click="Button_Click">
@@ -61,13 +57,13 @@
</StackPanel> </StackPanel>
</Grid> </Grid>
<TextBlock Height="75" Name="description" Grid.Row="2" Margin="10" Text="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin molestie vulputate leo, sed faucibus ex rutrum nec. Donec quis diam nisi. Suspendisse sollicitudin sapien quis eros vulputate, sed scelerisque enim ullamcorper. Donec vulputate commodo mi, vel vestibulum quam posuere ac. Curabitur ac nunc augue. Phasellus aliquam neque ac condimentum bibendum." TextWrapping="WrapWholeWords" TextTrimming="CharacterEllipsis"/> <TextBlock Height="75" Name="description" Grid.Row="2" MaxLines="3" Margin="10,0" Text="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin molestie vulputate leo, sed faucibus ex rutrum nec. Donec quis diam nisi. Suspendisse sollicitudin sapien quis eros vulputate, sed scelerisque enim ullamcorper. Donec vulputate commodo mi, vel vestibulum quam posuere ac. Curabitur ac nunc augue. Phasellus aliquam neque ac condimentum bibendum." TextWrapping="WrapWholeWords" TextTrimming="CharacterEllipsis"/>
<TextBlock Grid.Row="3" VerticalAlignment="Bottom" HorizontalAlignment="Stretch" Height="50" Margin="10" TextAlignment="Center" Padding="0,16,0,0" Foreground="Gray"> <TextBlock Grid.Row="3" VerticalAlignment="Bottom" HorizontalAlignment="Stretch" Height="50" Margin="5" TextAlignment="Center" Padding="0,16,0,0" Foreground="Gray">
<Hyperlink Click="Hyperlink_Click"><Run x:Uid="/Cards/login">Log in</Run></Hyperlink> <Run x:Uid="/Cards/tomanage">to manage your subscriptions</Run> <Hyperlink Click="Hyperlink_Click"><Run x:Uid="/Cards/login">Log in</Run></Hyperlink> <Run x:Uid="/Cards/tomanage">to manage your subscriptions</Run>
</TextBlock> </TextBlock>
<Grid Visibility="Collapsed" Grid.Row="3" VerticalAlignment="Stretch" Margin="10" Name="subscriptionPane" Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}"> <Grid Visibility="Collapsed" Grid.Row="3" VerticalAlignment="Stretch" Margin="5" Name="subscriptionPane" Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}">
<Button x:Uid="/Cards/subscribe" VerticalAlignment="Stretch" 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" VerticalAlignment="Stretch" Click="subscribe_Click" Name="subscribe" HorizontalAlignment="Stretch" Height="50" Background="Red" Foreground="White" FontSize="18" FontWeight="SemiBold" Content="Subscirbe" Margin="0,0,0,0"/>
<ToggleButton Name="notify" Height="50" Width="50" Visibility="Collapsed" FontFamily="Segoe MDL2 Assets" FontSize="18" FontWeight="SemiBold" Content="&#xE7ED;" Foreground="White" Background="Red" HorizontalAlignment="Right"/> <ToggleButton Name="notify" Height="50" Width="50" Visibility="Collapsed" FontFamily="Segoe MDL2 Assets" FontSize="18" FontWeight="SemiBold" Content="&#xE7ED;" Foreground="White" Background="Red" HorizontalAlignment="Right"/>
</Grid> </Grid>
+5
View File
@@ -127,5 +127,10 @@ namespace FoxTube.Controls
{ {
showThumb.Begin(); showThumb.Begin();
} }
private void Card_SizeChanged(object sender, SizeChangedEventArgs e)
{
Height = e.NewSize.Width * 0.75;
}
} }
} }
+1 -1
View File
@@ -28,7 +28,7 @@ namespace FoxTube.Controls
VerticalAlignment = VerticalAlignment.Top, VerticalAlignment = VerticalAlignment.Top,
TextWrapping = TextWrapping.WrapWholeWords TextWrapping = TextWrapping.WrapWholeWords
}; };
Methods.FormatText(ref block, message.Snippet.DisplayMessage); block.FormatText(message.Snippet.DisplayMessage);
return block; return block;
} }
} }
+2 -2
View File
@@ -71,7 +71,7 @@ namespace FoxTube.Controls
author.Text = comment.Snippet.TopLevelComment.Snippet.AuthorDisplayName; author.Text = comment.Snippet.TopLevelComment.Snippet.AuthorDisplayName;
meta.Text = string.Format("{0} {1}", Methods.GetAgo(comment.Snippet.TopLevelComment.Snippet.PublishedAt.Value), comment.Snippet.TopLevelComment.Snippet.UpdatedAt != comment.Snippet.TopLevelComment.Snippet.PublishedAt ? resources.GetString("/CommentsPage/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); text.FormatText(comment.Snippet.TopLevelComment.Snippet.TextDisplay);
try { avatar.ProfilePicture = new BitmapImage(new Uri(comment.Snippet.TopLevelComment.Snippet.AuthorProfileImageUrl)) { DecodePixelWidth = 50, DecodePixelHeight = 50 }; } try { avatar.ProfilePicture = new BitmapImage(new Uri(comment.Snippet.TopLevelComment.Snippet.AuthorProfileImageUrl)) { DecodePixelWidth = 50, DecodePixelHeight = 50 }; }
catch { } catch { }
@@ -127,7 +127,7 @@ namespace FoxTube.Controls
author.Text = comment.Snippet.AuthorDisplayName; author.Text = comment.Snippet.AuthorDisplayName;
meta.Text = string.Format("{0} {1}", Methods.GetAgo(comment.Snippet.PublishedAt.Value), comment.Snippet.UpdatedAt != comment.Snippet.PublishedAt ? resources.GetString("/CommentsPage/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); text.FormatText(comment.Snippet.TextDisplay);
try { avatar.ProfilePicture = new BitmapImage(new Uri(comment.Snippet.AuthorProfileImageUrl)) { DecodePixelWidth = 50, DecodePixelHeight = 50 }; } try { avatar.ProfilePicture = new BitmapImage(new Uri(comment.Snippet.AuthorProfileImageUrl)) { DecodePixelWidth = 50, DecodePixelHeight = 50 }; }
catch { } catch { }
+14
View File
@@ -0,0 +1,14 @@
<UserControl
x:Class="FoxTube.Controls.ContentFrame"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:foxtube="using:FoxTube"
mc:Ignorable="d">
<Grid>
<Frame x:Name="content" Navigating="Content_Navigating"/>
<foxtube:LoadingPage x:Name="loading" RefreshPage="Loading_RefreshPage" Visibility="Collapsed"/>
</Grid>
</UserControl>
+35
View File
@@ -0,0 +1,35 @@
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
namespace FoxTube.Controls
{
public sealed partial class ContentFrame : UserControl
{
public Frame Frame => content;
public LoadingPage LoadingPage => loading;
public event NavigatedEventHandler Navigated;
public ContentFrame()
{
InitializeComponent();
content.Navigated += (s, e) => Navigated?.Invoke(s, e);
}
private void Content_Navigating(object sender, NavigatingCancelEventArgs e)
{
loading.Refresh();
}
private void Loading_RefreshPage(object sender, RoutedEventArgs e)
{
content.Navigate(content.CurrentSourcePageType, (content.Content as INavigationPage).Parameter);
content.BackStack.RemoveAt(content.BackStack.Count - 1);
}
public void Refresh()
{
Loading_RefreshPage(this, null);
}
}
}
-1
View File
@@ -9,7 +9,6 @@ using YoutubeExplode;
using Windows.Storage; using Windows.Storage;
using Google.Apis.YouTube.v3.Data; using Google.Apis.YouTube.v3.Data;
using System.Threading; using System.Threading;
using System.Xml;
using Windows.UI.Popups; using Windows.UI.Popups;
using Windows.UI.Notifications; using Windows.UI.Notifications;
using Microsoft.Toolkit.Uwp.Notifications; using Microsoft.Toolkit.Uwp.Notifications;
+8 -21
View File
@@ -412,25 +412,6 @@ namespace FoxTube
{ {
ClosedCaptions = await new YoutubeClient().GetVideoClosedCaptionTrackInfosAsync(meta.Id); ClosedCaptions = await new YoutubeClient().GetVideoClosedCaptionTrackInfosAsync(meta.Id);
/*foreach (MuxedStreamInfo i in MediaStreams.Muxed)
quality.Items.Add(new ComboBoxItem
{
Content = $"{i.VideoQualityLabel} (muxed)",
Tag = i
});
foreach (VideoStreamInfo i in MediaStreams.Video)
quality.Items.Add(new ComboBoxItem
{
Content = $"{i.VideoQualityLabel} (video-only)",
Tag = i
});
foreach (AudioStreamInfo i in MediaStreams.Audio)
quality.Items.Add(new ComboBoxItem
{
Content = $"{i.Bitrate} (audio-only)",
Tag = i
});*/
uint screenHeight = DisplayInformation.GetForCurrentView().ScreenHeightInRawPixels; uint screenHeight = DisplayInformation.GetForCurrentView().ScreenHeightInRawPixels;
List<string> qualityList = MediaStreams.GetAllVideoQualityLabels().ToList(); List<string> qualityList = MediaStreams.GetAllVideoQualityLabels().ToList();
@@ -461,8 +442,8 @@ namespace FoxTube
string s = SettingsStorage.VideoQuality == "remember" ? SettingsStorage.RememberedQuality : SettingsStorage.VideoQuality; string s = SettingsStorage.VideoQuality == "remember" ? SettingsStorage.RememberedQuality : SettingsStorage.VideoQuality;
if (quality.Items.Any(i => (i as ComboBoxItem).Content as string == s)) if (quality.Items.Any(i => ((i as ComboBoxItem).Content as string).Contains(s)))
quality.SelectedItem = quality.Items.Find(i => (i as ComboBoxItem).Content as string == s); quality.SelectedItem = quality.Items.Find(i => ((i as ComboBoxItem).Content as string).Contains(s));
else else
quality.SelectedIndex = 0; quality.SelectedIndex = 0;
@@ -518,5 +499,11 @@ namespace FoxTube
quality.SelectedIndex = 0; quality.SelectedIndex = 0;
} }
} }
public void PushAdvert()
{
if(State == PlayerDisplayState.Normal)
Advert.PushAdvert();
}
} }
} }
+1 -15
View File
@@ -6,20 +6,6 @@ using Google.Apis.YouTube.v3.Data;
using Windows.UI.Xaml.Media.Imaging; using Windows.UI.Xaml.Media.Imaging;
using Windows.Media; using Windows.Media;
using Windows.Storage.Streams; using Windows.Storage.Streams;
using YoutubeExplode.Models.MediaStreams;
using YoutubeExplode;
using System.IO;
using FoxTube.Classes;
using Windows.Media.Core;
using System.Linq;
using Windows.Media.Playback;
using System.Threading.Tasks;
using Windows.Media.Editing;
using Windows.Storage.Pickers;
using Windows.Storage;
using Windows.Media.MediaProperties;
using FoxTube.Controls.Player;
using System.Diagnostics;
using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Media;
namespace FoxTube namespace FoxTube
@@ -180,7 +166,7 @@ namespace FoxTube
private void VideoSource_MarkerReached(object sender, TimelineMarkerRoutedEventArgs e) private void VideoSource_MarkerReached(object sender, TimelineMarkerRoutedEventArgs e)
{ {
Controls.Advert.PushAdvert(); Controls.PushAdvert();
} }
} }
} }
+3 -8
View File
@@ -4,28 +4,23 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:Windows10version1809="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractPresent(Windows.Foundation.UniversalApiContract, 7)"
mc:Ignorable="d" mc:Ignorable="d"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
VerticalAlignment="Top" VerticalAlignment="Top"
d:DesignHeight="290" d:DesignHeight="290"
d:DesignWidth="384" d:DesignWidth="384"
MaxWidth="700"
Opacity="0" Opacity="0"
Name="card"> Name="card"
SizeChanged="Card_SizeChanged">
<UserControl.Resources> <UserControl.Resources>
<Storyboard x:Name="show"> <Storyboard x:Name="show">
<DoubleAnimation Storyboard.TargetName="card" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="{StaticResource CardOpacityDuration}"/> <DoubleAnimation Storyboard.TargetName="card" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="{StaticResource CardOpacityDuration}"/>
</Storyboard> </Storyboard>
<Storyboard x:Name="hide">
<DoubleAnimation Storyboard.TargetName="card" Storyboard.TargetProperty="Opacity" From="1" To="0" Duration="{StaticResource CardOpacityDuration}"/>
</Storyboard>
<Storyboard x:Name="showThumb"> <Storyboard x:Name="showThumb">
<DoubleAnimation Storyboard.TargetName="thumbnail" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="{StaticResource CardOpacityDuration}"/> <DoubleAnimation Storyboard.TargetName="thumbnail" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="{StaticResource CardOpacityDuration}"/>
</Storyboard> </Storyboard>
<Storyboard x:Name="hideThumb">
<DoubleAnimation Storyboard.TargetName="thumbnail" Storyboard.TargetProperty="Opacity" From="1" To="0" Duration="{StaticResource CardOpacityDuration}"/>
</Storyboard>
</UserControl.Resources> </UserControl.Resources>
<Button Padding="0" Margin="1" Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}" Click="Button_Click"> <Button Padding="0" Margin="1" Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}" Click="Button_Click">
+7 -4
View File
@@ -45,10 +45,8 @@ namespace FoxTube.Controls
ChannelsResource.ListRequest r = SecretsVault.Service.Channels.List("snippet"); ChannelsResource.ListRequest r = SecretsVault.Service.Channels.List("snippet");
r.Id = item.Snippet.ChannelId; r.Id = item.Snippet.ChannelId;
try { thumbnail.Source = new BitmapImage(item.Snippet.Thumbnails.Medium.Url.ToUri()); } thumbnail.Source = new BitmapImage(item.Snippet.Thumbnails.Medium.Url.ToUri());
catch { } avatar.ProfilePicture = new BitmapImage(new Uri((await r.ExecuteAsync()).Items[0].Snippet.Thumbnails.Medium.Url)) { DecodePixelWidth = 46, DecodePixelHeight = 46 };
try { avatar.ProfilePicture = new BitmapImage(new Uri((await r.ExecuteAsync()).Items[0].Snippet.Thumbnails.Medium.Url)) { DecodePixelWidth = 46, DecodePixelHeight = 46 }; }
catch { }
show.Begin(); show.Begin();
} }
@@ -90,5 +88,10 @@ namespace FoxTube.Controls
{ {
showThumb.Begin(); showThumb.Begin();
} }
private void Card_SizeChanged(object sender, SizeChangedEventArgs e)
{
Height = e.NewSize.Width * 0.75;
}
} }
} }
+3 -7
View File
@@ -9,22 +9,18 @@
VerticalAlignment="Top" VerticalAlignment="Top"
d:DesignHeight="290" d:DesignHeight="290"
d:DesignWidth="384" d:DesignWidth="384"
MaxWidth="700"
Opacity="0" Opacity="0"
Name="card"> Name="card"
SizeChanged="Card_SizeChanged">
<UserControl.Resources> <UserControl.Resources>
<Storyboard x:Name="show"> <Storyboard x:Name="show">
<DoubleAnimation Storyboard.TargetName="card" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="{StaticResource CardOpacityDuration}"/> <DoubleAnimation Storyboard.TargetName="card" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="{StaticResource CardOpacityDuration}"/>
</Storyboard> </Storyboard>
<Storyboard x:Name="hide">
<DoubleAnimation Storyboard.TargetName="card" Storyboard.TargetProperty="Opacity" From="1" To="0" Duration="{StaticResource CardOpacityDuration}"/>
</Storyboard>
<Storyboard x:Name="showThumb"> <Storyboard x:Name="showThumb">
<DoubleAnimation Storyboard.TargetName="thumbnail" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="{StaticResource CardOpacityDuration}"/> <DoubleAnimation Storyboard.TargetName="thumbnail" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="{StaticResource CardOpacityDuration}"/>
</Storyboard> </Storyboard>
<Storyboard x:Name="hideThumb">
<DoubleAnimation Storyboard.TargetName="thumbnail" Storyboard.TargetProperty="Opacity" From="1" To="0" Duration="{StaticResource CardOpacityDuration}"/>
</Storyboard>
</UserControl.Resources> </UserControl.Resources>
<Button Padding="0" Margin="1" Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}" Click="Button_Click"> <Button Padding="0" Margin="1" Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}" Click="Button_Click">
+102 -53
View File
@@ -14,6 +14,7 @@ using Windows.UI.Popups;
using YoutubeExplode.Models.MediaStreams; using YoutubeExplode.Models.MediaStreams;
using Windows.Foundation; using Windows.Foundation;
using FoxTube.Pages; using FoxTube.Pages;
using Windows.Networking.Connectivity;
namespace FoxTube.Controls namespace FoxTube.Controls
{ {
@@ -25,7 +26,6 @@ namespace FoxTube.Controls
ResourceLoader resources = ResourceLoader.GetForCurrentView("Cards"); ResourceLoader resources = ResourceLoader.GetForCurrentView("Cards");
public string playlistId; public string playlistId;
public string videoId;
Video item; Video item;
HistoryItem history; HistoryItem history;
@@ -48,9 +48,7 @@ namespace FoxTube.Controls
{ {
try try
{ {
videoId = id;
playlistId = playlist; playlistId = playlist;
delete.Visibility = string.IsNullOrWhiteSpace(playlistId) ? Visibility.Collapsed : Visibility.Visible; delete.Visibility = string.IsNullOrWhiteSpace(playlistId) ? Visibility.Collapsed : Visibility.Visible;
VideosResource.ListRequest request = SecretsVault.Service.Videos.List("snippet,contentDetails,statistics,liveStreamingDetails"); VideosResource.ListRequest request = SecretsVault.Service.Videos.List("snippet,contentDetails,statistics,liveStreamingDetails");
@@ -100,12 +98,10 @@ namespace FoxTube.Controls
} }
LoadAddTo(); LoadAddTo();
try { thumbnail.Source = new BitmapImage(item.Snippet.Thumbnails.Medium.Url.ToUri()); } thumbnail.Source = new BitmapImage(item.Snippet.Thumbnails.Medium.Url.ToUri());
catch { } avatar.ProfilePicture = new BitmapImage((await new YoutubeClient().GetChannelAsync(item.Snippet.ChannelId)).LogoUrl.ToUri()) { DecodePixelWidth = 46, DecodePixelHeight = 46 };
try { avatar.ProfilePicture = new BitmapImage((await new YoutubeClient().GetChannelAsync(item.Snippet.ChannelId)).LogoUrl.ToUri()) { DecodePixelWidth = 46, DecodePixelHeight = 46 }; }
catch { }
if (SecretsVault.History.Contains(videoId)) if (SecretsVault.History.Contains(item.Id))
watched.Visibility = Visibility.Visible; watched.Visibility = Visibility.Visible;
if (HistorySet.Items.Exists(i => i.Id == item.Id)) if (HistorySet.Items.Exists(i => i.Id == item.Id))
{ {
@@ -123,7 +119,7 @@ namespace FoxTube.Controls
{ {
{ "Exception", e.GetType().ToString() }, { "Exception", e.GetType().ToString() },
{ "Message", e.Message }, { "Message", e.Message },
{ "Video ID", videoId } { "Video ID", item.Id }
}); });
} }
} }
@@ -132,7 +128,7 @@ namespace FoxTube.Controls
{ {
try try
{ {
MediaStreamInfoSet infoSet = await new YoutubeClient().GetVideoMediaStreamInfosAsync(videoId); MediaStreamInfoSet infoSet = await new YoutubeClient().GetVideoMediaStreamInfosAsync(item.Id);
foreach (MuxedStreamInfo i in infoSet.Muxed) foreach (MuxedStreamInfo i in infoSet.Muxed)
{ {
MenuFlyoutItem menuItem = new MenuFlyoutItem() MenuFlyoutItem menuItem = new MenuFlyoutItem()
@@ -165,10 +161,16 @@ namespace FoxTube.Controls
public async void LoadMeta() public async void LoadMeta()
{ {
videoId = item.Id;
title.Text = item.Snippet.Title; title.Text = item.Snippet.Title;
channelName.Text = item.Snippet.ChannelTitle; channelName.Text = item.Snippet.ChannelTitle;
if (item.Snippet.Title == "Deleted video")
{
ContextFlyout = null;
show.Begin();
return;
}
if (item.Snippet.LiveBroadcastContent == "live") if (item.Snippet.LiveBroadcastContent == "live")
{ {
views.Text = $"{item.LiveStreamingDetails.ConcurrentViewers:0,0} {resources.GetString("/Cards/viewers")}"; views.Text = $"{item.LiveStreamingDetails.ConcurrentViewers:0,0} {resources.GetString("/Cards/viewers")}";
@@ -197,12 +199,10 @@ namespace FoxTube.Controls
info.Text = $"{item.ContentDetails.Duration.GetDuration()} | {Methods.GetAgo(item.Snippet.PublishedAt.Value)}"; info.Text = $"{item.ContentDetails.Duration.GetDuration()} | {Methods.GetAgo(item.Snippet.PublishedAt.Value)}";
} }
try { thumbnail.Source = new BitmapImage(item.Snippet.Thumbnails.Medium.Url.ToUri()); } thumbnail.Source = new BitmapImage(item.Snippet.Thumbnails.Medium.Url.ToUri());
catch { } avatar.ProfilePicture = new BitmapImage((await new YoutubeClient().GetChannelAsync(item.Snippet.ChannelId)).LogoUrl.ToUri()) { DecodePixelHeight = 50, DecodePixelWidth = 50 };
try { avatar.ProfilePicture = new BitmapImage((await new YoutubeClient().GetChannelAsync(item.Snippet.ChannelId)).LogoUrl.ToUri()) { DecodePixelHeight = 50, DecodePixelWidth = 50 }; }
catch { }
if (SecretsVault.History.Contains(videoId)) if (SecretsVault.History.Contains(item.Id))
watched.Visibility = Visibility.Visible; watched.Visibility = Visibility.Visible;
if (HistorySet.Items.Exists(i => i.Id == item.Id)) if (HistorySet.Items.Exists(i => i.Id == item.Id))
leftOn.Value = 100 * HistorySet.Items.Find(i => i.Id == item.Id).LeftOn.TotalSeconds / Methods.GetDuration(item.ContentDetails.Duration).TotalSeconds; leftOn.Value = 100 * HistorySet.Items.Find(i => i.Id == item.Id).LeftOn.TotalSeconds / Methods.GetDuration(item.ContentDetails.Duration).TotalSeconds;
@@ -244,7 +244,44 @@ namespace FoxTube.Controls
} }
} }
Methods.MainPage.GoToVideo(videoId, playlistId == "HL" ? null : playlistId, ((FrameworkElement)sender).Name == "incognito" ? true : false); ConnectionCost connection = NetworkInformation.GetInternetConnectionProfile().GetConnectionCost();
if (SettingsStorage.CheckConnection && (connection.NetworkCostType == NetworkCostType.Fixed || connection.NetworkCostType == NetworkCostType.Variable))
{
MessageDialog dialog = new MessageDialog(resources.GetString("/Main/metered"))
{
DefaultCommandIndex = 2,
CancelCommandIndex = 1
};
dialog.Commands.Add(new UICommand(resources.GetString("/Main/yes"), null, false));
dialog.Commands.Add(new UICommand(resources.GetString("/Main/no"), null, true));
if(SecretsVault.IsAuthorized)
dialog.Commands.Add(new UICommand(resources.GetString("/Main/metered"), async (command) =>
{
try
{
PlaylistItem playlistItem = new PlaylistItem()
{
Snippet = new PlaylistItemSnippet()
{
ResourceId = new ResourceId()
{
Kind = "youtube#video",
VideoId = item.Id
},
PlaylistId = "WL"
}
};
await SecretsVault.Service.PlaylistItems.Insert(playlistItem, "snippet").ExecuteAsync();
}
catch { }
}, true));
if ((bool)(await dialog.ShowAsync()).Id)
return;
}
Methods.MainPage.GoToVideo(item.Id, playlistId == "HL" ? null : playlistId, ((FrameworkElement)sender).Name == "incognito" ? true : false);
} }
private void Share(DataTransferManager sender, DataRequestedEventArgs args) private void Share(DataTransferManager sender, DataRequestedEventArgs args)
@@ -252,7 +289,7 @@ namespace FoxTube.Controls
Methods.Share(args, Methods.Share(args,
item.Snippet.Thumbnails.Medium.Url, item.Snippet.Thumbnails.Medium.Url,
item.Snippet.Title, item.Snippet.Title,
$"https://www.youtube.com/watch?v={videoId}", $"https://www.youtube.com/watch?v={item.Id}",
resources.GetString("/Cards/videoShare")); resources.GetString("/Cards/videoShare"));
} }
@@ -270,13 +307,13 @@ namespace FoxTube.Controls
private void GetLink_Click(object sender, RoutedEventArgs e) private void GetLink_Click(object sender, RoutedEventArgs e)
{ {
DataPackage data = new DataPackage(); DataPackage data = new DataPackage();
data.SetText($"https://www.youtube.com/watch?v={videoId}"); data.SetText($"https://www.youtube.com/watch?v={item.Id}");
Clipboard.SetContent(data); Clipboard.SetContent(data);
} }
private async void InBrowser_Click(object sender, RoutedEventArgs e) private async void InBrowser_Click(object sender, RoutedEventArgs e)
{ {
await Launcher.LaunchUriAsync($"https://www.youtube.com/watch?v={videoId}".ToUri()); await Launcher.LaunchUriAsync($"https://www.youtube.com/watch?v={item.Id}".ToUri());
} }
private void Thumbnail_ImageOpened(object sender, RoutedEventArgs e) private void Thumbnail_ImageOpened(object sender, RoutedEventArgs e)
@@ -401,39 +438,46 @@ namespace FoxTube.Controls
async void LoadAddTo() async void LoadAddTo()
{ {
if (SecretsVault.UserChannel == null) try
{
if (SecretsVault.UserChannel == null)
{
addTo.Visibility = Visibility.Collapsed;
return;
}
if (SecretsVault.WatchLater.Contains(item.Id))
(addTo.Items[1] as ToggleMenuFlyoutItem).IsChecked = true;
PlaylistsResource.ListRequest request = SecretsVault.Service.Playlists.List("snippet");
request.Mine = true;
request.MaxResults = 50;
PlaylistListResponse response = await request.ExecuteAsync();
PlaylistItemsResource.ListRequest itemRequest = SecretsVault.Service.PlaylistItems.List("snippet");
itemRequest.VideoId = item.Id;
foreach (Playlist i in response.Items)
{
itemRequest.PlaylistId = i.Id;
ToggleMenuFlyoutItem menuItem = new ToggleMenuFlyoutItem
{
Text = i.Snippet.Title,
IsChecked = (await itemRequest.ExecuteAsync()).Items.Count > 0,
Tag = i,
Icon = new FontIcon
{
Glyph = "\xE728"
}
};
menuItem.Click += Item_Click;
addTo.Items.Add(menuItem);
}
}
catch
{ {
addTo.Visibility = Visibility.Collapsed; addTo.Visibility = Visibility.Collapsed;
return;
}
if (SecretsVault.WatchLater.Contains(item.Id))
(addTo.Items[1] as ToggleMenuFlyoutItem).IsChecked = true;
PlaylistsResource.ListRequest request = SecretsVault.Service.Playlists.List("snippet");
request.Mine = true;
request.MaxResults = 50;
PlaylistListResponse response = await request.ExecuteAsync();
PlaylistItemsResource.ListRequest itemRequest = SecretsVault.Service.PlaylistItems.List("snippet");
itemRequest.VideoId = item.Id;
foreach (Playlist i in response.Items)
{
itemRequest.PlaylistId = i.Id;
ToggleMenuFlyoutItem menuItem = new ToggleMenuFlyoutItem
{
Text = i.Snippet.Title,
IsChecked = (await itemRequest.ExecuteAsync()).Items.Count > 0,
Tag = i,
Icon = new FontIcon
{
Glyph = "\xE728"
}
};
menuItem.Click += Item_Click;
addTo.Items.Add(menuItem);
} }
} }
@@ -497,7 +541,7 @@ namespace FoxTube.Controls
else else
{ {
HistorySet.Delete(history); HistorySet.Delete(history);
(Methods.MainPage.PageContent as History).Delete(this); (Methods.MainPage.PageContent.Frame.Content as History).Delete(this);
} }
return; return;
} }
@@ -512,12 +556,17 @@ namespace FoxTube.Controls
await SecretsVault.Service.PlaylistItems.Delete(playlistItem.Id).ExecuteAsync(); await SecretsVault.Service.PlaylistItems.Delete(playlistItem.Id).ExecuteAsync();
(Methods.MainPage.PageContent as PlaylistPage).DeleteItem(this); (Methods.MainPage.PageContent.Frame.Content as PlaylistPage).DeleteItem(this);
} }
catch catch
{ {
} }
} }
private void Card_SizeChanged(object sender, SizeChangedEventArgs e)
{
Height = e.NewSize.Width * 0.75;
}
} }
} }
+9 -1
View File
@@ -21,7 +21,7 @@
<PackageCertificateThumbprint>50B93E6A246058D555BA65CD203D7A02064A7409</PackageCertificateThumbprint> <PackageCertificateThumbprint>50B93E6A246058D555BA65CD203D7A02064A7409</PackageCertificateThumbprint>
<GenerateAppInstallerFile>False</GenerateAppInstallerFile> <GenerateAppInstallerFile>False</GenerateAppInstallerFile>
<AppxAutoIncrementPackageRevision>True</AppxAutoIncrementPackageRevision> <AppxAutoIncrementPackageRevision>True</AppxAutoIncrementPackageRevision>
<AppxPackageDir>E:\XFox\Documents\FoxTube builds\0.5\</AppxPackageDir> <AppxPackageDir>E:\XFox\Documents\FoxTube builds\0.6\</AppxPackageDir>
<AppxBundle>Always</AppxBundle> <AppxBundle>Always</AppxBundle>
<AppxBundlePlatforms>x86|x64|arm</AppxBundlePlatforms> <AppxBundlePlatforms>x86|x64|arm</AppxBundlePlatforms>
<AppInstallerUpdateFrequency>1</AppInstallerUpdateFrequency> <AppInstallerUpdateFrequency>1</AppInstallerUpdateFrequency>
@@ -103,6 +103,7 @@
<Compile Include="App.xaml.cs"> <Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon> <DependentUpon>App.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Classes\HistorySet.cs" />
<Compile Include="Classes\InboxItem.cs" /> <Compile Include="Classes\InboxItem.cs" />
<Compile Include="Classes\Methods.cs" /> <Compile Include="Classes\Methods.cs" />
<Compile Include="Classes\SearchPaameters.cs" /> <Compile Include="Classes\SearchPaameters.cs" />
@@ -130,6 +131,9 @@
<DependentUpon>CommentCard.xaml</DependentUpon> <DependentUpon>CommentCard.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Classes\DownloadAgent.cs" /> <Compile Include="Classes\DownloadAgent.cs" />
<Compile Include="Controls\ContentFrame.xaml.cs">
<DependentUpon>ContentFrame.xaml</DependentUpon>
</Compile>
<Compile Include="Controls\DownloadItem.xaml.cs"> <Compile Include="Controls\DownloadItem.xaml.cs">
<DependentUpon>DownloadItem.xaml</DependentUpon> <DependentUpon>DownloadItem.xaml</DependentUpon>
</Compile> </Compile>
@@ -309,6 +313,10 @@
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
<Page Include="Controls\ContentFrame.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Controls\DownloadItem.xaml"> <Page Include="Controls\DownloadItem.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3" IgnorableNamespaces="uap mp uap3"> <Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3" IgnorableNamespaces="uap mp uap3">
<Identity Name="53949MichaelXFoxGordeev.FoxTube" Publisher="CN=FD7A34DD-FE4D-4D7D-9D33-2DA9EBBE7725" Version="0.6.0.0" /> <Identity Name="53949MichaelXFoxGordeev.FoxTube" Publisher="CN=FD7A34DD-FE4D-4D7D-9D33-2DA9EBBE7725" Version="0.6.2.0" />
<mp:PhoneIdentity PhoneProductId="04fd81c1-6473-4174-afd7-4ac71dd85721" PhonePublisherId="00000000-0000-0000-0000-000000000000" /> <mp:PhoneIdentity PhoneProductId="04fd81c1-6473-4174-afd7-4ac71dd85721" PhonePublisherId="00000000-0000-0000-0000-000000000000" />
<Properties> <Properties>
<DisplayName>FoxTube</DisplayName> <DisplayName>FoxTube</DisplayName>
+1
View File
@@ -11,6 +11,7 @@ namespace FoxTube.Pages
public Home1() public Home1()
{ {
InitializeComponent(); InitializeComponent();
Methods.MainPage.PageContent.LoadingPage.Close();
} }
public async void Initialize() public async void Initialize()
+28 -32
View File
@@ -8,30 +8,28 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:pages="using:FoxTube.Pages" xmlns:pages="using:FoxTube.Pages"
xmlns:controls="using:FoxTube.Controls" xmlns:controls="using:FoxTube.Controls"
mc:Ignorable="d"> mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Page.Resources> <Page.Resources>
<Storyboard x:Name="showHeader"> <Storyboard x:Name="showHeader">
<DoubleAnimation Storyboard.TargetName="ColapsedHeader" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="{StaticResource CardOpacityDuration}"/> <DoubleAnimation Storyboard.TargetName="ColapsedHeader" Storyboard.TargetProperty="Opacity" To="1" Duration="{StaticResource CardOpacityDuration}"/>
</Storyboard> </Storyboard>
<Storyboard x:Name="hideHeader"> <Storyboard x:Name="hideHeader">
<DoubleAnimation Storyboard.TargetName="ColapsedHeader" Storyboard.TargetProperty="Opacity" From="1" To="0" Duration="{StaticResource CardOpacityDuration}"/> <DoubleAnimation Storyboard.TargetName="ColapsedHeader" Storyboard.TargetProperty="Opacity" To="0" Duration="{StaticResource CardOpacityDuration}"/>
</Storyboard> </Storyboard>
<Storyboard x:Name="showThumb"> <Storyboard x:Name="showThumb">
<DoubleAnimation Storyboard.TargetName="channelCover" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="{StaticResource CardOpacityDuration}"/> <DoubleAnimation Storyboard.TargetName="channelCover" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="{StaticResource CardOpacityDuration}"/>
</Storyboard> </Storyboard>
<Storyboard x:Name="hideThumb">
<DoubleAnimation Storyboard.TargetName="channelCover" Storyboard.TargetProperty="Opacity" From="1" To="0" Duration="{StaticResource CardOpacityDuration}"/>
</Storyboard>
</Page.Resources> </Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" SizeChanged="Grid_SizeChanged"> <Grid SizeChanged="Grid_SizeChanged">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition/> <RowDefinition/>
<RowDefinition Height="auto"/> <RowDefinition Height="auto"/>
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Pivot SelectedIndex="0" Name="content" IsHeaderItemsCarouselEnabled="False" SelectionChanged="Content_SelectionChanged"> <Pivot Name="content" IsHeaderItemsCarouselEnabled="False" SelectionChanged="Content_SelectionChanged">
<PivotItem x:Uid="/Channel/videos" Header="Videos"> <PivotItem x:Uid="/Channel/videos" Header="Videos">
<Grid> <Grid>
<ParallaxView Source="{x:Bind videoScroll}" VerticalShift="100"> <ParallaxView Source="{x:Bind videoScroll}" VerticalShift="100">
@@ -40,27 +38,27 @@
</Grid> </Grid>
</ParallaxView> </ParallaxView>
<ScrollViewer ViewChanged="ScrollViewer_ViewChanged" Name="videoScroll"> <ScrollViewer ViewChanged="ScrollViewer_ViewChanged" Name="videoScroll">
<StackPanel Background="{ThemeResource AppBarBackgroundThemeBrush}" Margin="0,300,0,0" Name="infoStack" Visibility="Visible"> <StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" Name="infoStack">
<Grid Name="infoPanel"> <Grid Name="infoPanel" Height="80">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="120"/> <ColumnDefinition Width="120"/>
<ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Ellipse HorizontalAlignment="Left" Margin="10,-40,0,0" Fill="Black" Width="100" Height="1"/> <Ellipse Fill="{ThemeResource ApplicationPageBackgroundThemeBrush}" Margin="5,-30,5,0"/>
<PersonPicture Name="avatar" HorizontalAlignment="Left" Margin="10,-40,0,0"/> <PersonPicture Name="avatar" Margin="10,-30,10,0"/>
<StackPanel Grid.Column="1" Orientation="Vertical" Margin="10,0,0,5">
<StackPanel Grid.Column="1">
<TextBlock Name="title" FontWeight="SemiBold" FontSize="22" Text="Channel name"/> <TextBlock Name="title" FontWeight="SemiBold" FontSize="22" Text="Channel name"/>
<TextBlock Name="subscribers" Foreground="Gray" Text="1,000,000 subscribers"/> <TextBlock Name="subscribers" Foreground="Gray" Text="1,000,000 subscribers"/>
<TextBlock Name="videosCount" Foreground="Gray" Text="563,000 videos"/> <TextBlock Name="videosCount" Foreground="Gray" Text="563,000 videos"/>
</StackPanel> </StackPanel>
<TextBlock Grid.Column="2" VerticalAlignment="Bottom" HorizontalAlignment="Stretch" Height="50" Margin="10" TextAlignment="Center" Padding="0,16,0,0" Foreground="Gray">
<Hyperlink Click="Hyperlink_Click"><Run x:Uid="/Cards/login">Log in</Run></Hyperlink> <Run x:Uid="/Cards/tomanage">to manage your subscriptions</Run> <TextBlock x:Name="logIn" Grid.Column="2" VerticalAlignment="Center" Margin="10" Width="250" HorizontalTextAlignment="Center" Foreground="Gray">
<Hyperlink Click="Hyperlink_Click"><Run x:Uid="/Cards/login">Log in</Run></Hyperlink> <Run x:Uid="/Cards/tomanage">to manage your subscriptions</Run>
</TextBlock> </TextBlock>
<Grid Visibility="Collapsed" Grid.Column="2" VerticalAlignment="Bottom" Margin="10" Name="subscriptionPane" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <Button Visibility="Collapsed" x:Name="subscribe" x:Uid="/Cards/subscribe" Grid.Column="2" Content="Subscribe" Height="50" Width="250" Margin="10" VerticalAlignment="Center" FontSize="18" FontWeight="SemiBold" Foreground="White" Background="Red"/>
<Button x:Uid="/Cards/subscribe" Click="Subscribe_Click" Name="subscribe" Width="250" Height="50" Background="Red" Foreground="White" FontSize="18" FontWeight="SemiBold" Content="Subscirbe"/>
</Grid>
</Grid> </Grid>
<pages:VideoGrid x:Name="videoList"/> <pages:VideoGrid x:Name="videoList"/>
<controls:ShowMore Clicked="VideoMore_Clicked" x:Name="videoMore"/> <controls:ShowMore Clicked="VideoMore_Clicked" x:Name="videoMore"/>
@@ -69,40 +67,38 @@
</Grid> </Grid>
</PivotItem> </PivotItem>
<PivotItem x:Uid="/Channel/playlists" Header="Playlists"> <PivotItem x:Uid="/Channel/playlists" Header="Playlists">
<ScrollViewer> <Grid>
<Grid> <ScrollViewer>
<StackPanel Margin="10" Visibility="Visible"> <StackPanel>
<pages:VideoGrid x:Name="playlistList"/> <pages:VideoGrid x:Name="playlistList"/>
<controls:ShowMore Clicked="ShowMorePlaylists_Click" x:Name="playlistMore"/> <controls:ShowMore Clicked="ShowMorePlaylists_Click" x:Name="playlistMore"/>
</StackPanel> </StackPanel>
<local:LoadingPage Visibility="Collapsed" x:Name="playlistLoading"/> </ScrollViewer>
</Grid> <local:LoadingPage Visibility="Collapsed" x:Name="playlistLoading" RefreshPage="Refresh_Click"/>
</ScrollViewer> </Grid>
</PivotItem> </PivotItem>
<PivotItem x:Uid="/Channel/about" Header="About channel"> <PivotItem x:Uid="/Channel/about" Header="About channel">
<ScrollViewer> <ScrollViewer>
<TextBlock Name="description" TextWrapping="WrapWholeWords" Margin="10" IsTextSelectionEnabled="True" Text="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum justo erat, dapibus sit amet maximus eget, volutpat non turpis. Suspendisse. "/> <TextBlock Name="description" TextWrapping="WrapWholeWords" IsTextSelectionEnabled="True" Text="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum justo erat, dapibus sit amet maximus eget, volutpat non turpis. Suspendisse."/>
</ScrollViewer> </ScrollViewer>
</PivotItem> </PivotItem>
<Pivot.RightHeader> <Pivot.RightHeader>
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal" Margin="10,0">
<StackPanel Orientation="Horizontal" Name="ColapsedHeader" Opacity="0"> <StackPanel Orientation="Horizontal" Name="ColapsedHeader" Opacity="0" Margin="10,0">
<PersonPicture Height="32" Name="collapsedAvatar"/> <PersonPicture Height="32" Name="collapsedAvatar"/>
<TextBlock Text="Channel name" VerticalAlignment="Center" Margin="10,0" Name="collapsedTitle"/> <TextBlock Text="Channel name" VerticalAlignment="Center" Margin="10,0" Name="collapsedTitle"/>
<Button x:Uid="/Cards/subscribe" Background="Red" Foreground="White" FontWeight="SemiBold" Content="Subscribe" Width="150" Name="collapsedBtn" Click="Subscribe_Click" Padding="2"/> <Button x:Uid="/Cards/subscribe" Background="Red" Foreground="White" FontWeight="SemiBold" Content="Subscribe" Width="150" Name="collapsedBtn" Click="Subscribe_Click" Padding="2" Visibility="Collapsed"/>
</StackPanel> </StackPanel>
<AutoSuggestBox FontSize="14" x:Uid="/Channel/search" 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" PlaceholderText="Search on channel" QueryIcon="Find" Name="search" QuerySubmitted="AutoSuggestBox_QuerySubmitted"/>
</StackPanel> </StackPanel>
</Pivot.RightHeader> </Pivot.RightHeader>
</Pivot> </Pivot>
<CommandBar Grid.Row="1" VerticalAlignment="Bottom" Name="commandBar"> <CommandBar Grid.Row="1" VerticalAlignment="Bottom" Name="commandBar">
<AppBarButton x:Uid="/Channel/openWeb" Icon="Globe" Label="Open in browser" Name="inBrowser" Click="InBrowser_Click"/> <AppBarButton x:Uid="/Channel/openWeb" Icon="Globe" Label="Open in browser" Name="inBrowser" Click="InBrowser_Click"/>
<AppBarButton x:Uid="/Channel/refresh" Icon="Refresh" Label="Refresh" Name="refresh" Click="Refresh_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"/> <AppBarButton x:Uid="/Channel/share" Icon="Share" Label="Share" Name="share" Click="Share_Click"/>
</CommandBar> </CommandBar>
<local:LoadingPage Grid.RowSpan="2" Visibility="Collapsed" x:Name="loading" RefreshPage="Refresh_Click"/>
</Grid> </Grid>
</Page> </Page>
+45 -57
View File
@@ -21,12 +21,11 @@ namespace FoxTube.Pages
/// <summary> /// <summary>
/// Channel page /// Channel page
/// </summary> /// </summary>
public sealed partial class ChannelPage : Page, NavigationPage public sealed partial class ChannelPage : Page, INavigationPage
{ {
public object Parameter { get; set; } = null; public object Parameter { get; set; } = null;
readonly ResourceLoader resources = ResourceLoader.GetForCurrentView("Cards"); readonly ResourceLoader resources = ResourceLoader.GetForCurrentView("Cards");
public string channelId;
public Channel item; public Channel item;
SearchResource.ListRequest request; SearchResource.ListRequest request;
@@ -37,35 +36,22 @@ namespace FoxTube.Pages
public ChannelPage() public ChannelPage()
{ {
InitializeComponent(); InitializeComponent();
DataTransferManager.GetForCurrentView().DataRequested += new TypedEventHandler<DataTransferManager, DataRequestedEventArgs>(Share);
} }
protected override void OnNavigatedTo(NavigationEventArgs e) protected override void OnNavigatedTo(NavigationEventArgs e)
{ {
base.OnNavigatedTo(e); base.OnNavigatedTo(e);
Parameter = e.Parameter; Parameter = e.Parameter;
if ((string)e.Parameter == null) Initialize(e.Parameter as string);
loading.Error("NullReferenceException", "Unable to initialize search. Search term is not stated.");
else
Initialize(e.Parameter as string);
} }
public async void Initialize(string id) public async void Initialize(string id)
{ {
loading.Refresh();
playlistLoading.Refresh();
try try
{ {
if (id == SecretsVault.AccountId)
{
infoPanel.ColumnDefinitions[2].Width = new GridLength(0);
collapsedBtn.Visibility = Visibility.Collapsed;
}
ChannelsResource.ListRequest infoRequest = SecretsVault.Service.Channels.List("snippet,statistics,brandingSettings"); ChannelsResource.ListRequest infoRequest = SecretsVault.Service.Channels.List("snippet,statistics,brandingSettings");
infoRequest.Id = channelId = id; infoRequest.Id = id;
item = (await infoRequest.ExecuteAsync()).Items[0]; item = (await infoRequest.ExecuteAsync()).Items[0];
@@ -73,14 +59,13 @@ namespace FoxTube.Pages
subscribers.Text = $"{item.Statistics.SubscriberCount:0,0} {resources.GetString("/Cards/subscribers")}"; subscribers.Text = $"{item.Statistics.SubscriberCount:0,0} {resources.GetString("/Cards/subscribers")}";
videosCount.Text = $"{item.Statistics.VideoCount:0,0} {resources.GetString("/Cards/videos")}"; videosCount.Text = $"{item.Statistics.VideoCount:0,0} {resources.GetString("/Cards/videos")}";
if (!item.BrandingSettings.Image.BannerImageUrl.Contains("default")) if (item.BrandingSettings != null && !item.BrandingSettings.Image.BannerImageUrl.Contains("default"))
try { channelCover.Source = new BitmapImage(item.BrandingSettings.Image.BannerTabletExtraHdImageUrl == null ? item.BrandingSettings.Image.BannerImageUrl.ToUri() : item.BrandingSettings.Image.BannerTabletHdImageUrl.ToUri()); } channelCover.Source = new BitmapImage(item.BrandingSettings.Image.BannerTabletExtraHdImageUrl == null ?
catch { } item.BrandingSettings.Image.BannerImageUrl.ToUri() : item.BrandingSettings.Image.BannerTabletHdImageUrl.ToUri());
try { avatar.ProfilePicture = collapsedAvatar.ProfilePicture = new BitmapImage(item.Snippet.Thumbnails.Medium.Url.ToUri()) { DecodePixelHeight = 100, DecodePixelWidth = 100 }; } avatar.ProfilePicture = collapsedAvatar.ProfilePicture = new BitmapImage(item.Snippet.Thumbnails.Medium.Url.ToUri()) { DecodePixelHeight = 100, DecodePixelWidth = 100 };
catch { }
Methods.FormatText(ref description, item.Snippet.Description); description.FormatText(item.Snippet.Description);
request = SecretsVault.Service.Search.List("id"); request = SecretsVault.Service.Search.List("id");
request.ChannelId = id; request.ChannelId = id;
@@ -100,34 +85,42 @@ namespace FoxTube.Pages
if (SecretsVault.IsAuthorized) if (SecretsVault.IsAuthorized)
{ {
if (SecretsVault.Subscriptions.Any(i => i.Snippet.ResourceId.ChannelId == channelId)) logIn.Visibility = Visibility.Collapsed;
if (SecretsVault.Subscriptions.Any(i => i.Snippet.ResourceId.ChannelId == item.Id))
{ {
subscribe.Background = new SolidColorBrush(Colors.Transparent); subscribe.Background = Background;
subscribe.Foreground = new SolidColorBrush(Colors.Gray); subscribe.Foreground = new SolidColorBrush(Colors.Gray);
subscribe.Content = resources.GetString("/Cards/unsubscribe"); subscribe.Content = resources.GetString("/Cards/unsubscribe");
collapsedBtn.Visibility = Visibility.Collapsed;
} }
subscriptionPane.Visibility = Visibility.Visible; else
collapsedBtn.Visibility = Visibility.Visible;
subscribe.Visibility = Visibility.Visible;
} }
loading.Close(); if (id == SecretsVault.AccountId)
{
infoPanel.ColumnDefinitions[2].Width = new GridLength(0);
collapsedBtn.Visibility = Visibility.Collapsed;
}
ScrollViewer_ViewChanged(this, null);
Methods.MainPage.PageContent.LoadingPage.Close();
} }
catch (System.Net.Http.HttpRequestException) catch (System.Net.Http.HttpRequestException)
{ {
loading.Error("System.Net.Http.HttpRequestException", "Unable to connect to Google servers.", true); Methods.MainPage.PageContent.LoadingPage.Error("System.Net.Http.HttpRequestException", "Unable to connect to Google servers.", true);
} }
catch (Exception e) catch (Exception e)
{ {
loading.Error(e.GetType().ToString(), e.Message); Methods.MainPage.PageContent.LoadingPage.Error(e.GetType().ToString(), e.Message);
Analytics.TrackEvent("Channel loading error", new Dictionary<string, string>() Analytics.TrackEvent("Channel loading error", new Dictionary<string, string>()
{ {
{ "Exception", e.GetType().ToString() }, { "Exception", e.GetType().ToString() },
{ "Message", e.Message }, { "Message", e.Message },
{ "Channel ID", channelId } { "Channel ID", item.Id }
}); });
} }
ScrollViewer_ViewChanged(this, null);
} }
async void LoadPlaylist() async void LoadPlaylist()
@@ -162,7 +155,7 @@ namespace FoxTube.Pages
{ {
{ "Exception", e.GetType().ToString() }, { "Exception", e.GetType().ToString() },
{ "Message", e.Message }, { "Message", e.Message },
{ "Channel ID", channelId } { "Channel ID", item.Id }
}); });
} }
} }
@@ -216,9 +209,9 @@ namespace FoxTube.Pages
private async void Subscribe_Click(object sender, RoutedEventArgs e) private async void Subscribe_Click(object sender, RoutedEventArgs e)
{ {
if(await SecretsVault.ChangeSubscriptionState(channelId)) if(await SecretsVault.ChangeSubscriptionState(item.Id))
{ {
subscribe.Background = new SolidColorBrush(Colors.Transparent); subscribe.Background = Background;
subscribe.Foreground = new SolidColorBrush(Colors.Gray); subscribe.Foreground = new SolidColorBrush(Colors.Gray);
subscribe.Content = resources.GetString("/Cards/unsubscribe"); subscribe.Content = resources.GetString("/Cards/unsubscribe");
collapsedBtn.Visibility = Visibility.Collapsed; collapsedBtn.Visibility = Visibility.Collapsed;
@@ -239,18 +232,18 @@ namespace FoxTube.Pages
private void AutoSuggestBox_QuerySubmitted(AutoSuggestBox sender, AutoSuggestBoxQuerySubmittedEventArgs args) private void AutoSuggestBox_QuerySubmitted(AutoSuggestBox sender, AutoSuggestBoxQuerySubmittedEventArgs args)
{ {
if(search.Text.Length > 2) if (search.Text.Length < 3)
{ return;
if(content.Items.Count < 4)
content.Items.Add(new PivotItem()
{
Header = resources.GetString("/Channel/searchHeader"),
Content = new Search()
});
((content.Items[3] as PivotItem).Content as Search).Initialize(new SearchParameters(search.Text, item.Id)); if (content.Items.Count < 4)
content.SelectedIndex = 3; content.Items.Add(new PivotItem()
} {
Header = resources.GetString("/Channel/searchHeader"),
Content = new ContentFrame()
});
((content.Items[3] as PivotItem).Content as ContentFrame).Frame.Navigate(typeof(Search), new object[] { new SearchParameters(search.Text, item.Id), (content.Items[3] as PivotItem).Content as ContentFrame });
content.SelectedIndex = 3;
} }
private void ScrollViewer_ViewChanged(object sender, ScrollViewerViewChangedEventArgs e) private void ScrollViewer_ViewChanged(object sender, ScrollViewerViewChangedEventArgs e)
@@ -259,20 +252,14 @@ namespace FoxTube.Pages
Rect view = new Rect(0.0, 0.0, videoScroll.ActualWidth, videoScroll.ActualHeight); Rect view = new Rect(0.0, 0.0, videoScroll.ActualWidth, videoScroll.ActualHeight);
if (view.Contains(new Point(panel.Left, panel.Bottom))) if (view.Contains(new Point(panel.Left, panel.Bottom)))
{ hideHeader.Begin();
if (ColapsedHeader.Opacity == 1)
hideHeader.Begin();
}
else else
{ showHeader.Begin();
if (ColapsedHeader.Opacity == 0)
showHeader.Begin();
}
} }
private void Refresh_Click(object sender, RoutedEventArgs e) private void Refresh_Click(object sender, RoutedEventArgs e)
{ {
Methods.MainPage.GoToChannel(channelId); Methods.MainPage.PageContent.Refresh();
} }
private async void InBrowser_Click(object sender, RoutedEventArgs e) private async void InBrowser_Click(object sender, RoutedEventArgs e)
@@ -282,6 +269,7 @@ namespace FoxTube.Pages
private void Share_Click(object sender, RoutedEventArgs e) private void Share_Click(object sender, RoutedEventArgs e)
{ {
DataTransferManager.GetForCurrentView().DataRequested += new TypedEventHandler<DataTransferManager, DataRequestedEventArgs>(Share);
DataTransferManager.ShowShareUI(); DataTransferManager.ShowShareUI();
} }
+22 -27
View File
@@ -5,52 +5,47 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="using:FoxTube.Controls" xmlns:controls="using:FoxTube.Controls"
mc:Ignorable="d" mc:Ignorable="d">
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid> <Grid x:Name="grid">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="auto"/> <RowDefinition Height="auto"/>
<RowDefinition Height="30"/>
<RowDefinition/> <RowDefinition/>
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid Name="grid"> <TextBox x:Uid="/CommentsPage/textbox" PlaceholderText="Add a public comment" Name="newComment" MinHeight="32" TextWrapping="Wrap" AcceptsReturn="True" Margin="0,0,40,0"/>
<Grid.RowDefinitions> <Button HorizontalAlignment="Right" Name="send" Click="send_Click" VerticalAlignment="Top"
<RowDefinition Height="auto"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<TextBox x:Uid="/CommentsPage/textbox" Margin="5,5,42,5" PlaceholderText="Add a public comment" Name="newComment" VerticalAlignment="Center" MinHeight="32" TextWrapping="Wrap" AcceptsReturn="True"/>
<Button HorizontalAlignment="Right" Name="send" Click="send_Click" VerticalAlignment="Top"
Height="32" Width="32" Height="32" Width="32"
Margin="0,5,5,0" Padding="0" Margin="5,0" Padding="0"
Background="Transparent" Background="Transparent"
FontFamily="Segoe MDL2 Assets" FontFamily="Segoe MDL2 Assets"
Content="&#xE122;" FontSize="30"/> Content="&#xE122;" FontSize="30"/>
<ProgressBar Name="sending" IsIndeterminate="True" Foreground="Red" Visibility="Collapsed" VerticalAlignment="Bottom" HorizontalAlignment="Stretch"/> <ProgressBar Name="sending" IsIndeterminate="True" Visibility="Collapsed" VerticalAlignment="Bottom" HorizontalAlignment="Stretch"/>
<TextBlock Name="counter" Grid.Row="1" Text="[Comments count] Comments" Margin="5,0,0,0" VerticalAlignment="Center" FontWeight="SemiBold"/> <TextBlock Name="counter" Grid.Row="1" Text="[Comments count] Comments" VerticalAlignment="Center" FontWeight="SemiBold"/>
<StackPanel Padding="0" Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,0,10,0"> <StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Right">
<TextBlock x:Uid="/CommentsPage/sortBy" Text="Sort by: " VerticalAlignment="Center" Margin="0,0,5,0"/> <TextBlock x:Uid="/CommentsPage/sortBy" Text="Sort by: " VerticalAlignment="Center"/>
<Button Name="orderBtn" Background="Transparent" Content="Relevance" Foreground="Red" Padding="0" VerticalAlignment="Bottom" HorizontalAlignment="Center" Margin="0,0,0,3"> <Button Name="orderBtn" Background="Transparent" Content="Relevance" Foreground="Red" Padding="0" VerticalAlignment="Bottom" Margin="5,3">
<Button.Flyout> <Button.Flyout>
<MenuFlyout> <MenuFlyout>
<MenuFlyoutItem x:Uid="/CommentsPage/relevance" Click="toRelevance_Click" Name="toRelevance" Text="Relevance"/> <MenuFlyoutItem x:Uid="/CommentsPage/relevance" Click="toRelevance_Click" Name="toRelevance" Text="Relevance"/>
<MenuFlyoutItem x:Uid="/CommentsPage/date" Click="toDate_Click" Name="toDate" Text="Date"/> <MenuFlyoutItem x:Uid="/CommentsPage/date" Click="toDate_Click" Name="toDate" Text="Date"/>
</MenuFlyout> </MenuFlyout>
</Button.Flyout> </Button.Flyout>
</Button> </Button>
</StackPanel> </StackPanel>
</Grid>
<ScrollViewer Grid.Row="1" Name="scroll"> <ScrollViewer Grid.Row="2" Name="scroll">
<StackPanel> <StackPanel>
<StackPanel Name="placeholder"> <StackPanel x:Name="list">
<StackPanel.ChildrenTransitions> <StackPanel.ChildrenTransitions>
<TransitionCollection> <TransitionCollection>
<EntranceThemeTransition IsStaggeringEnabled="True"/> <EntranceThemeTransition IsStaggeringEnabled="True"/>
</TransitionCollection> </TransitionCollection>
</StackPanel.ChildrenTransitions> </StackPanel.ChildrenTransitions>
</StackPanel> </StackPanel>
<controls:ShowMore x:Name="more" Clicked="ShowMore_Clicked"/> <controls:ShowMore x:Name="more" Clicked="ShowMore_Clicked"/>
</StackPanel> </StackPanel>
</ScrollViewer> </ScrollViewer>
+45 -25
View File
@@ -6,6 +6,8 @@ using Google.Apis.YouTube.v3.Data;
using FoxTube.Controls; using FoxTube.Controls;
using Windows.UI.Popups; using Windows.UI.Popups;
using Windows.ApplicationModel.Resources; using Windows.ApplicationModel.Resources;
using Microsoft.AppCenter.Analytics;
using System.Collections.Generic;
namespace FoxTube.Pages namespace FoxTube.Pages
{ {
@@ -52,18 +54,18 @@ namespace FoxTube.Pages
foreach (CommentThread comment in response.Items) foreach (CommentThread comment in response.Items)
{ {
if ((placeholder.Children.Count - 5) % 20 == 0 && !SecretsVault.AdsDisabled) if ((list.Children.Count - 5) % 20 == 0 && !SecretsVault.AdsDisabled)
placeholder.Children.Add(new Controls.Adverts.CommentAdvert()); list.Children.Add(new Controls.Adverts.CommentAdvert());
placeholder.Children.Add(new CommentCard(comment)); list.Children.Add(new CommentCard(comment));
} }
} }
public void RemoveComment(CommentCard commentCard, string topCommentId = null) public void RemoveComment(CommentCard commentCard, string topCommentId = null)
{ {
if (string.IsNullOrWhiteSpace(topCommentId)) if (string.IsNullOrWhiteSpace(topCommentId))
placeholder.Children.Remove(commentCard); list.Children.Remove(commentCard);
else else
(placeholder.Children.Find(i => (i as CommentCard).thread.Id == topCommentId) as CommentCard).DeleteComment(commentCard); (list.Children.Find(i => (i as CommentCard).thread.Id == topCommentId) as CommentCard)?.DeleteComment(commentCard);
} }
private async void toRelevance_Click(object sender, RoutedEventArgs e) private async void toRelevance_Click(object sender, RoutedEventArgs e)
@@ -71,12 +73,12 @@ namespace FoxTube.Pages
if (order == CommentThreadsResource.ListRequest.OrderEnum.Relevance) if (order == CommentThreadsResource.ListRequest.OrderEnum.Relevance)
return; return;
more.Show(); more.Visibility = Visibility.Visible;
order = CommentThreadsResource.ListRequest.OrderEnum.Relevance; order = CommentThreadsResource.ListRequest.OrderEnum.Relevance;
orderBtn.Content = resources.GetString("/CommentsPage/relevance/Text"); orderBtn.Content = resources.GetString("/CommentsPage/relevance/Text");
placeholder.Children.Clear(); list.Children.Clear();
request.Order = order; request.Order = order;
var response = await request.ExecuteAsync(); var response = await request.ExecuteAsync();
@@ -86,7 +88,11 @@ namespace FoxTube.Pages
more.Visibility = Visibility.Collapsed; more.Visibility = Visibility.Collapsed;
foreach (CommentThread comment in response.Items) foreach (CommentThread comment in response.Items)
placeholder.Children.Add(new CommentCard(comment)); {
if ((list.Children.Count - 5) % 20 == 0 && !SecretsVault.AdsDisabled)
list.Children.Add(new Controls.Adverts.CommentAdvert());
list.Children.Add(new CommentCard(comment));
}
more.Complete(); more.Complete();
} }
@@ -96,12 +102,12 @@ namespace FoxTube.Pages
if (order == CommentThreadsResource.ListRequest.OrderEnum.Time) if (order == CommentThreadsResource.ListRequest.OrderEnum.Time)
return; return;
more.Show(); more.Visibility = Visibility.Visible;
order = CommentThreadsResource.ListRequest.OrderEnum.Time; order = CommentThreadsResource.ListRequest.OrderEnum.Time;
orderBtn.Content = resources.GetString("/CommentsPage/publish"); orderBtn.Content = resources.GetString("/CommentsPage/publish");
placeholder.Children.Clear(); list.Children.Clear();
request.Order = order; request.Order = order;
var response = await request.ExecuteAsync(); var response = await request.ExecuteAsync();
@@ -111,12 +117,16 @@ namespace FoxTube.Pages
more.Visibility = Visibility.Collapsed; more.Visibility = Visibility.Collapsed;
foreach (CommentThread comment in response.Items) foreach (CommentThread comment in response.Items)
placeholder.Children.Add(new CommentCard(comment)); {
if ((list.Children.Count - 5) % 20 == 0 && !SecretsVault.AdsDisabled)
list.Children.Add(new Controls.Adverts.CommentAdvert());
list.Children.Add(new CommentCard(comment));
}
more.Complete(); more.Complete();
} }
private async void send_Click(object sender, RoutedEventArgs e) private async void send_Click(object sender, RoutedEventArgs args)
{ {
if (string.IsNullOrWhiteSpace(newComment.Text)) if (string.IsNullOrWhiteSpace(newComment.Text))
return; return;
@@ -125,13 +135,13 @@ namespace FoxTube.Pages
send.IsEnabled = false; send.IsEnabled = false;
sending.Visibility = Visibility.Visible; sending.Visibility = Visibility.Visible;
CommentThread thread = new CommentThread() CommentThread thread = new CommentThread
{ {
Snippet = new CommentThreadSnippet() Snippet = new CommentThreadSnippet
{ {
TopLevelComment = new Comment() TopLevelComment = new Comment
{ {
Snippet = new CommentSnippet() Snippet = new CommentSnippet
{ {
TextOriginal = newComment.Text TextOriginal = newComment.Text
} }
@@ -143,11 +153,20 @@ namespace FoxTube.Pages
try try
{ {
CommentThread response = await SecretsVault.Service.CommentThreads.Insert(thread, "snippet").ExecuteAsync(); CommentThread response = await SecretsVault.Service.CommentThreads.Insert(thread, "snippet").ExecuteAsync();
placeholder.Children.Insert(0, new CommentCard(response)); list.Children.Insert(0, new CommentCard(response));
newComment.Text = ""; newComment.Text = "";
scroll.ChangeView(null, 0, null); scroll.ChangeView(null, 0, null);
} }
catch { await new MessageDialog("Failed to publish your comment. Please, try again later.").ShowAsync(); } catch (Exception e)
{
await new MessageDialog("Failed to publish your comment. Please, try again later.").ShowAsync();
Analytics.TrackEvent("Failed to post comment", new Dictionary<string, string>
{
{ "Exception", e.GetType().ToString() },
{ "Message", e.Message },
{ "Thread ID", threadId }
});
}
newComment.IsEnabled = true; newComment.IsEnabled = true;
send.IsEnabled = true; send.IsEnabled = true;
@@ -158,18 +177,19 @@ namespace FoxTube.Pages
{ {
request.PageToken = token; request.PageToken = token;
var response = await request.ExecuteAsync(); var response = await request.ExecuteAsync();
token = response.NextPageToken;
if (string.IsNullOrWhiteSpace(token))
more.Visibility = Visibility.Collapsed;
foreach (CommentThread comment in response.Items) foreach (CommentThread comment in response.Items)
{ {
if ((placeholder.Children.Count - 5) % 20 == 0 && !SecretsVault.AdsDisabled) if ((list.Children.Count - 5) % 20 == 0 && !SecretsVault.AdsDisabled)
placeholder.Children.Add(new Controls.Adverts.CommentAdvert()); list.Children.Add(new Controls.Adverts.CommentAdvert());
placeholder.Children.Add(new CommentCard(comment)); list.Children.Add(new CommentCard(comment));
} }
token = response.NextPageToken;
more.Complete(); more.Complete();
if (string.IsNullOrWhiteSpace(token))
more.Visibility = Visibility.Collapsed;
} }
} }
} }
-6
View File
@@ -11,7 +11,6 @@
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="auto"/> <RowDefinition Height="auto"/>
<RowDefinition/> <RowDefinition/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid Margin="10"> <Grid Margin="10">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
@@ -22,7 +21,6 @@
<Button Grid.Column="1" x:Uid="/Downloads/openFolder" Content="Open folder" Name="open" Click="Open_Click" VerticalAlignment="Center"/> <Button Grid.Column="1" x:Uid="/Downloads/openFolder" Content="Open folder" Name="open" Click="Open_Click" VerticalAlignment="Center"/>
</Grid> </Grid>
<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"/> <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"/>
<ScrollViewer Grid.Row="1"> <ScrollViewer Grid.Row="1">
@@ -34,9 +32,5 @@
</StackPanel.ChildrenTransitions> </StackPanel.ChildrenTransitions>
</StackPanel> </StackPanel>
</ScrollViewer> </ScrollViewer>
<CommandBar Grid.Row="2">
<AppBarButton x:Uid="/Downloads/refresh" Label="Refresh" Icon="Refresh" Click="Refresh"/>
</CommandBar>
</Grid> </Grid>
</Page> </Page>
+15 -10
View File
@@ -3,13 +3,14 @@ using System;
using Windows.System; using Windows.System;
using Windows.UI.Xaml; using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
namespace FoxTube.Pages namespace FoxTube.Pages
{ {
/// <summary> /// <summary>
/// Downloads page /// Downloads page
/// </summary> /// </summary>
public sealed partial class Downloads : Page, NavigationPage public sealed partial class Downloads : Page, INavigationPage
{ {
public object Parameter { get; set; } = null; public object Parameter { get; set; } = null;
public Downloads() public Downloads()
@@ -17,7 +18,19 @@ namespace FoxTube.Pages
InitializeComponent(); InitializeComponent();
DownloadAgent.Page = this; DownloadAgent.Page = this;
path.Text = DownloadAgent.Downloads.Path; path.Text = DownloadAgent.Downloads.Path;
Refresh(this, null);
list.Children.Clear();
DownloadAgent.Items.ForEach(i => list.Children.Add(i));
empty.Visibility = list.Children.Count == 0 ? Visibility.Visible : Visibility.Collapsed;
Methods.MainPage.PageContent.LoadingPage.Close();
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
base.OnNavigatedFrom(e);
DownloadAgent.Page = null;
} }
private async void Open_Click(object sender, RoutedEventArgs e) private async void Open_Click(object sender, RoutedEventArgs e)
@@ -25,14 +38,6 @@ namespace FoxTube.Pages
await Launcher.LaunchFolderAsync(DownloadAgent.Downloads); await Launcher.LaunchFolderAsync(DownloadAgent.Downloads);
} }
private void Refresh(object sender, RoutedEventArgs e)
{
list.Children.Clear();
DownloadAgent.items.ForEach(i => list.Children.Add(i));
empty.Visibility = list.Children.Count == 0 ? Visibility.Visible : Visibility.Collapsed;
}
public void Remove(DownloadItem item) public void Remove(DownloadItem item)
{ {
list.Children.Remove(item); list.Children.Remove(item);
-7
View File
@@ -55,13 +55,6 @@
</Grid> </Grid>
</PivotItem> </PivotItem>
</Pivot> </Pivot>
<!--<ScrollViewer>
<StackPanel>
<local:VideoGrid x:Name="list"/>
<controls:ShowMore Clicked="ShowMore_Clicked" x:Name="more"/>
</StackPanel>
</ScrollViewer>-->
<CommandBar Grid.Row="1" DefaultLabelPosition="Right"> <CommandBar Grid.Row="1" DefaultLabelPosition="Right">
<AppBarButton x:Uid="/Playlist/refresh" Icon="Refresh" Label="Refresh" Name="refresh" Click="Refresh_Click"/> <AppBarButton x:Uid="/Playlist/refresh" Icon="Refresh" Label="Refresh" Name="refresh" Click="Refresh_Click"/>
+9 -7
View File
@@ -14,7 +14,7 @@ namespace FoxTube.Pages
/// <summary> /// <summary>
/// YouTube history page /// YouTube history page
/// </summary> /// </summary>
public sealed partial class History : Page, NavigationPage public sealed partial class History : Page, INavigationPage
{ {
public object Parameter { get; set; } = null; public object Parameter { get; set; } = null;
int page = 1; int page = 1;
@@ -31,10 +31,12 @@ namespace FoxTube.Pages
Parameter = e.Parameter; Parameter = e.Parameter;
Initialize(); Initialize();
Methods.MainPage.PageContent.LoadingPage.Close();
} }
public async void Initialize() public async void Initialize()
{ {
Methods.MainPage.VideoContent.LoadingPage.Close();
try try
{ {
loading.Refresh(); loading.Refresh();
@@ -71,7 +73,7 @@ namespace FoxTube.Pages
private void Refresh_Click(object sender, RoutedEventArgs e) private void Refresh_Click(object sender, RoutedEventArgs e)
{ {
Methods.MainPage.GoToHistory(); Methods.MainPage.VideoContent.Refresh();
} }
private async void ShowMore_Clicked() private async void ShowMore_Clicked()
@@ -135,10 +137,10 @@ namespace FoxTube.Pages
{ {
websiteLoading.Error(e.GetType().ToString(), e.Message); websiteLoading.Error(e.GetType().ToString(), e.Message);
Analytics.TrackEvent("History loading error", new Dictionary<string, string>() Analytics.TrackEvent("History loading error", new Dictionary<string, string>()
{ {
{ "Exception", e.GetType().ToString() }, { "Exception", e.GetType().ToString() },
{ "Message", e.Message } { "Message", e.Message }
}); });
} }
}); });
} }
@@ -148,7 +150,7 @@ namespace FoxTube.Pages
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{ {
for (int k = 25 * webPage++; k < 25 * webPage && k < SecretsVault.History.Count; k++) for (int k = 25 * webPage++; k < 25 * webPage && k < SecretsVault.History.Count; k++)
websiteList.Add(new VideoCard(HistorySet.Items[k].Id, "HL")); websiteList.Add(new VideoCard(SecretsVault.History[k], "HL"));
if (websiteList.Count >= SecretsVault.History.Count) if (websiteList.Count >= SecretsVault.History.Count)
websiteMore.Visibility = Visibility.Collapsed; websiteMore.Visibility = Visibility.Collapsed;
+46 -62
View File
@@ -7,71 +7,55 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:pages="using:FoxTube.Pages" xmlns:pages="using:FoxTube.Pages"
xmlns:controls="using:FoxTube.Controls" xmlns:controls="using:FoxTube.Controls"
mc:Ignorable="d"> mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Pivot SelectionChanged="pivot_SelectionChanged" Name="pivot"> <Grid>
<PivotItem Name="recommended" Header="Recommended" x:Uid="/Home/recommended"> <Grid.RowDefinitions>
<Grid> <RowDefinition/>
<Grid.RowDefinitions> <RowDefinition Height="Auto"/>
<RowDefinition/> </Grid.RowDefinitions>
<RowDefinition Height="auto"/> <Pivot SelectionChanged="pivot_SelectionChanged" Name="pivot">
</Grid.RowDefinitions> <PivotItem Name="recommended" Header="Recommended" x:Uid="/Home/recommended">
<Grid>
<ScrollViewer>
<StackPanel>
<pages:VideoGrid x:Name="recGrid"/>
<controls:ShowMore Clicked="Recommended_More" x:Name="recommendedMore"/>
</StackPanel>
</ScrollViewer>
<ScrollViewer> <local:LoadingPage x:Name="recsLoading" Grid.RowSpan="2" RefreshPage="Refresh_Click"/>
<StackPanel> </Grid>
<pages:VideoGrid x:Name="recGrid"/> </PivotItem>
<controls:ShowMore Clicked="Recommended_More" x:Name="recommendedMore"/> <PivotItem Name="trending" Header="Trending" x:Uid="/Home/trending">
</StackPanel> <Grid>
</ScrollViewer> <ScrollViewer>
<StackPanel>
<pages:VideoGrid x:Name="trendGrid"/>
<controls:ShowMore Clicked="Trending_More" x:Name="trendingMore"/>
</StackPanel>
</ScrollViewer>
<CommandBar Grid.Row="1"> <local:LoadingPage x:Name="trendsLoading" Grid.RowSpan="2" RefreshPage="Refresh_Click"/>
<AppBarButton Icon="Refresh" Label="Refresh" x:Uid="/Home/refresh" Click="Recommended_Refresh"/> </Grid>
</CommandBar> </PivotItem>
<PivotItem Name="subscriptions" Header="Subscriptions" x:Uid="/Home/subs">
<Grid>
<ScrollViewer>
<StackPanel>
<pages:VideoGrid x:Name="subsGrid"/>
<controls:ShowMore Clicked="Subscriptions_More" x:Name="subscriptionsMore"/>
</StackPanel>
</ScrollViewer>
<local:LoadingPage x:Name="recsLoading" Grid.RowSpan="2" RefreshPage="Recommended_Refresh"/> <local:LoadingPage x:Name="subsLoading" Grid.RowSpan="2" RefreshPage="Refresh_Click"/>
</Grid> </Grid>
</PivotItem> </PivotItem>
<PivotItem Name="trending" Header="Trending" x:Uid="/Home/trending"> </Pivot>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<ScrollViewer> <CommandBar Grid.Row="1" Name="commandbar">
<StackPanel> <AppBarButton Icon="Refresh" Label="Refresh" x:Uid="/Home/refresh" Click="Refresh_Click"/>
<pages:VideoGrid x:Name="trendGrid"/> </CommandBar>
<controls:ShowMore Clicked="Trending_More" x:Name="trendingMore"/> </Grid>
</StackPanel>
</ScrollViewer>
<CommandBar Grid.Row="1">
<AppBarButton Icon="Refresh" Label="Refresh" x:Uid="/Home/refresh" Click="Trends_Refresh"/>
</CommandBar>
<local:LoadingPage x:Name="trendsLoading" Grid.RowSpan="2" RefreshPage="Trends_Refresh"/>
</Grid>
</PivotItem>
<PivotItem Name="subscriptions" Header="Subscriptions" x:Uid="/Home/subs">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<ScrollViewer>
<StackPanel>
<pages:VideoGrid x:Name="subsGrid"/>
<controls:ShowMore Clicked="Subscriptions_More" x:Name="subscriptionsMore"/>
</StackPanel>
</ScrollViewer>
<CommandBar Grid.Row="1">
<AppBarButton Icon="Refresh" Label="Refresh" x:Uid="/Home/refresh" Click="Subscriptions_Refresh"/>
</CommandBar>
<local:LoadingPage x:Name="subsLoading" Grid.RowSpan="2" RefreshPage="Subscriptions_Refresh"/>
</Grid>
</PivotItem>
</Pivot>
</Page> </Page>
+24 -27
View File
@@ -14,7 +14,7 @@ namespace FoxTube
/// <summary> /// <summary>
/// Home page /// Home page
/// </summary> /// </summary>
public sealed partial class Home : Page, NavigationPage public sealed partial class Home : Page, INavigationPage
{ {
public object Parameter { get; set; } = null; public object Parameter { get; set; } = null;
private bool trendLoaded = false, recLoaded = false, subsLoaded = false; private bool trendLoaded = false, recLoaded = false, subsLoaded = false;
@@ -27,6 +27,7 @@ namespace FoxTube
public Home() public Home()
{ {
InitializeComponent(); InitializeComponent();
SecretsVault.RefreshToken();
Initialize(); Initialize();
} }
@@ -41,6 +42,8 @@ namespace FoxTube
private void pivot_SelectionChanged(object sender, SelectionChangedEventArgs e) private void pivot_SelectionChanged(object sender, SelectionChangedEventArgs e)
{ {
Methods.MainPage.PageContent.LoadingPage.Close();
if (pivot.SelectedItem == recommended && !recLoaded) if (pivot.SelectedItem == recommended && !recLoaded)
LoadRecommendations(); LoadRecommendations();
else if (pivot.SelectedItem == trending && !trendLoaded) else if (pivot.SelectedItem == trending && !trendLoaded)
@@ -52,6 +55,7 @@ namespace FoxTube
#region Initializing tabs #region Initializing tabs
async void LoadRecommendations() async void LoadRecommendations()
{ {
recLoaded = false;
try try
{ {
recsLoading.Refresh(); recsLoading.Refresh();
@@ -71,12 +75,10 @@ namespace FoxTube
} }
catch (HttpRequestException) catch (HttpRequestException)
{ {
recLoaded = false;
recsLoading.Error("System.Net.Http.HttpRequestException", "Unable to connect to Google servers.", true); recsLoading.Error("System.Net.Http.HttpRequestException", "Unable to connect to Google servers.", true);
} }
catch (Exception e) catch (Exception e)
{ {
recLoaded = false;
recsLoading.Error(e.GetType().ToString(), e.Message); recsLoading.Error(e.GetType().ToString(), e.Message);
Analytics.TrackEvent("Failed to load recommendations", new Dictionary<string, string>() Analytics.TrackEvent("Failed to load recommendations", new Dictionary<string, string>()
@@ -88,6 +90,7 @@ namespace FoxTube
} }
async void LoadTrending() async void LoadTrending()
{ {
trendLoaded = false;
try try
{ {
trendsLoading.Refresh(); trendsLoading.Refresh();
@@ -111,12 +114,10 @@ namespace FoxTube
} }
catch (HttpRequestException) catch (HttpRequestException)
{ {
trendLoaded = false;
trendsLoading.Error("System.Net.Http.HttpRequestException", "Unable to connect to Google servers.", true); trendsLoading.Error("System.Net.Http.HttpRequestException", "Unable to connect to Google servers.", true);
} }
catch(Exception e) catch(Exception e)
{ {
trendLoaded = false;
trendsLoading.Error(e.GetType().ToString(), e.Message); trendsLoading.Error(e.GetType().ToString(), e.Message);
Analytics.TrackEvent("Failed to load trendings", new Dictionary<string, string>() Analytics.TrackEvent("Failed to load trendings", new Dictionary<string, string>()
@@ -128,11 +129,11 @@ namespace FoxTube
} }
async void LoadSubscriptions() async void LoadSubscriptions()
{ {
subsLoaded = false;
try try
{ {
subsLoading.Refresh(); subsLoading.Refresh();
await SecretsVault.HttpClient.GetStringAsync("https://www.youtube.com/list_ajax?style=json&action_get_list=1&list=WL");
string response = await SecretsVault.HttpClient.GetStringAsync("https://www.youtube.com/feed/subscriptions"); string response = await SecretsVault.HttpClient.GetStringAsync("https://www.youtube.com/feed/subscriptions");
foreach (Match match in Regex.Matches(response, @"\bdata-context-item-id=(\S*)\b", RegexOptions.IgnoreCase)) foreach (Match match in Regex.Matches(response, @"\bdata-context-item-id=(\S*)\b", RegexOptions.IgnoreCase))
@@ -148,12 +149,10 @@ namespace FoxTube
} }
catch (HttpRequestException) catch (HttpRequestException)
{ {
subsLoaded = false;
subsLoading.Error("System.Net.Http.HttpRequestException", "Unable to connect to Google servers.", true); subsLoading.Error("System.Net.Http.HttpRequestException", "Unable to connect to Google servers.", true);
} }
catch (Exception e) catch (Exception e)
{ {
subsLoaded = false;
subsLoading.Error(e.GetType().ToString(), e.Message); subsLoading.Error(e.GetType().ToString(), e.Message);
Analytics.TrackEvent("Failed to load subscriptions", new Dictionary<string, string>() Analytics.TrackEvent("Failed to load subscriptions", new Dictionary<string, string>()
@@ -198,26 +197,24 @@ namespace FoxTube
} }
#endregion #endregion
#region Refreshing tabs private void Refresh_Click(object sender, RoutedEventArgs e)
private void Recommended_Refresh(object sender, RoutedEventArgs e)
{ {
recGrid.Clear(); switch(pivot.SelectedIndex)
{
LoadRecommendations(); case 0:
recGrid.Clear();
LoadRecommendations();
break;
case 1:
trendsRequest = null;
trendGrid.Clear();
LoadTrending();
break;
case 2:
subsGrid.Clear();
LoadSubscriptions();
break;
}
} }
private void Trends_Refresh(object sender, RoutedEventArgs e)
{
trendsRequest = null;
trendGrid.Clear();
LoadTrending();
}
private void Subscriptions_Refresh(object sender, RoutedEventArgs e)
{
subsGrid.Clear();
LoadSubscriptions();
}
#endregion
} }
} }
+8 -8
View File
@@ -4,16 +4,16 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:Windows10version1809="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractPresent(Windows.Foundation.UniversalApiContract, 7)" mc:Ignorable="d"
mc:Ignorable="d"> Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <Grid>
<ProgressRing Name="ring" IsActive="True" Foreground="Red" Width="100" Height="100"/> <ProgressRing Name="ring" IsActive="True" Foreground="Red" Width="100" Height="100"/>
<StackPanel Name="wifiTrouble" Visibility="Collapsed" VerticalAlignment="Center"> <StackPanel Name="wifiTrouble" Visibility="Collapsed" VerticalAlignment="Center">
<FontIcon FontFamily="Segoe MDL2 Assets" Glyph="&#xEB5E;" FontSize="100" HorizontalAlignment="Center"/> <FontIcon FontFamily="Segoe MDL2 Assets" Glyph="&#xEB5E;" FontSize="100"/>
<TextBlock x:Uid="/LoadingPage/checkConnection" Text="Check your internet connection" TextWrapping="WrapWholeWords" FontSize="48" HorizontalAlignment="Center" HorizontalTextAlignment="Center"/> <TextBlock x:Uid="/LoadingPage/checkConnection" Text="Check your internet connection" TextWrapping="WrapWholeWords" FontSize="48" HorizontalAlignment="Center"/>
<TextBlock x:Uid="/LoadingPage/wifiDesc" Text="Please, make sure you are connected to the internet and try again." HorizontalAlignment="Center" TextWrapping="WrapWholeWords" HorizontalTextAlignment="Center"/> <TextBlock x:Uid="/LoadingPage/wifiDesc" Text="Please, make sure you are connected to the internet and try again." TextWrapping="WrapWholeWords" HorizontalAlignment="Center"/>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center"> <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Button x:Uid="/LoadingPage/openWifi" Content="Open network settings" Margin="5" Name="openWifi" Click="openWifi_Click"/> <Button x:Uid="/LoadingPage/openWifi" Content="Open network settings" Margin="5" Name="openWifi" Click="openWifi_Click"/>
<Button x:Uid="/LoadingPage/openTroubleshooter" Content="Open troubleshooter" Background="Red" Foreground="White" Margin="5" Name="openTroubleshoot" Click="openTroubleshoot_Click"/> <Button x:Uid="/LoadingPage/openTroubleshooter" Content="Open troubleshooter" Background="Red" Foreground="White" Margin="5" Name="openTroubleshoot" Click="openTroubleshoot_Click"/>
@@ -26,8 +26,8 @@
<StackPanel Name="trouble" Visibility="Collapsed" VerticalAlignment="Center"> <StackPanel Name="trouble" Visibility="Collapsed" VerticalAlignment="Center">
<FontIcon FontFamily="Segoe MDL2 Assets" Glyph="&#xE7BA;" FontSize="100" HorizontalAlignment="Center"/> <FontIcon FontFamily="Segoe MDL2 Assets" Glyph="&#xE7BA;" FontSize="100" HorizontalAlignment="Center"/>
<TextBlock x:Uid="/LoadingPage/err" Text="We are unable to display the page" FontSize="48" HorizontalAlignment="Center" TextWrapping="WrapWholeWords" HorizontalTextAlignment="Center"/> <TextBlock x:Uid="/LoadingPage/err" Text="We are unable to display the page" FontSize="48" HorizontalAlignment="Center" TextWrapping="WrapWholeWords"/>
<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"/> <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" TextWrapping="WrapWholeWords"/>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center"> <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Button x:Uid="/LoadingPage/refresh" Name="refresh" Click="wifiRefresh_Click" Content="Refresh page" Margin="5"/> <Button x:Uid="/LoadingPage/refresh" Name="refresh" Click="wifiRefresh_Click" Content="Refresh page" Margin="5"/>
<Button x:Uid="/LoadingPage/feedback" Content="Leave feedback" Background="Red" Foreground="White" Margin="5" Name="feedback" Click="feedback_Click"/> <Button x:Uid="/LoadingPage/feedback" Content="Leave feedback" Background="Red" Foreground="White" Margin="5" Name="feedback" Click="feedback_Click"/>
+11 -38
View File
@@ -5,7 +5,8 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" mc:Ignorable="d"
xmlns:ui="using:Microsoft.UI.Xaml.Controls"> xmlns:ui="using:Microsoft.UI.Xaml.Controls"
xmlns:controls="using:FoxTube.Controls">
<Grid Name="grid" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <Grid Name="grid" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<VisualStateManager.VisualStateGroups> <VisualStateManager.VisualStateGroups>
@@ -34,8 +35,7 @@
Style="{StaticResource CaptionTextBlockStyle}" /> Style="{StaticResource CaptionTextBlockStyle}" />
</Border> </Border>
<ui:NavigationView FontSize="14" SelectedItem="toHome" BackRequested="Nav_BackRequested" PaneClosing="Nav_PaneClosing" PaneOpened="Nav_PaneOpened" OpenPaneLength="300" Name="nav" SelectionChanged="Nav_SelectionChanged"> <ui:NavigationView SelectedItem="toHome" BackRequested="Nav_BackRequested" PaneClosing="Nav_PaneClosing" PaneOpened="Nav_PaneOpened" OpenPaneLength="300" Name="nav" SelectionChanged="Nav_SelectionChanged">
<ui:NavigationView.Header> <ui:NavigationView.Header>
<Grid> <Grid>
<TextBlock Name="Title" Style="{StaticResource TitleTextBlockStyle}"/> <TextBlock Name="Title" Style="{StaticResource TitleTextBlockStyle}"/>
@@ -66,23 +66,6 @@
</Ellipse> </Ellipse>
</Button> </Button>
</StackPanel> </StackPanel>
<CommandBar HorizontalAlignment="Right" Background="Transparent" OverflowButtonVisibility="Collapsed" Visibility="Collapsed" Margin="100,0">
<AppBarButton Label="Leave feedback">
<AppBarButton.Icon>
<FontIcon Glyph="&#xED15;"/>
</AppBarButton.Icon>
</AppBarButton>
<AppBarButton Label="Add account">
<AppBarButton.Icon>
<FontIcon Glyph="&#xE8FA;"/>
</AppBarButton.Icon>
</AppBarButton>
<AppBarButton>
<AppBarButton.Content>
<PersonPicture/>
</AppBarButton.Content>
</AppBarButton>
</CommandBar>
</Grid> </Grid>
</ui:NavigationView.Header> </ui:NavigationView.Header>
@@ -116,30 +99,20 @@
</ui:NavigationView.MenuItems> </ui:NavigationView.MenuItems>
<ui:NavigationView.PaneFooter> <ui:NavigationView.PaneFooter>
<ui:NavigationViewList> <ui:NavigationViewItem Content="Remove ads" Visibility="Collapsed" Tapped="RemoveAds_Tapped" Name="removeAds">
<ui:NavigationViewList.ItemContainerTransitions> <ui:NavigationViewItem.Icon>
<TransitionCollection> <FontIcon Glyph="&#xE14D;"/>
<EntranceThemeTransition IsStaggeringEnabled="True"/> </ui:NavigationViewItem.Icon>
<ReorderThemeTransition/> </ui:NavigationViewItem>
</TransitionCollection>
</ui:NavigationViewList.ItemContainerTransitions>
<ui:NavigationViewItem Name="openWeb" Tapped="Web_Tapped" Icon="Globe" Content="Browser" Visibility="Collapsed"/>
<ui:NavigationViewItem Content="Remove ads" Visibility="Collapsed" Tapped="RemoveAds_Tapped" Name="removeAds">
<ui:NavigationViewItem.Icon>
<FontIcon Glyph="&#xE14D;"/>
</ui:NavigationViewItem.Icon>
</ui:NavigationViewItem>
</ui:NavigationViewList>
</ui:NavigationView.PaneFooter> </ui:NavigationView.PaneFooter>
<ui:NavigationView.AutoSuggestBox> <ui:NavigationView.AutoSuggestBox>
<AutoSuggestBox FontSize="14" x:Name="search" QueryIcon="Find" QuerySubmitted="Search_QuerySubmitted" TextChanged="Search_TextChanged" x:Uid="/Main/searchPlaceholder" PlaceholderText="Search"/> <AutoSuggestBox x:Name="search" QueryIcon="Find" QuerySubmitted="Search_QuerySubmitted" TextChanged="Search_TextChanged" x:Uid="/Main/searchPlaceholder" PlaceholderText="Search"/>
</ui:NavigationView.AutoSuggestBox> </ui:NavigationView.AutoSuggestBox>
<Grid> <Grid>
<Frame Name="content" Navigated="Content_Navigated"/> <controls:ContentFrame x:Name="content" Navigated="Content_Navigated"/>
<Frame Name="videoPlaceholder"/> <controls:ContentFrame x:Name="videoPlaceholder"/>
</Grid> </Grid>
</ui:NavigationView> </ui:NavigationView>
+141 -200
View File
@@ -6,7 +6,6 @@ using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Navigation; using Windows.UI.Xaml.Navigation;
using System.Diagnostics;
using Windows.UI.Xaml.Media.Imaging; using Windows.UI.Xaml.Media.Imaging;
using System.Xml; using System.Xml;
using Google.Apis.YouTube.v3.Data; using Google.Apis.YouTube.v3.Data;
@@ -14,11 +13,11 @@ using Windows.ApplicationModel.Core;
using Windows.System; using Windows.System;
using FoxTube.Pages; using FoxTube.Pages;
using Windows.UI.Popups; using Windows.UI.Popups;
using Windows.Networking.Connectivity;
using Windows.ApplicationModel.Resources; using Windows.ApplicationModel.Resources;
using Microsoft.Services.Store.Engagement; using Microsoft.Services.Store.Engagement;
using Windows.UI.Xaml.Shapes; using Windows.UI.Xaml.Shapes;
using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Media;
using FoxTube.Controls;
namespace FoxTube namespace FoxTube
{ {
@@ -28,38 +27,14 @@ namespace FoxTube
public sealed partial class MainPage : Page public sealed partial class MainPage : Page
{ {
bool wasInvoked = false; bool wasInvoked = false;
public static event ObjectEventHandler VideoPageSizeChanged;
readonly ResourceLoader resources = ResourceLoader.GetForCurrentView("Main"); readonly ResourceLoader resources = ResourceLoader.GetForCurrentView("Main");
Dictionary<Type, string> headers; Dictionary<Type, string> headers;
public Page PageContent => content.Content as Page; public ContentFrame PageContent => content;
public ContentFrame VideoContent => videoPlaceholder;
public MainPage() public MainPage()
{ {
InitializeComponent();
Window.Current.SetTitleBar(AppTitleBar);
CoreApplication.GetCurrentView().TitleBar.ExtendViewIntoTitleBar = true;
CoreApplication.GetCurrentView().TitleBar.LayoutMetricsChanged += (s, e) => SetTitleBar(s);
SecretsVault.AuthorizationStateChanged += AuthorizationStateChanged;
SecretsVault.SubscriptionsChanged += SecretsVault_SubscriptionsChanged;
SecretsVault.Purchased += async (sender, e) =>
{
removeAds.Visibility = (e[0] as bool?).Value ? Visibility.Collapsed : Visibility.Visible;
removeAds.Content = $"{resources.GetString("/Main/adsFree/Content")} ({e[1]})";
if (!(bool)e[0])
return;
MessageDialog dialog = new MessageDialog(resources.GetString("/Main/purchaseSuccess"));
dialog.Commands.Add(new UICommand(resources.GetString("/Main/close"), (command) => Methods.CloseApp()));
dialog.Commands.Add(new UICommand(resources.GetString("/Main/delay")));
dialog.CancelCommandIndex = 1;
dialog.DefaultCommandIndex = 0;
await dialog.ShowAsync();
};
SecretsVault.Initialize();
headers = new Dictionary<Type, string>() headers = new Dictionary<Type, string>()
{ {
{ typeof(Settings), resources.GetString("/Main/settings/Content") }, { typeof(Settings), resources.GetString("/Main/settings/Content") },
@@ -72,6 +47,33 @@ namespace FoxTube
{ typeof(Downloads), resources.GetString("/Main/downloads/Content") } { typeof(Downloads), resources.GetString("/Main/downloads/Content") }
}; };
InitializeComponent();
Window.Current.SetTitleBar(AppTitleBar);
CoreApplication.GetCurrentView().TitleBar.ExtendViewIntoTitleBar = true;
CoreApplication.GetCurrentView().TitleBar.LayoutMetricsChanged += (s, e) => SetTitleBar(s);
SecretsVault.AuthorizationStateChanged += AuthorizationStateChanged;
SecretsVault.SubscriptionsChanged += SecretsVault_SubscriptionsChanged;
SecretsVault.Purchased += async (sender, e) =>
{
removeAds.Visibility = (e[0] as bool?).Value ? Visibility.Collapsed : Visibility.Visible;
if (!(bool)e[0])
{
removeAds.Content = $"{resources.GetString("/Main/adsFree/Content")} ({e[1]})";
return;
}
MessageDialog dialog = new MessageDialog(resources.GetString("/Main/purchaseSuccess"));
dialog.Commands.Add(new UICommand(resources.GetString("/Main/close"), (command) => Methods.CloseApp()));
dialog.Commands.Add(new UICommand(resources.GetString("/Main/delay")));
dialog.CancelCommandIndex = 1;
dialog.DefaultCommandIndex = 0;
await dialog.ShowAsync();
};
SecretsVault.Initialize();
if(StoreServicesFeedbackLauncher.IsSupported()) if(StoreServicesFeedbackLauncher.IsSupported())
feedback.Visibility = Visibility.Visible; feedback.Visibility = Visibility.Visible;
@@ -121,16 +123,15 @@ namespace FoxTube
} }
} }
public string GetPlaylist()
{
try { return (videoPlaceholder.Content as VideoPage).playlistId; }
catch { return null; }
}
public void SetTitleBar(CoreApplicationViewTitleBar coreTitleBar = null) public void SetTitleBar(CoreApplicationViewTitleBar coreTitleBar = null)
{ {
if (coreTitleBar != null) if (coreTitleBar != null)
{
bool full = ApplicationView.GetForCurrentView().IsFullScreenMode;
double left = 12 + (full ? 0 : coreTitleBar.SystemOverlayLeftInset);
AppTitle.Margin = new Thickness(left, 8, 0, 0);
AppTitleBar.Height = coreTitleBar.Height; AppTitleBar.Height = coreTitleBar.Height;
}
var titleBar = ApplicationView.GetForCurrentView().TitleBar; var titleBar = ApplicationView.GetForCurrentView().TitleBar;
@@ -148,7 +149,7 @@ namespace FoxTube
private void SecretsVault_SubscriptionsChanged(object sender, params object[] args) private void SecretsVault_SubscriptionsChanged(object sender, params object[] args)
{ {
switch(args[0] as string) switch((string)args[0])
{ {
case "add": case "add":
if (nav.MenuItems.Count < 19) if (nav.MenuItems.Count < 19)
@@ -156,21 +157,21 @@ namespace FoxTube
break; break;
case "remove": case "remove":
Microsoft.UI.Xaml.Controls.NavigationViewItem item = nav.MenuItems.Find(i => ((i as Microsoft.UI.Xaml.Controls.NavigationViewItem).Content as StackPanel).Tag.ToString() == (args[1] as Subscription).Snippet.ResourceId.ChannelId) as Microsoft.UI.Xaml.Controls.NavigationViewItem; if (nav.MenuItems.Find(i => ((i as Microsoft.UI.Xaml.Controls.NavigationViewItem).Content as StackPanel).Tag.ToString() == (string)args[1]) is Microsoft.UI.Xaml.Controls.NavigationViewItem item)
if (item == null) {
break;
else
nav.MenuItems.Remove(item); nav.MenuItems.Remove(item);
if (SecretsVault.Subscriptions.Count >= 10)
if (SecretsVault.Subscriptions.Count >= 10) nav.MenuItems.Add(SecretsVault.Subscriptions[9]);
nav.MenuItems.Add(SecretsVault.Subscriptions[9]); }
break; break;
} }
} }
private async void AuthorizationStateChanged(object sender, params object[] e) private async void AuthorizationStateChanged(object sender, params object[] e)
{ {
switch(e[0] as bool?) wasInvoked = false;
switch (e[0] as bool?)
{ {
case true: case true:
account.Visibility = Visibility.Collapsed; account.Visibility = Visibility.Collapsed;
@@ -183,8 +184,7 @@ namespace FoxTube
avatar.Visibility = Visibility.Visible; avatar.Visibility = Visibility.Visible;
if(SecretsVault.UserChannel != null) toChannel.Visibility = Visibility.Visible;
toChannel.Visibility = Visibility.Visible;
toSubscriptions.Visibility = Visibility.Visible; toSubscriptions.Visibility = Visibility.Visible;
libHeader.Visibility = Visibility.Visible; libHeader.Visibility = Visibility.Visible;
toHistory.Visibility = Visibility.Visible; toHistory.Visibility = Visibility.Visible;
@@ -198,9 +198,16 @@ namespace FoxTube
nav.MenuItems.Add(SecretsVault.Subscriptions[k]); nav.MenuItems.Add(SecretsVault.Subscriptions[k]);
} }
HistorySet.Load(); HistorySet.Load();
if (content.Frame.Content != null)
content.Refresh();
else
content.Frame.Navigate(typeof(Home));
break; break;
case false: case false:
content.Frame.Navigate(typeof(Home));
for (int k = nav.MenuItems.Count - 1; k > 8; k--) for (int k = nav.MenuItems.Count - 1; k > 8; k--)
nav.MenuItems.RemoveAt(k); nav.MenuItems.RemoveAt(k);
@@ -216,6 +223,9 @@ namespace FoxTube
subsHeader.Visibility = Visibility.Collapsed; subsHeader.Visibility = Visibility.Collapsed;
subsHeader.Visibility = Visibility.Collapsed; subsHeader.Visibility = Visibility.Collapsed;
content.Frame.BackStack.Clear();
content.Frame.ForwardStack.Clear();
break; break;
default: default:
@@ -237,17 +247,13 @@ namespace FoxTube
break; break;
} }
await Dispatcher.RunIdleAsync((command) => DownloadAgent.Initialize()); if (videoPlaceholder.Frame.Content != null)
{
MaximizeVideo();
videoPlaceholder.Refresh();
}
wasInvoked = false; DownloadAgent.Initialize();
if (content.Content != null)
content.Navigate(content.CurrentSourcePageType, (content.Content as NavigationPage).Parameter);
else
content.Navigate(typeof(Home));
if (videoPlaceholder.Content != null)
GoToVideo((videoPlaceholder.Content as VideoPage).videoId, (videoPlaceholder.Content as VideoPage).playlistId);
} }
private async void Feedback_Click(object sender, RoutedEventArgs e) private async void Feedback_Click(object sender, RoutedEventArgs e)
@@ -262,120 +268,69 @@ namespace FoxTube
private void Logout_Click(object sender, RoutedEventArgs e) private void Logout_Click(object sender, RoutedEventArgs e)
{ {
avatar.Flyout.Hide();
SecretsVault.Deauthenticate(); SecretsVault.Deauthenticate();
} }
public void GoToSearch(SearchParameters args) public void GoToSearch(SearchParameters args)
{ {
nav.IsPaneOpen = false; content.Frame.Navigate(typeof(Search), new object[] { args, content });
content.Navigate(typeof(Search), args);
} }
public void GoToChannel(string id) public void GoToChannel(string id)
{ {
content.Navigate(typeof(ChannelPage), id); content.Frame.Navigate(typeof(ChannelPage), id);
} }
public void GoToHome() public void GoToHome()
{ {
content.Navigate(typeof(Home)); content.Frame.Navigate(typeof(Home));
} }
public async void GoToVideo(string id, string playlistId = null, bool incognito = false) public void GoToVideo(string id, string playlistId = null, bool incognito = false)
{ {
if (SettingsStorage.CheckConnection) MaximizeVideo();
try
{
bool cancel = false;
ConnectionCost connection = NetworkInformation.GetInternetConnectionProfile().GetConnectionCost();
if (connection.NetworkCostType == NetworkCostType.Fixed || connection.NetworkCostType == NetworkCostType.Variable)
{
MessageDialog dialog = new MessageDialog(resources.GetString("/Main/metered"))
{
DefaultCommandIndex = 2,
CancelCommandIndex = 1
};
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(resources.GetString("/Main/addLater"), (command) =>
{
try
{
PlaylistItem item = new PlaylistItem()
{
Snippet = new PlaylistItemSnippet()
{
ResourceId = new ResourceId()
{
Kind = "youtube#video",
VideoId = id
},
PlaylistId = "WL"
}
};
SecretsVault.Service.PlaylistItems.Insert(item, "snippet").Execute();
}
catch (Exception e)
{
Debug.WriteLine(e.Message);
}
cancel = true;
}));
await dialog.ShowAsync();
if (cancel)
return;
}
}
catch { }
if (videoPlaceholder.Content != null)
(videoPlaceholder.Content as VideoPage).CloseVideo();
nav.IsBackEnabled = true; nav.IsBackEnabled = true;
nav.ExpandedModeThresholdWidth = short.MaxValue; nav.ExpandedModeThresholdWidth = short.MaxValue;
nav.IsPaneOpen = false; nav.IsPaneOpen = false;
VideoPageSizeChanged?.Invoke(this, true); videoPlaceholder.Frame.Navigate(typeof(VideoPage), new object[3] { id, playlistId, incognito });
videoPlaceholder.Navigate(typeof(VideoPage), new object[3] { id, playlistId, incognito });
Title.Text = resources.GetString("/Main/video"); Title.Text = resources.GetString("/Main/video");
} }
public void GoToDeveloper(string id) public void GoToDeveloper(string id)
{ {
content.Navigate(typeof(Settings), id); content.Frame.Navigate(typeof(Settings), id);
} }
public void GoToPlaylist(string id) public void GoToPlaylist(string id)
{ {
content.Navigate(typeof(PlaylistPage), id); content.Frame.Navigate(typeof(PlaylistPage), id);
} }
public void GoToHistory() public void GoToHistory()
{ {
content.Navigate(typeof(History)); content.Frame.Navigate(typeof(History));
} }
public void GoToDownloads() public void GoToDownloads()
{ {
content.Navigate(typeof(Downloads)); content.Frame.Navigate(typeof(Downloads));
} }
public void MinimizeAsInitializer() public void MinimizeAsInitializer()
{ {
if (videoPlaceholder.Content == null) if (videoPlaceholder.Frame.Content == null)
return; return;
if ((videoPlaceholder.Content as VideoPage).LoadingPage.State != LoadingState.Loaded) if (videoPlaceholder.LoadingPage.State != LoadingState.Loaded)
CloseVideo(); CloseVideo();
else else
(videoPlaceholder.Content as VideoPage).Player.Minimize(); (videoPlaceholder.Frame.Content as VideoPage).Player.Minimize();
Title.Text = headers[content.SourcePageType]; Title.Text = headers[content.Frame.SourcePageType];
} }
public void MinimizeVideo() public void MinimizeVideo()
@@ -386,27 +341,28 @@ namespace FoxTube
videoPlaceholder.HorizontalAlignment = HorizontalAlignment.Right; videoPlaceholder.HorizontalAlignment = HorizontalAlignment.Right;
videoPlaceholder.Margin = new Thickness(0, 0, 25, 50); videoPlaceholder.Margin = new Thickness(0, 0, 25, 50);
if (content.CanGoBack) if (content.Frame.CanGoBack)
nav.IsBackEnabled = true; nav.IsBackEnabled = true;
else else
nav.IsBackEnabled = false; nav.IsBackEnabled = false;
VideoPageSizeChanged?.Invoke(this, false);
SetNavigationMenu(); SetNavigationMenu();
Title.Text = headers[content.SourcePageType]; Title.Text = headers[content.Frame.SourcePageType];
} }
void SetNavigationMenu() void SetNavigationMenu()
{ {
if (content.SourcePageType == typeof(Home) || content.SourcePageType == typeof(Settings) || content.SourcePageType == typeof(Subscriptions)) if (content.Frame.SourcePageType == typeof(Home) || content.Frame.SourcePageType == typeof(Settings) || content.Frame.SourcePageType == typeof(Subscriptions))
{ {
nav.ExpandedModeThresholdWidth = 1008; nav.ExpandedModeThresholdWidth = 1008;
nav.IsPaneOpen = nav.DisplayMode == Microsoft.UI.Xaml.Controls.NavigationViewDisplayMode.Expanded ? true : false; nav.IsPaneOpen = nav.DisplayMode == Microsoft.UI.Xaml.Controls.NavigationViewDisplayMode.Expanded ? true : false;
} }
else else
{
nav.ExpandedModeThresholdWidth = short.MaxValue; nav.ExpandedModeThresholdWidth = short.MaxValue;
nav.IsPaneOpen = false;
}
} }
public void MaximizeVideo() public void MaximizeVideo()
@@ -417,15 +373,13 @@ namespace FoxTube
videoPlaceholder.HorizontalAlignment = HorizontalAlignment.Stretch; videoPlaceholder.HorizontalAlignment = HorizontalAlignment.Stretch;
videoPlaceholder.Margin = new Thickness(0); videoPlaceholder.Margin = new Thickness(0);
if (videoPlaceholder.Content == null) if (videoPlaceholder.Frame.Content == null)
return; return;
nav.IsBackEnabled = true; nav.IsBackEnabled = true;
Title.Text = resources.GetString("/Main/video"); Title.Text = resources.GetString("/Main/video");
nav.ExpandedModeThresholdWidth = short.MaxValue; nav.ExpandedModeThresholdWidth = short.MaxValue;
nav.IsPaneOpen = false; nav.IsPaneOpen = false;
VideoPageSizeChanged?.Invoke(this, true);
} }
public void CloseVideo() public void CloseVideo()
@@ -433,20 +387,15 @@ namespace FoxTube
if (ApplicationView.GetForCurrentView().IsFullScreenMode) if (ApplicationView.GetForCurrentView().IsFullScreenMode)
ApplicationView.GetForCurrentView().ExitFullScreenMode(); ApplicationView.GetForCurrentView().ExitFullScreenMode();
videoPlaceholder.Content = null; videoPlaceholder.Frame.Content = null;
GC.Collect(); GC.Collect();
MaximizeVideo(); MaximizeVideo();
if (content.CanGoBack) nav.IsBackEnabled = content.Frame.CanGoBack;
nav.IsBackEnabled = true;
else
nav.IsBackEnabled = false;
VideoPageSizeChanged?.Invoke(this, false);
SetNavigationMenu(); SetNavigationMenu();
Title.Text = headers[content.SourcePageType]; Title.Text = headers[content.Frame.SourcePageType];
} }
private void Search_QuerySubmitted(AutoSuggestBox sender, AutoSuggestBoxQuerySubmittedEventArgs args) private void Search_QuerySubmitted(AutoSuggestBox sender, AutoSuggestBoxQuerySubmittedEventArgs args)
@@ -464,7 +413,7 @@ namespace FoxTube
try try
{ {
XmlDocument doc = new XmlDocument(); XmlDocument doc = new XmlDocument();
doc.Load($"http://suggestqueries.google.com/complete/search?ds=yt&client=toolbar&q={search.Text}"); doc.Load($"http://suggestqueries.google.com/complete/search?ds=yt&client=toolbar&q={search.Text}&hl={SettingsStorage.RelevanceLanguage}");
List<string> suggestions = new List<string>(); List<string> suggestions = new List<string>();
@@ -492,7 +441,7 @@ namespace FoxTube
public void Content_Navigated(object sender, NavigationEventArgs e) public void Content_Navigated(object sender, NavigationEventArgs e)
{ {
Title.Text = headers[content.SourcePageType]; Title.Text = headers[content.Frame.SourcePageType];
if (!wasInvoked) if (!wasInvoked)
{ {
@@ -508,12 +457,17 @@ namespace FoxTube
SetNavigationItem(toHome); SetNavigationItem(toHome);
else if (e.SourcePageType == typeof(Search)) else if (e.SourcePageType == typeof(Search))
SetNavigationItem(null); SetNavigationItem(null);
else if(e.SourcePageType == typeof(ChannelPage) && SecretsVault.IsAuthorized) else if(e.SourcePageType == typeof(ChannelPage))
{ {
if (e.Parameter.ToString() == SecretsVault.AccountId) if (SecretsVault.IsAuthorized)
SetNavigationItem(toChannel); {
else if (nav.MenuItems.Contains(SecretsVault.Subscriptions.Find(i => i.Snippet.ResourceId.ChannelId == e.Parameter.ToString()))) if (e.Parameter.ToString() == SecretsVault.AccountId)
SetNavigationItem(SecretsVault.Subscriptions.Find(i => i.Snippet.ResourceId.ChannelId == e.Parameter.ToString())); SetNavigationItem(toChannel);
else if (nav.MenuItems.Contains(SecretsVault.Subscriptions.Find(i => i.Snippet.ResourceId.ChannelId == e.Parameter.ToString())))
SetNavigationItem(SecretsVault.Subscriptions.Find(i => i.Snippet.ResourceId.ChannelId == e.Parameter.ToString()));
else
SetNavigationItem(null);
}
else else
SetNavigationItem(null); SetNavigationItem(null);
} }
@@ -521,87 +475,79 @@ namespace FoxTube
SetNavigationItem(toHistory); SetNavigationItem(toHistory);
else if(e.SourcePageType == typeof(PlaylistPage)) else if(e.SourcePageType == typeof(PlaylistPage))
{ {
if (e.Parameter.ToString() == SecretsVault.UserChannel.ContentDetails.RelatedPlaylists.Likes) if (SecretsVault.IsAuthorized)
SetNavigationItem(toLiked); {
else if (e.Parameter.Equals("WL")) if (e.Parameter.ToString() == SecretsVault.UserChannel.ContentDetails.RelatedPlaylists.Likes)
SetNavigationItem(toLater); SetNavigationItem(toLiked);
else if (e.Parameter.Equals("WL"))
SetNavigationItem(toLater);
}
else
SetNavigationItem(null);
} }
} }
else else
wasInvoked = false; wasInvoked = false;
if (content.CanGoBack) nav.IsBackEnabled = content.Frame.CanGoBack;
nav.IsBackEnabled = true;
else
nav.IsBackEnabled = false;
SetNavigationMenu(); SetNavigationMenu();
if (videoPlaceholder.Content != null && videoPlaceholder.HorizontalAlignment == HorizontalAlignment.Stretch) if (videoPlaceholder.Frame.Content != null && videoPlaceholder.HorizontalAlignment == HorizontalAlignment.Stretch)
MinimizeAsInitializer(); MinimizeAsInitializer();
} }
private void OpenContext(object sender, TappedRoutedEventArgs e)
{
((Microsoft.UI.Xaml.Controls.NavigationViewItem)sender).ContextFlyout.ShowAt((Microsoft.UI.Xaml.Controls.NavigationViewItem)sender);
}
private void RemoveAds_Tapped(object sender, TappedRoutedEventArgs e) private void RemoveAds_Tapped(object sender, TappedRoutedEventArgs e)
{ {
SecretsVault.GetAdblock(); SecretsVault.GetAdblock();
} }
private void Web_Tapped(object sender, TappedRoutedEventArgs e)
{
content.Navigate(typeof(Home1));
}
private void Nav_SelectionChanged(Microsoft.UI.Xaml.Controls.NavigationView sender, Microsoft.UI.Xaml.Controls.NavigationViewSelectionChangedEventArgs args) private void Nav_SelectionChanged(Microsoft.UI.Xaml.Controls.NavigationView sender, Microsoft.UI.Xaml.Controls.NavigationViewSelectionChangedEventArgs args)
{ {
try if (!wasInvoked)
{ {
if (!wasInvoked) if (content == null)
{ return;
wasInvoked = true; wasInvoked = true;
if (args.IsSettingsSelected) if (args.IsSettingsSelected)
content.Navigate(typeof(Settings)); content.Frame.Navigate(typeof(Settings));
else
{
if (args.SelectedItem == toHome)
content.Navigate(typeof(Home));
else if (args.SelectedItem == toHistory)
content.Navigate(typeof(History));
else if (args.SelectedItem == toLiked)
content.Navigate(typeof(PlaylistPage), SecretsVault.UserChannel.ContentDetails.RelatedPlaylists.Likes);
else if (args.SelectedItem == toLater)
content.Navigate(typeof(PlaylistPage), "WL");
else if (args.SelectedItem == toSubscriptions)
content.Navigate(typeof(Subscriptions));
else if (args.SelectedItem == toDownloads)
content.Navigate(typeof(Downloads));
else if (args.SelectedItem == toChannel)
content.Navigate(typeof(ChannelPage), SecretsVault.UserChannel.Id);
else
content.Navigate(typeof(ChannelPage), (args.SelectedItem as Subscription).Snippet.ResourceId.ChannelId);
}
}
else else
wasInvoked = false; {
if (args.SelectedItem == toHome)
content.Frame.Navigate(typeof(Home));
else if (args.SelectedItem == toHistory)
content.Frame.Navigate(typeof(History));
else if (args.SelectedItem == toLiked)
content.Frame.Navigate(typeof(PlaylistPage), SecretsVault.UserChannel.ContentDetails.RelatedPlaylists.Likes);
else if (args.SelectedItem == toLater)
content.Frame.Navigate(typeof(PlaylistPage), "WL");
else if (args.SelectedItem == toSubscriptions)
content.Frame.Navigate(typeof(Subscriptions));
else if (args.SelectedItem == toDownloads)
content.Frame.Navigate(typeof(Downloads));
else if (args.SelectedItem == toChannel)
content.Frame.Navigate(typeof(ChannelPage), SecretsVault.UserChannel.Id);
else
content.Frame.Navigate(typeof(ChannelPage), (args.SelectedItem as Subscription).Snippet.ResourceId.ChannelId);
}
} }
catch { } else
wasInvoked = false;
} }
private void Nav_BackRequested(Microsoft.UI.Xaml.Controls.NavigationView sender, Microsoft.UI.Xaml.Controls.NavigationViewBackRequestedEventArgs args) private void Nav_BackRequested(Microsoft.UI.Xaml.Controls.NavigationView sender, Microsoft.UI.Xaml.Controls.NavigationViewBackRequestedEventArgs args)
{ {
if (videoPlaceholder.Content != null && videoPlaceholder.Width == double.NaN) if (videoPlaceholder.Frame.Content != null && double.IsNaN(videoPlaceholder.Width))
{ {
if ((videoPlaceholder.Content as VideoPage).LoadingPage.State != LoadingState.Loaded) if (videoPlaceholder.Frame.CanGoBack)
videoPlaceholder.Frame.GoBack();
else if (videoPlaceholder.LoadingPage.State != LoadingState.Loaded)
CloseVideo(); CloseVideo();
else if (videoPlaceholder.HorizontalAlignment == HorizontalAlignment.Stretch) else
MinimizeAsInitializer(); MinimizeAsInitializer();
} }
else else
content.GoBack(); content.Frame.GoBack();
} }
private void Nav_PaneClosing(Microsoft.UI.Xaml.Controls.NavigationView sender, Microsoft.UI.Xaml.Controls.NavigationViewPaneClosingEventArgs args) private void Nav_PaneClosing(Microsoft.UI.Xaml.Controls.NavigationView sender, Microsoft.UI.Xaml.Controls.NavigationViewPaneClosingEventArgs args)
@@ -612,11 +558,6 @@ namespace FoxTube
private void Nav_PaneOpened(Microsoft.UI.Xaml.Controls.NavigationView sender, object args) private void Nav_PaneOpened(Microsoft.UI.Xaml.Controls.NavigationView sender, object args)
{ {
AppTitle.Visibility = Visibility.Visible; AppTitle.Visibility = Visibility.Visible;
if (sender.DisplayMode == Microsoft.UI.Xaml.Controls.NavigationViewDisplayMode.Expanded && sender.IsPaneOpen)
AppTitleBar.Margin = new Thickness(40, 0, 0, 0);
else
AppTitleBar.Margin = new Thickness();
} }
} }
} }
+4 -7
View File
@@ -5,7 +5,6 @@
xmlns:local="using:FoxTube.Pages" xmlns:local="using:FoxTube.Pages"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:foxtube="using:FoxTube"
xmlns:controls="using:FoxTube.Controls" xmlns:controls="using:FoxTube.Controls"
mc:Ignorable="d" mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
@@ -40,19 +39,19 @@
<RowDefinition Height="auto"/> <RowDefinition Height="auto"/>
<RowDefinition/> <RowDefinition/>
</Grid.RowDefinitions> </Grid.RowDefinitions>
<StackPanel Grid.Row="0" Margin="20" Grid.Column="1" x:Name="cover" HorizontalAlignment="Left"> <StackPanel Grid.Row="0" Margin="10" Grid.Column="1" x:Name="cover" HorizontalAlignment="Left">
<Image Source="/Assets/videoThumbSample.png" Name="thumbnail"/> <Image Source="/Assets/videoThumbSample.png" Name="thumbnail"/>
<TextBlock FontSize="20" Text="[Title]" TextWrapping="WrapWholeWords" Name="title"/> <TextBlock FontSize="20" Text="[Title]" TextWrapping="WrapWholeWords" Name="title"/>
<TextBlock Foreground="Gray" Text="# videos | # views | Updated at: ##-##-## ##:##:##" TextWrapping="WrapWholeWords" Name="info"/> <TextBlock Foreground="Gray" Text="# videos | # views | Updated at: ##-##-## ##:##:##" TextWrapping="WrapWholeWords" Name="info"/>
<TextBlock Foreground="Gray" Text="description" TextWrapping="WrapWholeWords" Name="description"/> <TextBlock Foreground="Gray" Text="description" TextWrapping="WrapWholeWords" Name="description"/>
<Button Margin="0,10,0,0" Background="Transparent" Name="toChannel" Click="toChannel_Click"> <Button Margin="10" Background="Transparent" Name="toChannel" Click="toChannel_Click">
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/>
<ColumnDefinition/> <ColumnDefinition/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<PersonPicture Height="50" Name="avatar"/> <PersonPicture Height="50" Name="avatar"/>
<TextBlock Grid.Column="1" Text="Channel name" FontSize="18" VerticalAlignment="Center" Margin="10,0,0,0" TextWrapping="WrapWholeWords" Name="channelName"/> <TextBlock Grid.Column="1" Text="Channel name" FontSize="18" VerticalAlignment="Center" Margin="10,0" TextWrapping="WrapWholeWords" Name="channelName"/>
</Grid> </Grid>
</Button> </Button>
</StackPanel> </StackPanel>
@@ -76,7 +75,7 @@
</StackPanel> </StackPanel>
</Grid> </Grid>
</ScrollViewer> </ScrollViewer>
<CommandBar Grid.Row="2"> <CommandBar Grid.Row="2">
<AppBarButton x:Uid="/Playlist/openWeb" Icon="Globe" Label="Open in browser" Name="inBrowser" Click="inBrowser_Click"/> <AppBarButton x:Uid="/Playlist/openWeb" Icon="Globe" Label="Open in browser" Name="inBrowser" Click="inBrowser_Click"/>
<AppBarButton x:Uid="/Playlist/addTo" Icon="Add" Label="Add to" IsEnabled="False" Visibility="Collapsed"> <AppBarButton x:Uid="/Playlist/addTo" Icon="Add" Label="Add to" IsEnabled="False" Visibility="Collapsed">
@@ -89,7 +88,5 @@
<AppBarButton x:Uid="/Playlist/refresh" Icon="Refresh" Label="Refresh" Name="refresh" Click="refresh_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"/> <AppBarButton x:Uid="/Playlist/share" Icon="Share" Label="Share" Name="share" Click="share_Click"/>
</CommandBar> </CommandBar>
<foxtube:LoadingPage Grid.RowSpan="2" Visibility="Collapsed" RefreshPage="refresh_Click" x:Name="loading"/>
</Grid> </Grid>
</Page> </Page>
+15 -29
View File
@@ -19,7 +19,7 @@ namespace FoxTube.Pages
/// <summary> /// <summary>
/// Playlist page /// Playlist page
/// </summary> /// </summary>
public sealed partial class PlaylistPage : Page, NavigationPage public sealed partial class PlaylistPage : Page, INavigationPage
{ {
public object Parameter { get; set; } = null; public object Parameter { get; set; } = null;
public string playlistId; public string playlistId;
@@ -32,17 +32,14 @@ namespace FoxTube.Pages
public PlaylistPage() public PlaylistPage()
{ {
InitializeComponent(); InitializeComponent();
DataTransferManager.GetForCurrentView().DataRequested += new TypedEventHandler<DataTransferManager, DataRequestedEventArgs>(Share);
} }
protected override void OnNavigatedTo(NavigationEventArgs e) protected override void OnNavigatedTo(NavigationEventArgs e)
{ {
base.OnNavigatedTo(e); base.OnNavigatedTo(e);
Parameter = e.Parameter; Parameter = e.Parameter;
if (e.Parameter == null)
loading.Error("NullReferenceException", "Unable to initialize page. Playlist ID is not stated."); if (e.Parameter as string == "WL")
else if (e.Parameter as string == "WL")
LoadWL(); LoadWL();
else else
Initialize(e.Parameter as string); Initialize(e.Parameter as string);
@@ -50,8 +47,6 @@ namespace FoxTube.Pages
public async void Initialize(string id) public async void Initialize(string id)
{ {
loading.Refresh();
try try
{ {
playlistId = id; playlistId = id;
@@ -66,16 +61,10 @@ namespace FoxTube.Pages
info.Text = $"{item.ContentDetails.ItemCount} {ResourceLoader.GetForCurrentView("Playlist").GetString("/Playlist/videos")}"; info.Text = $"{item.ContentDetails.ItemCount} {ResourceLoader.GetForCurrentView("Playlist").GetString("/Playlist/videos")}";
description.Text = item.Snippet.Localized.Description; description.Text = item.Snippet.Localized.Description;
channelName.Text = item.Snippet.ChannelTitle; channelName.Text = Methods.GuardFromNull(item.Snippet.ChannelTitle);
ChannelsResource.ListRequest channelRequest = SecretsVault.Service.Channels.List("snippet");
channelRequest.Id = item.Snippet.ChannelId;
Channel channel = (await channelRequest.ExecuteAsync()).Items[0];
try { avatar.ProfilePicture = new BitmapImage(channel.Snippet.Thumbnails.Medium.Url.ToUri()) { DecodePixelWidth = 50, DecodePixelHeight = 50 }; } avatar.ProfilePicture = new BitmapImage((await new YoutubeExplode.YoutubeClient().GetChannelAsync(item.Snippet.ChannelId)).LogoUrl.ToUri()) { DecodePixelWidth = 50, DecodePixelHeight = 50 };
catch { } thumbnail.Source = new BitmapImage(item.Snippet.Thumbnails.Medium.Url.ToUri());
try { thumbnail.Source = new BitmapImage(item.Snippet.Thumbnails.Medium.Url.ToUri()); }
catch { }
request = SecretsVault.Service.PlaylistItems.List("contentDetails"); request = SecretsVault.Service.PlaylistItems.List("contentDetails");
request.PlaylistId = id; request.PlaylistId = id;
@@ -89,15 +78,15 @@ namespace FoxTube.Pages
foreach (PlaylistItem i in response.Items) foreach (PlaylistItem i in response.Items)
list.Add(new VideoCard(i.ContentDetails.VideoId, playlistId)); list.Add(new VideoCard(i.ContentDetails.VideoId, playlistId));
loading.Close(); Methods.MainPage.PageContent.LoadingPage.Close();
} }
catch (System.Net.Http.HttpRequestException) catch (System.Net.Http.HttpRequestException)
{ {
loading.Error("System.Net.Http.HttpRequestException", "Unable to connect to Google servers.", true); Methods.MainPage.PageContent.LoadingPage.Error("System.Net.Http.HttpRequestException", "Unable to connect to Google servers.", true);
} }
catch (Exception e) catch (Exception e)
{ {
loading.Error(e.GetType().ToString(), e.Message); Methods.MainPage.PageContent.LoadingPage.Error(e.GetType().ToString(), e.Message);
Analytics.TrackEvent("Playlist loading error", new Dictionary<string, string>() Analytics.TrackEvent("Playlist loading error", new Dictionary<string, string>()
{ {
{ "Exception", e.GetType().ToString() }, { "Exception", e.GetType().ToString() },
@@ -109,8 +98,6 @@ namespace FoxTube.Pages
public async void LoadWL() public async void LoadWL()
{ {
loading.Refresh();
try try
{ {
playlistId = "WL"; playlistId = "WL";
@@ -125,10 +112,8 @@ namespace FoxTube.Pages
channelName.Text = SecretsVault.UserChannel.Snippet.Title; channelName.Text = SecretsVault.UserChannel.Snippet.Title;
try { avatar.ProfilePicture = new BitmapImage(SecretsVault.UserChannel.Snippet.Thumbnails.Medium.Url.ToUri()) { DecodePixelWidth = 50, DecodePixelHeight = 50 }; } avatar.ProfilePicture = new BitmapImage(SecretsVault.UserChannel.Snippet.Thumbnails.Medium.Url.ToUri()) { DecodePixelWidth = 50, DecodePixelHeight = 50 };
catch { } thumbnail.Source = new BitmapImage((await new YoutubeExplode.YoutubeClient().GetVideoAsync(SecretsVault.WatchLater.First())).Thumbnails.HighResUrl.ToUri());
try { thumbnail.Source = new BitmapImage((await new YoutubeExplode.YoutubeClient().GetVideoAsync(SecretsVault.WatchLater.First())).Thumbnails.HighResUrl.ToUri()); }
catch { }
for (int k = 0; k < 25 && k < SecretsVault.WatchLater.Count; k++) for (int k = 0; k < 25 && k < SecretsVault.WatchLater.Count; k++)
list.Add(new VideoCard(SecretsVault.WatchLater[k], "WL")); list.Add(new VideoCard(SecretsVault.WatchLater[k], "WL"));
@@ -136,11 +121,11 @@ namespace FoxTube.Pages
if (list.Count >= SecretsVault.WatchLater.Count) if (list.Count >= SecretsVault.WatchLater.Count)
more.Visibility = Visibility.Collapsed; more.Visibility = Visibility.Collapsed;
loading.Close(); Methods.MainPage.PageContent.LoadingPage.Close();
} }
catch (Exception e) catch (Exception e)
{ {
loading.Error(e.GetType().ToString(), e.Message); Methods.MainPage.PageContent.LoadingPage.Error(e.GetType().ToString(), e.Message);
Analytics.TrackEvent("WL playlist loading error", new Dictionary<string, string>() Analytics.TrackEvent("WL playlist loading error", new Dictionary<string, string>()
{ {
{ "Exception", e.GetType().ToString() }, { "Exception", e.GetType().ToString() },
@@ -161,11 +146,12 @@ namespace FoxTube.Pages
private void refresh_Click(object sender, RoutedEventArgs e) private void refresh_Click(object sender, RoutedEventArgs e)
{ {
Methods.MainPage.GoToPlaylist(playlistId); Methods.MainPage.VideoContent.Refresh();
} }
private void share_Click(object sender, RoutedEventArgs e) private void share_Click(object sender, RoutedEventArgs e)
{ {
DataTransferManager.GetForCurrentView().DataRequested += new TypedEventHandler<DataTransferManager, DataRequestedEventArgs>(Share);
DataTransferManager.ShowShareUI(); DataTransferManager.ShowShareUI();
} }
-2
View File
@@ -76,7 +76,5 @@
<AppBarButton Label="Open in browser" Icon="Globe" Name="inBrowser" Click="InBrowser_Click"/> <AppBarButton Label="Open in browser" Icon="Globe" Name="inBrowser" Click="InBrowser_Click"/>
<AppBarButton Label="Refresh" Icon="Refresh" Click="AppBarButton_Click"/> <AppBarButton Label="Refresh" Icon="Refresh" Click="AppBarButton_Click"/>
</CommandBar> </CommandBar>
<local:LoadingPage x:Name="loading" Grid.RowSpan="2" Visibility="Collapsed" RefreshPage="AppBarButton_Click"/>
</Grid> </Grid>
</Page> </Page>
+10 -16
View File
@@ -16,11 +16,12 @@ namespace FoxTube
/// <summary> /// <summary>
/// Search page /// Search page
/// </summary> /// </summary>
public sealed partial class Search : Page, NavigationPage public sealed partial class Search : Page, INavigationPage
{ {
public object Parameter { get; set; } = null; public object Parameter { get; set; } = null;
readonly ResourceLoader resources = ResourceLoader.GetForCurrentView("Search"); readonly ResourceLoader resources = ResourceLoader.GetForCurrentView("Search");
ContentFrame frame;
public SearchParameters Parameters; public SearchParameters Parameters;
SearchResource.ListRequest request; SearchResource.ListRequest request;
string nextToken; string nextToken;
@@ -65,21 +66,13 @@ namespace FoxTube
{ {
base.OnNavigatedTo(e); base.OnNavigatedTo(e);
Parameter = e.Parameter; Parameter = e.Parameter;
if (e.Parameter == null)
loading.Error("NullReferenceException", "Unable to initialize search. Search term is not stated."); frame = ((object[])e.Parameter)[1] as ContentFrame;
else Initialize(((object[])e.Parameter)[0] as SearchParameters);
{
if (e.Parameter is SearchParameters)
Initialize(e.Parameter as SearchParameters);
else
loading.Error("ArgumentException", "Wrong parameter");
}
} }
public async void Initialize(SearchParameters arg) public async void Initialize(SearchParameters arg)
{ {
loading.Refresh();
try try
{ {
Parameters = arg; Parameters = arg;
@@ -129,6 +122,7 @@ namespace FoxTube
SearchListResponse response = await request.ExecuteAsync(); SearchListResponse response = await request.ExecuteAsync();
searchTerm.Text = $"{resources.GetString("/Search/header")} '{Parameters.Term}'"; searchTerm.Text = $"{resources.GetString("/Search/header")} '{Parameters.Term}'";
resultsCount.Text = $"{resources.GetString("/Search/found")}: {SetResults(response.PageInfo.TotalResults)} {resources.GetString("/Search/items")}"; resultsCount.Text = $"{resources.GetString("/Search/found")}: {SetResults(response.PageInfo.TotalResults)} {resources.GetString("/Search/items")}";
if (!string.IsNullOrWhiteSpace(response.NextPageToken)) if (!string.IsNullOrWhiteSpace(response.NextPageToken))
nextToken = response.NextPageToken; nextToken = response.NextPageToken;
else else
@@ -138,15 +132,15 @@ namespace FoxTube
foreach (SearchResult item in response.Items) foreach (SearchResult item in response.Items)
AddItem(item); AddItem(item);
loading.Close(); frame.LoadingPage.Close();
} }
catch (System.Net.Http.HttpRequestException) catch (System.Net.Http.HttpRequestException)
{ {
loading.Error("System.Net.Http.HttpRequestException", "Unable to connect to Google servers.", true); frame.LoadingPage.Error("System.Net.Http.HttpRequestException", "Unable to connect to Google servers.", true);
} }
catch (Exception e) catch (Exception e)
{ {
loading.Error(e.GetType().ToString(), e.Message); frame.LoadingPage.Error(e.GetType().ToString(), e.Message);
Analytics.TrackEvent("Search loading error", new Dictionary<string, string>() Analytics.TrackEvent("Search loading error", new Dictionary<string, string>()
{ {
{ "Exception", e.GetType().ToString() }, { "Exception", e.GetType().ToString() },
@@ -172,7 +166,7 @@ namespace FoxTube
private void AppBarButton_Click(object sender, RoutedEventArgs e) private void AppBarButton_Click(object sender, RoutedEventArgs e)
{ {
Methods.MainPage.GoToSearch(Parameters); frame.Refresh();
} }
private async void More_Clicked() private async void More_Clicked()
+4 -4
View File
@@ -9,19 +9,19 @@
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Pivot SelectedIndex="0" Name="pivot" IsHeaderItemsCarouselEnabled="False" SelectionChanged="Pivot_SelectionChanged"> <Pivot SelectedIndex="0" Name="pivot" IsHeaderItemsCarouselEnabled="False" SelectionChanged="Pivot_SelectionChanged">
<PivotItem Header="General" x:Uid="/Settings/general"> <PivotItem Name="generalTab" Header="General" x:Uid="/Settings/general">
<ScrollViewer> <ScrollViewer>
<settingspages:General/> <settingspages:General/>
</ScrollViewer> </ScrollViewer>
</PivotItem> </PivotItem>
<PivotItem Header="About us" x:Uid="/Settings/about"> <PivotItem Name="aboutTab" Header="About us" x:Uid="/Settings/about">
<ScrollViewer> <ScrollViewer>
<settingspages:About/> <settingspages:About/>
</ScrollViewer> </ScrollViewer>
</PivotItem> </PivotItem>
<PivotItem Header="Inbox" x:Uid="/Settings/inbox"> <PivotItem Name="inboxTab" Header="Inbox" x:Uid="/Settings/inbox">
<ScrollViewer> <ScrollViewer>
<settingspages:Inbox/> <settingspages:Inbox x:Name="inbox"/>
</ScrollViewer> </ScrollViewer>
</PivotItem> </PivotItem>
</Pivot> </Pivot>
+19 -13
View File
@@ -7,9 +7,10 @@ namespace FoxTube
/// <summary> /// <summary>
/// Settings tabs placeholder /// Settings tabs placeholder
/// </summary> /// </summary>
public sealed partial class Settings : Page, NavigationPage public sealed partial class Settings : Page, INavigationPage
{ {
public object Parameter { get; set; } = null; public object Parameter { get; set; } = null;
bool inboxLoaded = false; bool inboxLoaded = false;
string inboxId = null; string inboxId = null;
public Settings() public Settings()
@@ -21,24 +22,29 @@ namespace FoxTube
{ {
base.OnNavigatedTo(e); base.OnNavigatedTo(e);
Parameter = e.Parameter; Parameter = e.Parameter;
if (!string.IsNullOrWhiteSpace(e.Parameter as string))
{ if(!string.IsNullOrWhiteSpace((string)e.Parameter))
inboxId = e.Parameter as string; switch((string)e.Parameter)
pivot.SelectedIndex = 2; {
} case "about":
pivot.SelectedItem = aboutTab;
break;
default:
inboxId = (string)e.Parameter;
pivot.SelectedItem = inboxTab;
break;
}
Methods.MainPage.PageContent.LoadingPage.Close();
} }
private void Pivot_SelectionChanged(object sender, SelectionChangedEventArgs e) private void Pivot_SelectionChanged(object sender, SelectionChangedEventArgs e)
{ {
if (pivot.SelectedIndex == 2 && !inboxLoaded) if (pivot.SelectedItem == inboxTab && !inboxLoaded)
{ {
(((pivot.Items[2] as PivotItem).Content as ScrollViewer).Content as Inbox).LoadItems(); inbox.LoadItems(inboxId);
inboxLoaded = true; inboxLoaded = true;
if(inboxId != null) inboxId = null;
{
(((pivot.Items[2] as PivotItem).Content as ScrollViewer).Content as Inbox).Open(inboxId as string);
inboxId = null;
}
} }
} }
} }
+20 -41
View File
@@ -7,48 +7,27 @@
mc:Ignorable="d" mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid Name="grid"> <StackPanel>
<VisualStateManager.VisualStateGroups> <TextBlock Text="FoxTube" FontSize="28"/>
<VisualStateGroup> <TextBlock Name="version" Text="[currentVersion]" FontSize="14" Foreground="Gray" Margin="0,-5,0,0"/>
<VisualState>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="600"/>
</VisualState.StateTriggers>
<VisualState.Setters> <TextBlock x:Uid="/About/developed" TextWrapping="WrapWholeWords" Text="Developed by Michael &#x22;XFox&#x22; Gordeev" Margin="0,10,0,0"/>
<Setter Target="grid.ColumnDefinitions[1].Width" Value="auto"/> <TextBlock TextWrapping="WrapWholeWords" Visibility="Collapsed" Text="Special thanks to contributors for motivating me, testers and translators for making this app better everyday and you for using this app;)" Margin="0,10,0,0"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="0"/>
</Grid.ColumnDefinitions>
<StackPanel> <TextBlock x:Uid="/About/contacts" Text="Contacts" FontSize="22" FontWeight="SemiBold" Margin="0,10,0,0"/>
<TextBlock Text="FoxTube" FontSize="28"/> <TextBlock><Run x:Uid="/About/twitter">Twitter:</Run> <Hyperlink NavigateUri="https://twitter.com/xfox111">@xfox111</Hyperlink></TextBlock>
<TextBlock Name="version" Text="[currentVersion]" FontSize="14" Foreground="Gray" Margin="0,-5,0,10"/> <TextBlock><Run x:Uid="/About/vk">Vkontakte:</Run> <Hyperlink NavigateUri="https://vk.com/XFox.Mike">@XFox.Mike</Hyperlink></TextBlock>
<TextBlock Visibility="Collapsed">YouTube: <Hyperlink NavigateUri="https://youtube.com/c/FoxGameStudioChannel">@xfox</Hyperlink></TextBlock>
<TextBlock>E-mail: <Hyperlink NavigateUri="mailto:michael.xfox@outlook.com">michael.xfox@outlook.com</Hyperlink></TextBlock>
<TextBlock Visibility="Collapsed"><Run x:Uid="/About/myBlog">My website:</Run> <Hyperlink NavigateUri="https://michael-xfox.com">https://michael-xfox.com</Hyperlink></TextBlock>
<TextBlock x:Uid="/About/developed" TextWrapping="WrapWholeWords" Text="Developed by Michael Gordeev (also known as XFox)" Margin="0,0,0,10"/> <TextBlock x:Uid="/About/legal" Text="Legal stuff" FontSize="22" FontWeight="SemiBold" Margin="0,10,0,0"/>
<TextBlock TextWrapping="WrapWholeWords" Visibility="Collapsed" Text="Special thanks to contributors for motivating me, testers and translators for making this app better everyday and you for using this app;)" Margin="0,0,0,10"/> <HyperlinkButton x:Uid="/About/ourPrivacy" Content="Our Privacy Policy" NavigateUri="https://foxgame-studio.000webhostapp.com/FoxTubeAssets/PrivacyPolicy.txt" Padding="0"/>
<HyperlinkButton x:Uid="/About/ytPrivacy" Content="YouTube Privacy Policy" NavigateUri="https://youtube.com/t/privacy" Padding="0"/>
<TextBlock x:Uid="/About/contacts" Text="Contacts" FontSize="22" FontWeight="SemiBold"/> <HyperlinkButton x:Uid="/About/terms" Content="YouTube Terms of use" NavigateUri="https://youtube.com/t/terms" Padding="0"/>
<TextBlock><Run x:Uid="/About/twitter">Twitter:</Run> <Hyperlink NavigateUri="https://twitter.com/XFox_Mike">@XFox_Mike</Hyperlink></TextBlock> <HyperlinkButton x:Uid="/About/guides" Content="YouTube Community Guidelines" NavigateUri="https://youtube.com/t/community_guidelines" Padding="0,0,0,10"/>
<TextBlock><Run x:Uid="/About/vk">Vkontakte:</Run> <Hyperlink NavigateUri="https://vk.com/XFox.Mike">@XFox.Mike</Hyperlink></TextBlock> <TextBlock Name="crMe" x:Uid="/About/crMe" Text="© Michael Gordeev"/>
<TextBlock Visibility="Collapsed">YouTube: <Hyperlink NavigateUri="https://youtube.com/c/FoxGameStudioChannel">@FoxGameStudioChannel</Hyperlink></TextBlock> <TextBlock Name="crYt" x:Uid="/About/crYt" Text="© YouTube, LLC"/>
<TextBlock>E-mail: <Hyperlink NavigateUri="mailto:michael.xfox@outlook.com">michael.xfox@outlook.com</Hyperlink></TextBlock> <Button Name="feedback" x:Uid="/About/feedback" Content="Leave feedback" Margin="0,10" Click="Button_Click" Visibility="Collapsed"/>
<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> </StackPanel>
<TextBlock x:Uid="/About/legal" Text="Legal stuff" FontSize="22" FontWeight="SemiBold"/>
<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"/>
<TextBlock x:Uid="/About/crMe" Text="© 2018 Michael Gordeev"/>
<TextBlock x:Uid="/About/crYt" Text="© 2018 YouTube, LLC"/>
<Button Name="feedback" x:Uid="/About/feedback" Content="Leave feedback" Margin="0,5" Click="Button_Click" Visibility="Collapsed"/>
</StackPanel>
<Image Grid.Column="1" Source="/Assets/LogoAvatar.png" VerticalAlignment="Top" Width="128"/>
</Grid>
</Page> </Page>
@@ -17,6 +17,9 @@ namespace FoxTube.Pages.SettingsPages
PackageVersion ver = Package.Current.Id.Version; PackageVersion ver = Package.Current.Id.Version;
version.Text = $"{ver.Major}.{ver.Minor}.{ver.Build}"; version.Text = $"{ver.Major}.{ver.Minor}.{ver.Build}";
crMe.Text = crMe.Text.Insert(1, " " + DateTime.Now.Year);
crYt.Text = crYt.Text.Insert(1, " " + DateTime.Now.Year);
if (StoreServicesFeedbackLauncher.IsSupported()) if (StoreServicesFeedbackLauncher.IsSupported())
feedback.Visibility = Visibility.Visible; feedback.Visibility = Visibility.Visible;
} }
+20 -19
View File
@@ -26,6 +26,7 @@ namespace FoxTube.Pages.SettingsPages
foreach (VideoQuality i in Enum.GetValues(typeof(VideoQuality)).ToReversedList()) foreach (VideoQuality i in Enum.GetValues(typeof(VideoQuality)).ToReversedList())
quality.Items.Add(new ComboBoxItem() { Tag = i.GetVideoQualityLabel(), Content = i.GetVideoQualityLabel() }); quality.Items.Add(new ComboBoxItem() { Tag = i.GetVideoQualityLabel(), Content = i.GetVideoQualityLabel() });
quality.SelectedItem = quality.Items.ToList().Find(i => ((ComboBoxItem)i).Tag.ToString() == SettingsStorage.VideoQuality); quality.SelectedItem = quality.Items.ToList().Find(i => ((ComboBoxItem)i).Tag.ToString() == SettingsStorage.VideoQuality);
mobileWarning.IsOn = SettingsStorage.CheckConnection; mobileWarning.IsOn = SettingsStorage.CheckConnection;
autoplay.IsOn = SettingsStorage.Autoplay; autoplay.IsOn = SettingsStorage.Autoplay;
@@ -50,34 +51,34 @@ namespace FoxTube.Pages.SettingsPages
async void InitializeRegions() async void InitializeRegions()
{ {
//Initialize regions
I18nRegionsResource.ListRequest regRequest = SecretsVault.Service.I18nRegions.List("snippet"); I18nRegionsResource.ListRequest regRequest = SecretsVault.Service.I18nRegions.List("snippet");
regRequest.Hl = SettingsStorage.Language; regRequest.Hl = SettingsStorage.Language;
I18nRegionListResponse regResponse = await regRequest.ExecuteAsync(); I18nRegionListResponse regResponse = await regRequest.ExecuteAsync();
regResponse.Items.ForEach(i => region.Items.Add(new ComboBoxItem regResponse.Items.ForEach(i => region.Items.Add(new ComboBoxItem
{ {
Content = i.Snippet.Name, Content = i.Snippet.Name,
Tag = i.Snippet.Gl Tag = i.Snippet.Gl
})); }));
region.SelectedItem = region.Items.Find(i => ((ComboBoxItem)i).Tag as string == SettingsStorage.Region) ?? region.Items.Find(i => ((ComboBoxItem)i).Tag as string == SettingsStorage.Language.Remove(0, 3)); region.SelectedItem = region.Items.Find(i => ((ComboBoxItem)i).Tag as string == SettingsStorage.Region);
//Initialize relevance language
I18nLanguagesResource.ListRequest langRequest = SecretsVault.Service.I18nLanguages.List("snippet"); I18nLanguagesResource.ListRequest langRequest = SecretsVault.Service.I18nLanguages.List("snippet");
langRequest.Hl = SettingsStorage.Language; langRequest.Hl = SettingsStorage.Language;
I18nLanguageListResponse langResponse = await langRequest.ExecuteAsync(); I18nLanguageListResponse langResponse = await langRequest.ExecuteAsync();
foreach(I18nLanguage i in langResponse.Items)
langResponse.Items.ForEach(i => relLanguage.Items.Add(new ComboBoxItem
{ {
relLanguage.Items.Add(new ComboBoxItem Content = i.Snippet.Name,
{ Tag = i.Snippet.Hl
Content = i.Snippet.Name, }));
Tag = i.Snippet.Hl relLanguage.SelectedItem = relLanguage.Items.Find(i => ((ComboBoxItem)i).Tag as string == SettingsStorage.RelevanceLanguage);
});
if (SettingsStorage.RelevanceLanguage == i.Snippet.Hl)
relLanguage.SelectedItem = relLanguage.Items.Last();
}
} }
private void language_SelectionChanged(object sender, SelectionChangedEventArgs e) private void language_SelectionChanged(object sender, SelectionChangedEventArgs e)
{ {
if (SettingsStorage.Language == (language.SelectedItem as ComboBoxItem).Tag.ToString()) if ((language.SelectedItem as ComboBoxItem).Tag.ToString() == SettingsStorage.Language)
return; return;
ApplicationLanguages.PrimaryLanguageOverride = (language.SelectedItem as ComboBoxItem).Tag.ToString(); ApplicationLanguages.PrimaryLanguageOverride = (language.SelectedItem as ComboBoxItem).Tag.ToString();
SettingsStorage.Language = (language.SelectedItem as ComboBoxItem).Tag.ToString(); SettingsStorage.Language = (language.SelectedItem as ComboBoxItem).Tag.ToString();
@@ -104,6 +105,11 @@ namespace FoxTube.Pages.SettingsPages
SettingsStorage.VideoNotifications = newVideo.IsOn; SettingsStorage.VideoNotifications = newVideo.IsOn;
} }
private void devNews_Toggled(object sender, RoutedEventArgs e)
{
SettingsStorage.DevNotifications = devNews.IsOn;
}
private void RelLanguage_SelectionChanged(object sender, SelectionChangedEventArgs e) private void RelLanguage_SelectionChanged(object sender, SelectionChangedEventArgs e)
{ {
SettingsStorage.RelevanceLanguage = ((ComboBoxItem)relLanguage.SelectedItem).Tag.ToString(); SettingsStorage.RelevanceLanguage = ((ComboBoxItem)relLanguage.SelectedItem).Tag.ToString();
@@ -121,17 +127,17 @@ namespace FoxTube.Pages.SettingsPages
private void RadioButton_Checked(object sender, RoutedEventArgs e) private void RadioButton_Checked(object sender, RoutedEventArgs e)
{ {
if (sender == light && SettingsStorage.Theme != 0) if (sender == light)
{ {
SettingsStorage.Theme = 0; SettingsStorage.Theme = 0;
Methods.MainPage.RequestedTheme = ElementTheme.Light; Methods.MainPage.RequestedTheme = ElementTheme.Light;
} }
else if (sender == dark && SettingsStorage.Theme != 1) else if (sender == dark)
{ {
SettingsStorage.Theme = 1; SettingsStorage.Theme = 1;
Methods.MainPage.RequestedTheme = ElementTheme.Dark; Methods.MainPage.RequestedTheme = ElementTheme.Dark;
} }
else if (sender == system && SettingsStorage.Theme != 2) else if (sender == system)
{ {
SettingsStorage.Theme = 2; SettingsStorage.Theme = 2;
if (new Windows.UI.ViewManagement.UISettings().GetColorValue(Windows.UI.ViewManagement.UIColorType.Background) == Colors.Black) if (new Windows.UI.ViewManagement.UISettings().GetColorValue(Windows.UI.ViewManagement.UIColorType.Background) == Colors.Black)
@@ -146,10 +152,5 @@ namespace FoxTube.Pages.SettingsPages
{ {
CoreApplication.Exit(); CoreApplication.Exit();
} }
private void devNews_Toggled(object sender, RoutedEventArgs e)
{
SettingsStorage.DevNotifications = devNews.IsOn;
}
} }
} }
+5 -2
View File
@@ -10,7 +10,7 @@
<Grid Name="grid"> <Grid Name="grid">
<VisualStateManager.VisualStateGroups> <VisualStateManager.VisualStateGroups>
<VisualStateGroup> <VisualStateGroup CurrentStateChanged="VisualStateGroup_CurrentStateChanged">
<VisualState> <VisualState>
<VisualState.StateTriggers> <VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="1500"/> <AdaptiveTrigger MinWindowWidth="1500"/>
@@ -20,6 +20,7 @@
<Setter Target="grid.ColumnDefinitions[0].Width" Value="*"/> <Setter Target="grid.ColumnDefinitions[0].Width" Value="*"/>
<Setter Target="grid.ColumnDefinitions[1].Width" Value="3*"/> <Setter Target="grid.ColumnDefinitions[1].Width" Value="3*"/>
<Setter Target="close.Visibility" Value="Collapsed"/> <Setter Target="close.Visibility" Value="Collapsed"/>
<Setter Target="selector.Background" Value="{StaticResource SystemControlBackgroundChromeMediumLowBrush}"/>
</VisualState.Setters> </VisualState.Setters>
</VisualState> </VisualState>
@@ -32,6 +33,7 @@
<Setter Target="grid.ColumnDefinitions[0].Width" Value="*"/> <Setter Target="grid.ColumnDefinitions[0].Width" Value="*"/>
<Setter Target="grid.ColumnDefinitions[1].Width" Value="2*"/> <Setter Target="grid.ColumnDefinitions[1].Width" Value="2*"/>
<Setter Target="close.Visibility" Value="Collapsed"/> <Setter Target="close.Visibility" Value="Collapsed"/>
<Setter Target="selector.Background" Value="{StaticResource SystemControlBackgroundChromeMediumLowBrush}"/>
</VisualState.Setters> </VisualState.Setters>
</VisualState> </VisualState>
@@ -44,6 +46,7 @@
<Setter Target="grid.ColumnDefinitions[0].Width" Value="*"/> <Setter Target="grid.ColumnDefinitions[0].Width" Value="*"/>
<Setter Target="grid.ColumnDefinitions[1].Width" Value="*"/> <Setter Target="grid.ColumnDefinitions[1].Width" Value="*"/>
<Setter Target="close.Visibility" Value="Collapsed"/> <Setter Target="close.Visibility" Value="Collapsed"/>
<Setter Target="selector.Background" Value="{StaticResource SystemControlBackgroundChromeMediumLowBrush}"/>
</VisualState.Setters> </VisualState.Setters>
</VisualState> </VisualState>
</VisualStateGroup> </VisualStateGroup>
@@ -53,7 +56,7 @@
<ColumnDefinition Width="0"/> <ColumnDefinition Width="0"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<StackPanel VerticalAlignment="Stretch" Background="{StaticResource SystemControlBackgroundChromeMediumLowBrush}"> <StackPanel VerticalAlignment="Stretch" Name="selector">
<ComboBox x:Uid="/Inbox/filter" Header="Filter" Margin="10" HorizontalAlignment="Stretch" SelectedIndex="0" Name="filter" SelectionChanged="filter_SelectionChanged"> <ComboBox x:Uid="/Inbox/filter" Header="Filter" Margin="10" HorizontalAlignment="Stretch" SelectedIndex="0" Name="filter" SelectionChanged="filter_SelectionChanged">
<ComboBoxItem x:Uid="/Inbox/all" Content="All"/> <ComboBoxItem x:Uid="/Inbox/all" Content="All"/>
<ComboBoxItem x:Uid="/Inbox/messages" Content="Messages"/> <ComboBoxItem x:Uid="/Inbox/messages" Content="Messages"/>
+54 -58
View File
@@ -7,6 +7,7 @@ using Windows.UI.Xaml.Controls;
using FoxTube.Classes; using FoxTube.Classes;
using Windows.Storage; using Windows.Storage;
using System.Xml; using System.Xml;
using Microsoft.AppCenter.Analytics;
namespace FoxTube.Pages.SettingsPages namespace FoxTube.Pages.SettingsPages
{ {
@@ -15,27 +16,26 @@ namespace FoxTube.Pages.SettingsPages
/// </summary> /// </summary>
public sealed partial class Inbox : Page public sealed partial class Inbox : Page
{ {
List<InboxItem> items = new List<InboxItem>(); readonly List<InboxItem> items = new List<InboxItem>();
string open;
public Inbox() public Inbox()
{ {
InitializeComponent(); InitializeComponent();
} }
public async void LoadItems() public async void LoadItems(string id = null)
{ {
try try
{ {
XmlDocument doc = new XmlDocument(); XmlDocument doc = new XmlDocument();
StorageFile file = await (await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFolderAsync(@"Assets\Data")).GetFileAsync("Patchnotes.xml"); StorageFile file = await StorageFile.GetFileFromApplicationUriAsync("ms-appx:///Assets/Data/Patchnotes.xml".ToUri());
doc.Load(await file.OpenStreamForReadAsync()); doc.Load(await file.OpenStreamForReadAsync());
foreach (XmlElement e in doc["items"].ChildNodes) foreach (XmlElement e in doc["items"].ChildNodes)
items.Add(new InboxItem( items.Add(new InboxItem(
e.GetAttribute("version"), e.GetAttribute("version"),
e["content"][SettingsStorage.Language].InnerText, e["content"][SettingsStorage.Language].InnerText,
e.GetAttribute("time"))); DateTime.Parse(e.GetAttribute("time"))));
doc.Load("http://foxgame-studio.000webhostapp.com/foxtube-messages.xml"); doc.Load("http://foxgame-studio.000webhostapp.com/foxtube-messages.xml");
foreach (XmlElement e in doc["posts"].ChildNodes) foreach (XmlElement e in doc["posts"].ChildNodes)
@@ -43,59 +43,55 @@ namespace FoxTube.Pages.SettingsPages
e["header"][SettingsStorage.Language].InnerText, e["header"][SettingsStorage.Language].InnerText,
e["content"][SettingsStorage.Language].InnerText, e["content"][SettingsStorage.Language].InnerText,
DateTime.Parse(e.GetAttribute("time")), DateTime.Parse(e.GetAttribute("time")),
e["id"].InnerText e["id"].InnerText));
)); }
catch (Exception e)
items.OrderBy(item => item.TimeStamp); {
Analytics.TrackEvent("Failed to load inbox", new Dictionary<string, string>
{
{ "Exception", e.GetType().ToString() },
{ "Message", e.Message }
});
} }
catch { }
items.OrderBy(item => item.TimeStamp);
items.ForEach(i => list.Items.Add(i)); items.ForEach(i => list.Items.Add(i));
if (!string.IsNullOrWhiteSpace(open)) if (!string.IsNullOrWhiteSpace(id))
Open(open); list.SelectedItem = items.Find(i => i.Id == id);
open = null;
} }
private void filter_SelectionChanged(object sender, SelectionChangedEventArgs e) private void filter_SelectionChanged(object sender, SelectionChangedEventArgs e)
{ {
try if (list == null)
return;
list.Items.Clear();
switch (filter.SelectedIndex)
{ {
list.Items.Clear(); case 0:
items.ForEach(i => list.Items.Add(i));
break;
switch (filter.SelectedIndex) case 1:
{ List<InboxItem> messages = items.FindAll(i => i.Type == InboxItemType.Default);
case 0: messages.ForEach(i => list.Items.Add(i));
items.ForEach(i => list.Items.Add(i)); break;
break;
case 1: case 2:
List<InboxItem> messages = items.FindAll(i => i.Type == InboxItemType.Default); List<InboxItem> notes = items.FindAll(i => i.Type == InboxItemType.PatchNote);
messages.ForEach(i => list.Items.Add(i)); notes.ForEach(i => list.Items.Add(i));
break; break;
case 2:
List<InboxItem> notes = items.FindAll(i => i.Type == InboxItemType.PatchNote);
notes.ForEach(i => list.Items.Add(i));
break;
}
} }
catch(NullReferenceException) { }
} }
private void list_SelectionChanged(object sender, SelectionChangedEventArgs e) private void list_SelectionChanged(object sender, SelectionChangedEventArgs e)
{ {
InboxItem item = list.SelectedItem as InboxItem; if (!(list.SelectedItem is InboxItem item))
if(list.SelectedItem != null) return;
{
OpenView(item.Title, item.Content); OpenView(item.Title, item.Content);
if (grid.ColumnDefinitions[1].Width.Value == 0)
{
grid.ColumnDefinitions[0].Width = new GridLength(0);
grid.ColumnDefinitions[1].Width = new GridLength(1, GridUnitType.Star);
}
}
} }
void CloseView() void CloseView()
@@ -104,6 +100,12 @@ namespace FoxTube.Pages.SettingsPages
title.Text = ""; title.Text = "";
list.SelectedItem = null; list.SelectedItem = null;
block.Visibility = Visibility.Visible; block.Visibility = Visibility.Visible;
if (grid.ColumnDefinitions[0].Width.Value == 0)
{
grid.ColumnDefinitions[1].Width = new GridLength(0);
grid.ColumnDefinitions[0].Width = new GridLength(1, GridUnitType.Star);
}
} }
void OpenView(string header, string body) void OpenView(string header, string body)
@@ -111,29 +113,23 @@ namespace FoxTube.Pages.SettingsPages
content.Text = body; content.Text = body;
title.Text = header; title.Text = header;
block.Visibility = Visibility.Collapsed; block.Visibility = Visibility.Collapsed;
if (grid.ColumnDefinitions[1].Width.Value == 0)
{
grid.ColumnDefinitions[0].Width = new GridLength(0);
grid.ColumnDefinitions[1].Width = new GridLength(1, GridUnitType.Star);
}
} }
private void close_Click(object sender, RoutedEventArgs e) private void close_Click(object sender, RoutedEventArgs e)
{ {
CloseView(); CloseView();
if (grid.ColumnDefinitions[0].Width.Value == 0)
{
grid.ColumnDefinitions[0].Width = new GridLength(1, GridUnitType.Star);
grid.ColumnDefinitions[1].Width = new GridLength(0);
}
} }
public void Open(string arg) private void VisualStateGroup_CurrentStateChanged(object sender, VisualStateChangedEventArgs e)
{ {
if(items.Count == 0) if (e.NewState == null)
{ CloseView();
open = arg;
return;
}
InboxItem item = items.Find(i => i.Id == arg);
if(item != null)
list.SelectedItem = item;
} }
} }
} }
+22 -26
View File
@@ -4,34 +4,30 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:foxtube="using:FoxTube"
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls" xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
mc:Ignorable="d" mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid> <ScrollViewer>
<ScrollViewer> <controls:AdaptiveGridView ItemsSource="{x:Bind list}" DesiredWidth="250">
<controls:AdaptiveGridView ItemsSource="{x:Bind list}" DesiredWidth="250" Margin="5,0,0,0"> <controls:AdaptiveGridView.ItemTemplate>
<controls:AdaptiveGridView.ItemTemplate> <DataTemplate>
<DataTemplate> <Button HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" Padding="5" Tag="{Binding Path=Snippet.ResourceId.ChannelId}" Click="Button_Click">
<Button HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" Padding="5" Tag="{Binding Path=Snippet.ResourceId.ChannelId}" Click="Button_Click"> <Grid>
<Grid> <Grid.ColumnDefinitions>
<Grid.ColumnDefinitions> <ColumnDefinition Width="55"/>
<ColumnDefinition Width="55"/> <ColumnDefinition/>
<ColumnDefinition/> </Grid.ColumnDefinitions>
</Grid.ColumnDefinitions> <PersonPicture Height="50" HorizontalAlignment="Left">
<PersonPicture Height="50" HorizontalAlignment="Left"> <PersonPicture.ProfilePicture>
<PersonPicture.ProfilePicture> <BitmapImage UriSource="{Binding Path=Snippet.Thumbnails.Medium.Url}" DecodePixelHeight="50" DecodePixelWidth="50"/>
<BitmapImage UriSource="{Binding Path=Snippet.Thumbnails.Medium.Url}" DecodePixelHeight="50" DecodePixelWidth="50"/> </PersonPicture.ProfilePicture>
</PersonPicture.ProfilePicture> </PersonPicture>
</PersonPicture> <TextBlock Grid.Column="1" TextWrapping="Wrap" VerticalAlignment="Center" TextTrimming="CharacterEllipsis" Text="{Binding Path=Snippet.Title}"/>
<TextBlock Grid.Column="1" TextWrapping="Wrap" VerticalAlignment="Center" TextTrimming="CharacterEllipsis" Text="{Binding Path=Snippet.Title}"/> </Grid>
</Grid> </Button>
</Button> </DataTemplate>
</DataTemplate> </controls:AdaptiveGridView.ItemTemplate>
</controls:AdaptiveGridView.ItemTemplate> </controls:AdaptiveGridView>
</controls:AdaptiveGridView> </ScrollViewer>
</ScrollViewer>
<foxtube:LoadingPage Visibility="Collapsed"/>
</Grid>
</Page> </Page>
+3 -1
View File
@@ -8,13 +8,15 @@ namespace FoxTube.Pages
/// <summary> /// <summary>
/// User's subscriptions page /// User's subscriptions page
/// </summary> /// </summary>
public sealed partial class Subscriptions : Page, NavigationPage public sealed partial class Subscriptions : Page, INavigationPage
{ {
public object Parameter { get; set; } = null; public object Parameter { get; set; } = null;
readonly List<Subscription> list = SecretsVault.Subscriptions; readonly List<Subscription> list = SecretsVault.Subscriptions;
public Subscriptions() public Subscriptions()
{ {
InitializeComponent(); InitializeComponent();
Methods.MainPage.PageContent.LoadingPage.Close();
} }
private void Button_Click(object sender, RoutedEventArgs e) private void Button_Click(object sender, RoutedEventArgs e)
+10 -15
View File
@@ -4,22 +4,17 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ui="using:Microsoft.Toolkit.Uwp.UI.Controls"
mc:Ignorable="d"> mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" Name="grid" SizeChanged="Grid_SizeChanged"> <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.ColumnDefinitions> <ui:AdaptiveGridView Name="list" DesiredWidth="400" SelectionMode="None" HorizontalContentAlignment="Left">
<ColumnDefinition/> <ui:AdaptiveGridView.ItemContainerTransitions>
<ColumnDefinition Width="0"/> <TransitionCollection>
<ColumnDefinition Width="0"/> <EntranceThemeTransition IsStaggeringEnabled="True"/>
<ColumnDefinition Width="0"/> </TransitionCollection>
<ColumnDefinition Width="0"/> </ui:AdaptiveGridView.ItemContainerTransitions>
</Grid.ColumnDefinitions> </ui:AdaptiveGridView>
<TextBlock Name="empty" Grid.ColumnSpan="5" Text="&#xD8;" FontSize="200" Foreground="Gray" VerticalAlignment="Center" HorizontalAlignment="Center" Grid.RowSpan="2"/> <TextBlock Name="empty" Text="&#xD8;" FontSize="200" Foreground="Gray" VerticalAlignment="Center" HorizontalAlignment="Center" Grid.RowSpan="2"/>
<StackPanel Grid.Column="0" Name="col0"/>
<StackPanel Grid.Column="1" Name="col1"/>
<StackPanel Grid.Column="2" Name="col2"/>
<StackPanel Grid.Column="3" Name="col3"/>
<StackPanel Grid.Column="4" Name="col4"/>
</Grid> </Grid>
</Page> </Page>
+9 -58
View File
@@ -1,5 +1,5 @@
using FoxTube.Controls.Adverts; using FoxTube.Controls;
using System.Collections.Generic; using FoxTube.Controls.Adverts;
using Windows.UI.Xaml; using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls;
@@ -10,19 +10,9 @@ namespace FoxTube.Pages
/// </summary> /// </summary>
public sealed partial class VideoGrid : Page public sealed partial class VideoGrid : Page
{ {
public int Columns public int Count => list.Items.Count;
{ public ItemCollection Children => list.Items;
get { return cols; } private int ItemsCount => Children.FindAll(i => i is VideoCard).Count + Children.FindAll(i => i is ChannelCard).Count + Children.FindAll(i => i is PlaylistCard).Count + Children.FindAll(i => i is CardAdvert).Count;
set
{
cols = value;
UpdateGrid();
}
}
private int cols = 1;
public int Count => Children.Count;
public bool IsRelatedVideos { get; set; } = false;
public List<UIElement> Children { get; } = new List<UIElement>();
public VideoGrid() public VideoGrid()
{ {
@@ -31,60 +21,21 @@ namespace FoxTube.Pages
public void Add(UIElement card) public void Add(UIElement card)
{ {
(grid.Children[Count % cols + 1] as StackPanel).Children.Add(card); list.Items.Add(card);
Children.Add(card); if ((list.Items.Count - 5) % 25 == 0)
list.Items.Add(new CardAdvert());
if ((Children.Count - 5) % 25 == 0 && !SecretsVault.AdsDisabled)
{
CardAdvert advert = new CardAdvert(IsRelatedVideos);
(grid.Children[Count % cols + 1] as StackPanel).Children.Add(advert);
Children.Add(advert);
}
empty.Visibility = Visibility.Collapsed; empty.Visibility = Visibility.Collapsed;
} }
public void Clear() public void Clear()
{ {
for (int k = 1; k <= 5; k++) list.Items.Clear();
(grid.Children[k] as StackPanel).Children.Clear();
empty.Visibility = Visibility.Visible; empty.Visibility = Visibility.Visible;
} }
public void DeleteItem(FrameworkElement item) public void DeleteItem(FrameworkElement item)
{ {
Children.Remove(item); Children.Remove(item);
UpdateGrid();
}
void UpdateGrid()
{
for (int k = 1; k <= 5; k++)
(grid.Children[k] as StackPanel).Children.Clear();
for (int k = 0; k < Count; k++)
(grid.Children[k % cols + 1] as StackPanel).Children.Add(Children[k]);
for (int k = 0; k < cols; k++)
grid.ColumnDefinitions[k].Width = new GridLength(1, GridUnitType.Star);
for (int k = cols; k < 5; k++)
grid.ColumnDefinitions[k].Width = new GridLength(0);
}
private void Grid_SizeChanged(object sender, SizeChangedEventArgs e)
{
if (e.NewSize.Width >= 1600 && Columns != 5)
Columns = 5;
else if (e.NewSize.Width >= 1200 && e.NewSize.Width < 1600 && Columns != 4)
Columns = 4;
else if (e.NewSize.Width >= 900 && e.NewSize.Width < 1200 && Columns != 3)
Columns = 3;
else if (e.NewSize.Width >= 550 && e.NewSize.Width < 900 && Columns != 2)
Columns = 2;
else if (e.NewSize.Width < 550 && Columns != 1)
Columns = 1;
} }
} }
} }
+4 -6
View File
@@ -29,8 +29,8 @@
<ColumnDefinition Width="400"/> <ColumnDefinition Width="400"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<ScrollViewer Margin="0,0,0,50" Name="mainScroll" VerticalScrollBarVisibility="Hidden"> <ScrollViewer Margin="0,0,0,50" Name="mainScroll" VerticalScrollBarVisibility="Hidden">
<StackPanel Orientation="Vertical" Name="mainContent"> <StackPanel Name="mainContent">
<Border BorderBrush="Red" BorderThickness="5" CornerRadius="10" Margin="0,10" Name="upcoming" Visibility="Collapsed"> <Border BorderBrush="Red" BorderThickness="5" CornerRadius="10" Margin="10" Name="upcoming" Visibility="Collapsed">
<Grid Margin="10"> <Grid Margin="10">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/> <ColumnDefinition Width="auto"/>
@@ -125,10 +125,10 @@
</CommandBar> </CommandBar>
<Grid Grid.Column="1" Name="tabsPlaceholder"> <Grid Grid.Column="1" Name="tabsPlaceholder">
<Pivot Grid.Row="1" Name="pivot" SelectedIndex="0" IsHeaderItemsCarouselEnabled="False"> <Pivot Name="pivot" SelectedIndex="0" IsHeaderItemsCarouselEnabled="False">
<PivotItem x:Uid="/VideoPage/related" Header="Suggestions"> <PivotItem x:Uid="/VideoPage/related" Header="Suggestions">
<ScrollViewer> <ScrollViewer>
<pages:VideoGrid x:Name="relatedVideos" IsRelatedVideos="True"/> <pages:VideoGrid x:Name="relatedVideos"/>
</ScrollViewer> </ScrollViewer>
</PivotItem> </PivotItem>
<PivotItem x:Uid="/VideoPage/comments" Header="Comments" Name="commentsPlaceholder"> <PivotItem x:Uid="/VideoPage/comments" Header="Comments" Name="commentsPlaceholder">
@@ -174,7 +174,5 @@
</ComboBox> </ComboBox>
</StackPanel> </StackPanel>
</ContentDialog> </ContentDialog>
<local:LoadingPage Grid.ColumnSpan="2" Visibility="Collapsed" x:Name="loading" RefreshPage="refresh_Click"/>
</Grid> </Grid>
</Page> </Page>
+74 -86
View File
@@ -42,11 +42,12 @@ namespace FoxTube.Pages
/// <summary> /// <summary>
/// Video page /// Video page
/// </summary> /// </summary>
public sealed partial class VideoPage : Page public sealed partial class VideoPage : Page, INavigationPage
{ {
ResourceLoader resources = ResourceLoader.GetForCurrentView("VideoPage"); ResourceLoader resources = ResourceLoader.GetForCurrentView("VideoPage");
public string videoId; public object Parameter { get; set; } = null;
public string playlistId = null; public string playlistId = null;
public Video item; public Video item;
public HistoryItem history; public HistoryItem history;
@@ -59,14 +60,11 @@ namespace FoxTube.Pages
DispatcherTimer liveTimer; DispatcherTimer liveTimer;
DispatcherTimer countdownTimer; DispatcherTimer countdownTimer;
public LoadingPage LoadingPage => loading;
public VideoPlayer Player => player; public VideoPlayer Player => player;
public VideoPage() public VideoPage()
{ {
InitializeComponent(); InitializeComponent();
DataTransferManager.GetForCurrentView().DataRequested += new TypedEventHandler<DataTransferManager, DataRequestedEventArgs>(Share);
if (Window.Current.Bounds.Width <= 1000) if (Window.Current.Bounds.Width <= 1000)
{ {
@@ -78,14 +76,12 @@ namespace FoxTube.Pages
mainContent.Children.Add(pivot); mainContent.Children.Add(pivot);
grid.ColumnDefinitions[1].Width = new GridLength(0); grid.ColumnDefinitions[1].Width = new GridLength(0);
pivot.SelectedIndex = 0;
} }
} }
private void Player_NextClicked() private void Player_NextClicked()
{ {
if (playlistId != null) if (playlistId != null && playlistList.SelectedIndex + 1 < playlistList.Items.Count)
playlistList.SelectedIndex++; playlistList.SelectedIndex++;
else else
(relatedVideos.Children[0] as VideoCard).Button_Click(this, null); (relatedVideos.Children[0] as VideoCard).Button_Click(this, null);
@@ -94,19 +90,15 @@ namespace FoxTube.Pages
protected override void OnNavigatedTo(NavigationEventArgs e) protected override void OnNavigatedTo(NavigationEventArgs e)
{ {
base.OnNavigatedTo(e); base.OnNavigatedTo(e);
if (e.Parameter == null) Parameter = e.Parameter;
loading.Error("NullReferenceException", "Unable to initialize page. Video ID is not stated.");
else Initialize(e.Parameter as object[]);
Initialize(e.Parameter as object[]);
} }
public async void Initialize(object[] ids) public async void Initialize(object[] ids)
{ {
loading.Refresh();
try try
{ {
videoId = ids[0] as string;
incognito = (bool)ids[2]; incognito = (bool)ids[2];
if (ids[1] != null) if (ids[1] != null)
@@ -130,27 +122,26 @@ namespace FoxTube.Pages
LoadInfo(); LoadInfo();
LoadAddTo(); LoadAddTo();
loading.Close(); Methods.MainPage.VideoContent.LoadingPage.Close();
} }
catch (System.Net.Http.HttpRequestException) catch (System.Net.Http.HttpRequestException)
{ {
loading.Error("System.Net.Http.HttpRequestException", "Unable to connect to Google servers.", true); Methods.MainPage.VideoContent.LoadingPage.Error("System.Net.Http.HttpRequestException", "Unable to connect to Google servers.", true);
} }
catch (Exception e) catch (Exception e)
{ {
loading.Error(e.GetType().ToString(), e.Message); Methods.MainPage.VideoContent.LoadingPage.Error(e.GetType().ToString(), e.Message);
Analytics.TrackEvent("Video loading error", new Dictionary<string, string>() Analytics.TrackEvent("Video loading error", new Dictionary<string, string>()
{ {
{ "Exception", e.GetType().ToString() }, { "Exception", e.GetType().ToString() },
{ "Message", e.Message }, { "Message", e.Message },
{ "Video ID", videoId } { "Video ID", item.Id }
}); });
} }
} }
void SetSchedule() void SetSchedule()
{ {
views.Visibility = Visibility.Collapsed;
upcoming.Visibility = Visibility.Visible; upcoming.Visibility = Visibility.Visible;
if (item.LiveStreamingDetails.ScheduledEndTime.HasValue || item.LiveStreamingDetails.ScheduledStartTime.HasValue) if (item.LiveStreamingDetails.ScheduledEndTime.HasValue || item.LiveStreamingDetails.ScheduledStartTime.HasValue)
schedule.Visibility = Visibility.Visible; schedule.Visibility = Visibility.Visible;
@@ -208,7 +199,6 @@ namespace FoxTube.Pages
} }
else else
{ {
//Retrieving data //Retrieving data
PlaylistsResource.ListRequest playlistRequest = SecretsVault.Service.Playlists.List("snippet,contentDetails"); PlaylistsResource.ListRequest playlistRequest = SecretsVault.Service.Playlists.List("snippet,contentDetails");
playlistRequest.Id = id; playlistRequest.Id = id;
@@ -237,7 +227,7 @@ namespace FoxTube.Pages
//Setting data //Setting data
playlistName.Text = playlistItem.Snippet.Localized.Title; playlistName.Text = playlistItem.Snippet.Localized.Title;
playlistChannel.Text = playlistItem.Snippet.ChannelTitle; playlistChannel.Text = Methods.GuardFromNull(playlistItem.Snippet.ChannelTitle);
playlistCounter.Text = $"{items.IndexOf(selection) + 1}/{playlistItem.ContentDetails.ItemCount}"; playlistCounter.Text = $"{items.IndexOf(selection) + 1}/{playlistItem.ContentDetails.ItemCount}";
} }
@@ -249,9 +239,6 @@ namespace FoxTube.Pages
await Task.Delay(500); await Task.Delay(500);
playlistScroll.ChangeView(null, playlistList.SelectedIndex * 86 + 89, null, true); playlistScroll.ChangeView(null, playlistList.SelectedIndex * 86 + 89, null, true);
if (playlistList.SelectedIndex == playlistList.Items.Count - 1)
player.Controls.IsNextTrackButtonVisible = false;
} }
async void LoadInfo() async void LoadInfo()
@@ -259,7 +246,7 @@ namespace FoxTube.Pages
//Setting meta //Setting meta
title.Text = item.Snippet.Localized.Title; title.Text = item.Snippet.Localized.Title;
date.Text = $"{resources.GetString("/VideoPage/publishedAt")}: {item.Snippet.PublishedAt} ({Methods.GetAgo(item.Snippet.PublishedAt.Value)})"; date.Text = $"{resources.GetString("/VideoPage/publishedAt")}: {item.Snippet.PublishedAt} ({Methods.GetAgo(item.Snippet.PublishedAt.Value)})";
Methods.FormatText(ref description, item.Snippet.Localized.Description); description.FormatText(item.Snippet.Localized.Description);
//Setting channel button //Setting channel button
ChannelsResource.ListRequest channelRequest = SecretsVault.Service.Channels.List("snippet, statistics"); ChannelsResource.ListRequest channelRequest = SecretsVault.Service.Channels.List("snippet, statistics");
@@ -278,28 +265,24 @@ namespace FoxTube.Pages
//Setting User's rate //Setting User's rate
if (SecretsVault.IsAuthorized) if (SecretsVault.IsAuthorized)
{ {
VideoGetRatingResponse ratingResponse = await SecretsVault.Service.Videos.GetRating(videoId).ExecuteAsync(); VideoRating rating = (await SecretsVault.Service.Videos.GetRating(item.Id).ExecuteAsync()).Items[0];
if (ratingResponse.Items[0].Rating == "like") if (rating.Rating == "like")
{ {
userRating = Rating.Like; userRating = Rating.Like;
like.Foreground = new SolidColorBrush(Colors.Green); like.Foreground = new SolidColorBrush(Colors.Green);
} }
else if (ratingResponse.Items[0].Rating == "dislike") else if (rating.Rating == "dislike")
{ {
userRating = Rating.Dislike; userRating = Rating.Dislike;
dislike.Foreground = new SolidColorBrush(Colors.Red); dislike.Foreground = new SolidColorBrush(Colors.Red);
} }
foreach (Subscription s in SecretsVault.Subscriptions) if(SecretsVault.Subscriptions.Exists(i => i.Snippet.ResourceId.ChannelId == item.Snippet.ChannelId))
{ {
if (s.Snippet.ResourceId.ChannelId == item.Snippet.ChannelId) subscribe.Background = new SolidColorBrush(Colors.Transparent);
{ subscribe.Foreground = new SolidColorBrush(Colors.Gray);
subscribe.Background = new SolidColorBrush(Colors.Transparent); subscribe.Content = resources.GetString("/Cards/unsubscribe");
subscribe.Foreground = new SolidColorBrush(Colors.Gray);
subscribe.Content = resources.GetString("/Cards/unsubscribe");
}
} }
subscribe.Visibility = Visibility.Visible;
} }
else else
{ {
@@ -308,9 +291,9 @@ namespace FoxTube.Pages
subscribe.Visibility = Visibility.Collapsed; subscribe.Visibility = Visibility.Collapsed;
} }
if(HistorySet.Items.Exists(i => i.Id == videoId) && HistorySet.Items.Find(i => i.Id == videoId).LeftOn.TotalSeconds >= 30 && Methods.GetDuration(item.ContentDetails.Duration).TotalSeconds - HistorySet.Items.Find(i => i.Id == videoId).LeftOn.TotalSeconds >= 30)
if ((history = HistorySet.Items.Find(i => i.Id == item.Id)) != null && history.LeftOn.TotalSeconds >= 30 && Methods.GetDuration(item.ContentDetails.Duration).TotalSeconds - history.LeftOn.TotalSeconds >= 30)
{ {
history = HistorySet.Items.Find(i => i.Id == videoId);
left.Visibility = Visibility.Visible; left.Visibility = Visibility.Visible;
left.Content = $"\xE122 {resources.GetString("/VideoPage/continue")}: {history.LeftOn.ToString(@"hh\:mm\:ss")}"; left.Content = $"\xE122 {resources.GetString("/VideoPage/continue")}: {history.LeftOn.ToString(@"hh\:mm\:ss")}";
} }
@@ -342,7 +325,7 @@ namespace FoxTube.Pages
private async void LiveStatsUpdate(object sender = null, object e = null) private async void LiveStatsUpdate(object sender = null, object e = null)
{ {
VideosResource.ListRequest request = SecretsVault.Service.Videos.List("liveStreamingDetails"); VideosResource.ListRequest request = SecretsVault.Service.Videos.List("liveStreamingDetails");
request.Id = videoId; request.Id = item.Id;
views.Text = $"{(await request.ExecuteAsync()).Items[0].LiveStreamingDetails.ConcurrentViewers} {resources.GetString("/Cards/viewers")}"; views.Text = $"{(await request.ExecuteAsync()).Items[0].LiveStreamingDetails.ConcurrentViewers} {resources.GetString("/Cards/viewers")}";
} }
@@ -359,7 +342,7 @@ namespace FoxTube.Pages
{ {
try try
{ {
MediaStreamInfoSet infoSet = await new YoutubeClient().GetVideoMediaStreamInfosAsync(videoId); MediaStreamInfoSet infoSet = await new YoutubeClient().GetVideoMediaStreamInfosAsync(item.Id);
foreach (MuxedStreamInfo i in infoSet.Muxed) foreach (MuxedStreamInfo i in infoSet.Muxed)
{ {
MenuFlyoutItem menuItem = new MenuFlyoutItem() MenuFlyoutItem menuItem = new MenuFlyoutItem()
@@ -395,7 +378,7 @@ namespace FoxTube.Pages
SearchResource.ListRequest request = SecretsVault.Service.Search.List("snippet"); SearchResource.ListRequest request = SecretsVault.Service.Search.List("snippet");
request.RegionCode = SettingsStorage.Region; request.RegionCode = SettingsStorage.Region;
request.RelevanceLanguage = SettingsStorage.RelevanceLanguage; request.RelevanceLanguage = SettingsStorage.RelevanceLanguage;
request.RelatedToVideoId = videoId; request.RelatedToVideoId = item.Id;
request.SafeSearch = (SearchResource.ListRequest.SafeSearchEnum)SettingsStorage.SafeSearch; request.SafeSearch = (SearchResource.ListRequest.SafeSearchEnum)SettingsStorage.SafeSearch;
request.MaxResults = 20; request.MaxResults = 20;
request.Type = "video"; request.Type = "video";
@@ -408,9 +391,6 @@ namespace FoxTube.Pages
private void Player_Minimize(object sender, params object[] e) private void Player_Minimize(object sender, params object[] e)
{ {
if (isExtended == (bool)e[0])
return;
isExtended = (bool)e[0]; isExtended = (bool)e[0];
if(isExtended) if(isExtended)
{ {
@@ -447,12 +427,12 @@ namespace FoxTube.Pages
string timecode = player.Player.Position.TotalSeconds > 10 ? string timecode = player.Player.Position.TotalSeconds > 10 ?
"&t=" + (int)player.Player.Position.TotalSeconds + "s" : string.Empty; "&t=" + (int)player.Player.Position.TotalSeconds + "s" : string.Empty;
await Launcher.LaunchUriAsync($"https://www.youtube.com/watch?v={videoId}{timecode}".ToUri()); await Launcher.LaunchUriAsync($"https://www.youtube.com/watch?v={item.Id}{timecode}".ToUri());
} }
public void refresh_Click(object sender, RoutedEventArgs e) public void refresh_Click(object sender, RoutedEventArgs e)
{ {
Methods.MainPage.GoToVideo(videoId, playlistId); Methods.MainPage.VideoContent.Refresh();
} }
public void CloseVideo() public void CloseVideo()
@@ -497,12 +477,13 @@ namespace FoxTube.Pages
Methods.Share(args, Methods.Share(args,
item.Snippet.Thumbnails.Medium.Url, item.Snippet.Thumbnails.Medium.Url,
item.Snippet.Title, item.Snippet.Title,
$"https://www.youtube.com/watch?v={videoId}", $"https://www.youtube.com/watch?v={item.Id}",
resources.GetString("/Cards/videoShare")); resources.GetString("/Cards/videoShare"));
} }
private void share_Click(object sender, RoutedEventArgs e) private void share_Click(object sender, RoutedEventArgs e)
{ {
DataTransferManager.GetForCurrentView().DataRequested += new TypedEventHandler<DataTransferManager, DataRequestedEventArgs>(Share);
DataTransferManager.ShowShareUI(); DataTransferManager.ShowShareUI();
} }
@@ -518,7 +499,7 @@ namespace FoxTube.Pages
dislike.Foreground = new SolidColorBrush(Colors.Red); dislike.Foreground = new SolidColorBrush(Colors.Red);
dislikes.Text = (int.Parse(dislikes.Text, NumberStyles.AllowThousands) + 1).ToString("0,0"); dislikes.Text = (int.Parse(dislikes.Text, NumberStyles.AllowThousands) + 1).ToString("0,0");
rating.Value--; rating.Value--;
await SecretsVault.Service.Videos.Rate(videoId, VideosResource.RateRequest.RatingEnum.Dislike).ExecuteAsync(); await SecretsVault.Service.Videos.Rate(item.Id, VideosResource.RateRequest.RatingEnum.Dislike).ExecuteAsync();
userRating = Rating.Dislike; userRating = Rating.Dislike;
break; break;
@@ -527,7 +508,7 @@ namespace FoxTube.Pages
dislike.Foreground = new SolidColorBrush(Colors.Red); dislike.Foreground = new SolidColorBrush(Colors.Red);
dislikes.Text = (int.Parse(dislikes.Text, NumberStyles.AllowThousands) + 1).ToString("0,0"); dislikes.Text = (int.Parse(dislikes.Text, NumberStyles.AllowThousands) + 1).ToString("0,0");
rating.Maximum++; rating.Maximum++;
await SecretsVault.Service.Videos.Rate(videoId, VideosResource.RateRequest.RatingEnum.Dislike).ExecuteAsync(); await SecretsVault.Service.Videos.Rate(item.Id, VideosResource.RateRequest.RatingEnum.Dislike).ExecuteAsync();
userRating = Rating.Dislike; userRating = Rating.Dislike;
break; break;
@@ -536,7 +517,7 @@ namespace FoxTube.Pages
dislike.Foreground = new SolidColorBrush(Colors.Gray); dislike.Foreground = new SolidColorBrush(Colors.Gray);
dislikes.Text = (int.Parse(dislikes.Text, NumberStyles.AllowThousands) - 1).ToString("0,0"); dislikes.Text = (int.Parse(dislikes.Text, NumberStyles.AllowThousands) - 1).ToString("0,0");
rating.Maximum--; rating.Maximum--;
await SecretsVault.Service.Videos.Rate(videoId, VideosResource.RateRequest.RatingEnum.None).ExecuteAsync(); await SecretsVault.Service.Videos.Rate(item.Id, VideosResource.RateRequest.RatingEnum.None).ExecuteAsync();
break; break;
} }
} }
@@ -553,7 +534,7 @@ namespace FoxTube.Pages
like.Foreground = new SolidColorBrush(Colors.Green); like.Foreground = new SolidColorBrush(Colors.Green);
likes.Text = (int.Parse(likes.Text, NumberStyles.AllowThousands) + 1).ToString("0,0"); likes.Text = (int.Parse(likes.Text, NumberStyles.AllowThousands) + 1).ToString("0,0");
rating.Value++; rating.Value++;
await SecretsVault.Service.Videos.Rate(videoId, VideosResource.RateRequest.RatingEnum.Like).ExecuteAsync(); await SecretsVault.Service.Videos.Rate(item.Id, VideosResource.RateRequest.RatingEnum.Like).ExecuteAsync();
userRating = Rating.Like; userRating = Rating.Like;
break; break;
@@ -563,7 +544,7 @@ namespace FoxTube.Pages
likes.Text = (int.Parse(likes.Text, NumberStyles.AllowThousands) + 1).ToString("0,0"); likes.Text = (int.Parse(likes.Text, NumberStyles.AllowThousands) + 1).ToString("0,0");
rating.Maximum++; rating.Maximum++;
rating.Value++; rating.Value++;
await SecretsVault.Service.Videos.Rate(videoId, VideosResource.RateRequest.RatingEnum.Like).ExecuteAsync(); await SecretsVault.Service.Videos.Rate(item.Id, VideosResource.RateRequest.RatingEnum.Like).ExecuteAsync();
userRating = Rating.Like; userRating = Rating.Like;
break; break;
@@ -573,7 +554,7 @@ namespace FoxTube.Pages
likes.Text = (int.Parse(likes.Text, NumberStyles.AllowThousands) - 1).ToString("0,0"); likes.Text = (int.Parse(likes.Text, NumberStyles.AllowThousands) - 1).ToString("0,0");
rating.Maximum--; rating.Maximum--;
rating.Value--; rating.Value--;
await SecretsVault.Service.Videos.Rate(videoId, VideosResource.RateRequest.RatingEnum.None).ExecuteAsync(); await SecretsVault.Service.Videos.Rate(item.Id, VideosResource.RateRequest.RatingEnum.None).ExecuteAsync();
break; break;
} }
} }
@@ -582,7 +563,7 @@ namespace FoxTube.Pages
{ {
try try
{ {
if ((e.AddedItems[0] as VideoPlaylistItem).Id != videoId) if ((e.AddedItems[0] as VideoPlaylistItem).Id != item.Id)
Methods.MainPage.GoToVideo((e.AddedItems[0] as VideoPlaylistItem).Id, playlistId); Methods.MainPage.GoToVideo((e.AddedItems[0] as VideoPlaylistItem).Id, playlistId);
} }
catch { } catch { }
@@ -606,39 +587,46 @@ namespace FoxTube.Pages
async void LoadAddTo() async void LoadAddTo()
{ {
if(SecretsVault.UserChannel == null) try
{
if (SecretsVault.UserChannel == null)
{
addTo.Visibility = Visibility.Collapsed;
return;
}
if (SecretsVault.WatchLater.Contains(item.Id))
(addList.Items[1] as ToggleMenuFlyoutItem).IsChecked = true;
PlaylistsResource.ListRequest request = SecretsVault.Service.Playlists.List("snippet");
request.Mine = true;
request.MaxResults = 50;
PlaylistListResponse response = await request.ExecuteAsync();
PlaylistItemsResource.ListRequest itemRequest = SecretsVault.Service.PlaylistItems.List("snippet");
itemRequest.VideoId = item.Id;
foreach (Playlist i in response.Items)
{
itemRequest.PlaylistId = i.Id;
ToggleMenuFlyoutItem menuItem = new ToggleMenuFlyoutItem
{
Text = i.Snippet.Title,
IsChecked = (await itemRequest.ExecuteAsync()).Items.Count > 0,
Tag = i,
Icon = new FontIcon
{
Glyph = "\xE728"
}
};
menuItem.Click += Item_Click;
addList.Items.Add(menuItem);
}
}
catch
{ {
addTo.Visibility = Visibility.Collapsed; addTo.Visibility = Visibility.Collapsed;
return;
}
if (SecretsVault.WatchLater.Contains(item.Id))
(addList.Items[1] as ToggleMenuFlyoutItem).IsChecked = true;
PlaylistsResource.ListRequest request = SecretsVault.Service.Playlists.List("snippet");
request.Mine = true;
request.MaxResults = 50;
PlaylistListResponse response = await request.ExecuteAsync();
PlaylistItemsResource.ListRequest itemRequest = SecretsVault.Service.PlaylistItems.List("snippet");
itemRequest.VideoId = item.Id;
foreach (Playlist i in response.Items)
{
itemRequest.PlaylistId = i.Id;
ToggleMenuFlyoutItem menuItem = new ToggleMenuFlyoutItem
{
Text = i.Snippet.Title,
IsChecked = (await itemRequest.ExecuteAsync()).Items.Count > 0,
Tag = i,
Icon = new FontIcon
{
Glyph = "\xE728"
}
};
menuItem.Click += Item_Click;
addList.Items.Add(menuItem);
} }
} }
+3 -3
View File
@@ -124,10 +124,10 @@
<value>Contacts</value> <value>Contacts</value>
</data> </data>
<data name="crMe.Text" xml:space="preserve"> <data name="crMe.Text" xml:space="preserve">
<value>© 2018 Michael Gordeev</value> <value>© Michael Gordeev</value>
</data> </data>
<data name="crYt.Text" xml:space="preserve"> <data name="crYt.Text" xml:space="preserve">
<value>© 2018 YouTube, LLC</value> <value>© YouTube, LLC</value>
</data> </data>
<data name="developed.Text" xml:space="preserve"> <data name="developed.Text" xml:space="preserve">
<value>Developed by Michael Gordeev (also known as XFox)</value> <value>Developed by Michael Gordeev (also known as XFox)</value>
@@ -142,7 +142,7 @@
<value>Legal stuff</value> <value>Legal stuff</value>
</data> </data>
<data name="myBlog.Text" xml:space="preserve"> <data name="myBlog.Text" xml:space="preserve">
<value>My blog (Russian language only)</value> <value>My website</value>
</data> </data>
<data name="ourPrivacy.Content" xml:space="preserve"> <data name="ourPrivacy.Content" xml:space="preserve">
<value>Our Privacy Policy</value> <value>Our Privacy Policy</value>
+2 -2
View File
@@ -139,7 +139,7 @@
<value>Windows color settings</value> <value>Windows color settings</value>
</data> </data>
<data name="en.Content" xml:space="preserve"> <data name="en.Content" xml:space="preserve">
<value>English (United States of America)</value> <value>English (United States)</value>
</data> </data>
<data name="interfaceLang.Header" xml:space="preserve"> <data name="interfaceLang.Header" xml:space="preserve">
<value>App interface language</value> <value>App interface language</value>
@@ -187,7 +187,7 @@
<value>Reopen the app to apply changes (otherwise some elements may not be displayed correctly)</value> <value>Reopen the app to apply changes (otherwise some elements may not be displayed correctly)</value>
</data> </data>
<data name="ru.Content" xml:space="preserve"> <data name="ru.Content" xml:space="preserve">
<value>Russian (Russian Federation)</value> <value>Russian (Russia)</value>
</data> </data>
<data name="safeSearch.Header" xml:space="preserve"> <data name="safeSearch.Header" xml:space="preserve">
<value>SafeSearch</value> <value>SafeSearch</value>
+3 -3
View File
@@ -124,10 +124,10 @@
<value>Контакты</value> <value>Контакты</value>
</data> </data>
<data name="crMe.Text" xml:space="preserve"> <data name="crMe.Text" xml:space="preserve">
<value>© 2018 Михаил Гордеев</value> <value>© Михаил Гордеев</value>
</data> </data>
<data name="crYt.Text" xml:space="preserve"> <data name="crYt.Text" xml:space="preserve">
<value>© 2018 YouTube, LLC</value> <value>© YouTube, LLC</value>
</data> </data>
<data name="developed.Text" xml:space="preserve"> <data name="developed.Text" xml:space="preserve">
<value>Разработано Михаилом Гордеевым (также известным как XFox)</value> <value>Разработано Михаилом Гордеевым (также известным как XFox)</value>
@@ -142,7 +142,7 @@
<value>Юридический материал</value> <value>Юридический материал</value>
</data> </data>
<data name="myBlog.Text" xml:space="preserve"> <data name="myBlog.Text" xml:space="preserve">
<value>Мой блог</value> <value>Мой веб-сайт</value>
</data> </data>
<data name="ourPrivacy.Content" xml:space="preserve"> <data name="ourPrivacy.Content" xml:space="preserve">
<value>Наша политика конфиденциальности</value> <value>Наша политика конфиденциальности</value>
+2 -2
View File
@@ -139,7 +139,7 @@
<value>Цветовые настройки Windows</value> <value>Цветовые настройки Windows</value>
</data> </data>
<data name="en.Content" xml:space="preserve"> <data name="en.Content" xml:space="preserve">
<value>Английский (Соединенные Штаты Америки)</value> <value>Английский (США)</value>
</data> </data>
<data name="interfaceLang.Header" xml:space="preserve"> <data name="interfaceLang.Header" xml:space="preserve">
<value>Язык интерфейса</value> <value>Язык интерфейса</value>
@@ -187,7 +187,7 @@
<value>Перезапустите приложение, чтобы применить настройки (в противном случае некоторые элементы могут неправильно отображаться)</value> <value>Перезапустите приложение, чтобы применить настройки (в противном случае некоторые элементы могут неправильно отображаться)</value>
</data> </data>
<data name="ru.Content" xml:space="preserve"> <data name="ru.Content" xml:space="preserve">
<value>Русский (Российская Федерация)</value> <value>Русский (Россия)</value>
</data> </data>
<data name="safeSearch.Header" xml:space="preserve"> <data name="safeSearch.Header" xml:space="preserve">
<value>Безопасный поиск</value> <value>Безопасный поиск</value>
+1 -1
View File
@@ -41,6 +41,6 @@
<Style TargetType="ui:NavigationViewItemHeader"> <Style TargetType="ui:NavigationViewItemHeader">
<Setter Property="FontSize" Value="14"/> <Setter Property="FontSize" Value="14"/>
</Style> </Style>
<Duration x:Key="CardOpacityDuration">0:0:0.5</Duration> <Duration x:Key="CardOpacityDuration">0:0:0.3</Duration>
</ResourceDictionary> </ResourceDictionary>