diff --git a/FoxTube.Core/FoxTube.Core.csproj b/FoxTube.Core/FoxTube.Core.csproj
index 9f76189..a6b2923 100644
--- a/FoxTube.Core/FoxTube.Core.csproj
+++ b/FoxTube.Core/FoxTube.Core.csproj
@@ -132,26 +132,28 @@
+
+
-
+
+
+
-
-
@@ -163,22 +165,25 @@
1.0.3
- 1.45.0
+ 1.46.0
+
+
+ 1.46.0.1986
1.44.1.1869
- 1.45.0.1929
+ 1.46.0.1987
10.1811.22001
- 3.2.1
+ 3.2.2
- 3.2.1
+ 3.2.2
6.2.10
@@ -186,11 +191,14 @@
10.1901.28001
-
- 2.4.0
+
+ 6.0.0
+
+
+ 1.0.0
- 5.0.4
+ 5.0.5
diff --git a/FoxTube.Core/Models/Collections/InboxCollection.cs b/FoxTube.Core/Models/Collections/InboxCollection.cs
index c3a5089..2c87f6a 100644
--- a/FoxTube.Core/Models/Collections/InboxCollection.cs
+++ b/FoxTube.Core/Models/Collections/InboxCollection.cs
@@ -1,45 +1,49 @@
-using Newtonsoft.Json;
+using System;
using System.Threading.Tasks;
-using System.Net.Http;
using Windows.UI.Xaml.Data;
using FoxTube.Services;
using FoxTube.Utils;
+using Google.Apis.Blogger.v3;
+using Google.Apis.Blogger.v3.Data;
namespace FoxTube.Models.Collections
{
- public class InboxCollection : ViewCollection
+ public class InboxCollection : ViewCollection
{
- private int _pageNumber = 0;
- private HttpClient _httpClient = new HttpClient();
+ private string nextPageToken;
public override async Task LoadItems()
{
- // TODO: Add backend
- HttpResponseMessage response = await _httpClient.GetAsync($"https://xfox111.net/API/FoxTube/Inbox?" +
- $"lang={Storage.GetValue(Storage.Settings.UILanguage)}&" +
- $"currentVersion={Metrics.CurrentVersion}&" +
- $"itemsCount={ItemsPerRequest}&" +
- $"iteration={_pageNumber}");
-
- if (!response.IsSuccessStatusCode || response.StatusCode == System.Net.HttpStatusCode.NoContent)
+ try
{
+ PostsResource.ListRequest request = InboxService.Service.Posts.List(SecretConstants.BlogId);
+ request.FetchImages = false;
+ request.PageToken = nextPageToken;
+ request.Labels = "FoxTube";
+ request.MaxResults = ItemsPerRequest;
+ request.OrderBy = PostsResource.ListRequest.OrderByEnum.UPDATED;
+
+ PostList response = await request.ExecuteAsync();
+
+ foreach (Post post in response.Items)
+ Items.Add(post);
+
+ HasMoreItems = !string.IsNullOrWhiteSpace(nextPageToken = response.NextPageToken);
+
+ return new LoadMoreItemsResult
+ {
+ Count = (uint)response.Items.Count
+ };
+ }
+ catch (Exception e)
+ {
+ Metrics.SendReport(new Exception("Unable to load inbox", e));
HasMoreItems = false;
return new LoadMoreItemsResult
{
Count = 0
};
}
-
- InboxItem[] newItems = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync());
- foreach (InboxItem item in newItems)
- Items.Add(item);
-
- _pageNumber++;
-
- return new LoadMoreItemsResult
- {
- Count = (uint)newItems.Length
- };
}
}
}
diff --git a/FoxTube.Core/Models/Collections/ViewCollection.cs b/FoxTube.Core/Models/Collections/ViewCollection.cs
index 1ee2372..94cbfa9 100644
--- a/FoxTube.Core/Models/Collections/ViewCollection.cs
+++ b/FoxTube.Core/Models/Collections/ViewCollection.cs
@@ -8,7 +8,7 @@ namespace FoxTube.Models.Collections
{
public abstract class ViewCollection : ObservableCollection, ISupportIncrementalLoading
{
- public int ItemsPerRequest { get; set; }
+ public int ItemsPerRequest { get; set; } = 25;
public bool HasMoreItems { get; protected set; } = true;
public IAsyncOperation LoadMoreItemsAsync(uint count) =>
diff --git a/FoxTube.Core/Models/InboxItem.cs b/FoxTube.Core/Models/InboxItem.cs
deleted file mode 100644
index ab281b9..0000000
--- a/FoxTube.Core/Models/InboxItem.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-using System;
-
-namespace FoxTube.Models
-{
- public class InboxItem
- {
- public string Id { get; set; }
-
- public string DefaultIcon { get; set; }
- public string Avatar { get; set; }
-
- public string Title { get; set; }
- public string Description { get; set; }
- public string Content { get; set; }
-
- public DateTime TimeStamp { get; set; }
- public string Type { get; set; }
-
- public string ShortTimeStamp => $"{TimeStamp.ToShortDateString()} {TimeStamp.ToShortTimeString()}";
- }
-}
\ No newline at end of file
diff --git a/FoxTube.Core/Models/SearchParameters.cs b/FoxTube.Core/Models/SearchParameters.cs
new file mode 100644
index 0000000..2f4e77f
--- /dev/null
+++ b/FoxTube.Core/Models/SearchParameters.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FoxTube.Models
+{
+ public class SearchParameters
+ {
+ public SearchParameters(string query)
+ {
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/FoxTube.Core/Models/User.cs b/FoxTube.Core/Models/User.cs
index 11f0850..4c4ea92 100644
--- a/FoxTube.Core/Models/User.cs
+++ b/FoxTube.Core/Models/User.cs
@@ -5,12 +5,10 @@ using Google.Apis.Oauth2.v2.Data;
using Google.Apis.Services;
using Google.Apis.YouTube.v3;
using Google.Apis.YouTube.v3.Data;
-using Newtonsoft.Json;
using System;
using System.Linq;
using System.Collections.Generic;
using System.Threading.Tasks;
-using Windows.Storage;
using YouTube;
using YoutubeExplode;
using FoxTube.Services;
@@ -42,8 +40,6 @@ namespace FoxTube.Models
UserService.SubscriptionsChangedInvoker(this, subscription);
Subscriptions.Remove(subscription);
-
- SaveSubscriptions();
return false;
}
else
@@ -79,21 +75,10 @@ namespace FoxTube.Models
Subscriptions.Add(subscription);
UserService.SubscriptionsChangedInvoker(this, subscription);
-
- SaveSubscriptions();
return true;
}
}
- private void SaveSubscriptions()
- {
- Dictionary subs = Subscriptions.Select(i =>
- new KeyValuePair(i.ChannelId, i.Avatar.Default__?.Url))
- as Dictionary;
-
- ApplicationData.Current.RoamingSettings.Values[$"Subscriptions.{UserInfo.Id}"] = JsonConvert.SerializeObject(subs);
- }
-
public static async Task GetUser(UserCredential credential)
{
User user = new User
diff --git a/FoxTube.Core/Models/VideoItem.cs b/FoxTube.Core/Models/VideoItem.cs
deleted file mode 100644
index a86caff..0000000
--- a/FoxTube.Core/Models/VideoItem.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-using FoxTube.Services;
-using Google.Apis.YouTube.v3.Data;
-using System;
-using YoutubeExplode;
-
-namespace FoxTube.Models
-{
- public class VideoItem
- {
- public Video Meta { get; set; }
- public YoutubeExplode.Videos.Video AdditionalMeta { get; set; }
- public YoutubeExplode.Channels.Channel ChannelMeta { get; set; }
-
- public string TimeLabel { get; set; }
- public string ViewsLabel { get; set; }
- public int LiveLabelOpacity => Meta?.LiveStreamingDetails == null ? 0 : 1;
- public string LiveLabel
- {
- get
- {
- if (Meta?.LiveStreamingDetails == null)
- return "";
- else if (Meta.LiveStreamingDetails.ActualStartTime.HasValue)
- return "LIVE";
- else if (Meta.LiveStreamingDetails.ScheduledStartTime.HasValue)
- return $"Live in {Meta.LiveStreamingDetails.ScheduledStartTime - DateTime.Now}";
- else
- return "Upcoming";
- }
- }
-
- public VideoItem(Video meta)
- {
- Meta = meta;
- LoadInfo();
- }
-
- private async void LoadInfo()
- {
- YoutubeClient client = new YoutubeClient(UserService.Service.HttpClient);
-
- AdditionalMeta = await client.Videos.GetAsync(Meta.Id);
- ChannelMeta = await client.Channels.GetByVideoAsync(Meta.Id);
-
- TimeLabel = $"{AdditionalMeta?.Duration} • {AdditionalMeta.UploadDate.DateTime.GetFriendlyDate()}";
- ViewsLabel = $"{AdditionalMeta?.Engagement.ViewCount} views";
- }
- }
-}
\ No newline at end of file
diff --git a/FoxTube.Core/Services/DownloadsService.cs b/FoxTube.Core/Services/DownloadsService.cs
index 221b434..7f307ed 100644
--- a/FoxTube.Core/Services/DownloadsService.cs
+++ b/FoxTube.Core/Services/DownloadsService.cs
@@ -18,12 +18,9 @@ namespace FoxTube.Services
public static List History { get; } = new List();
public static List Queue { get; } = new List();
- static DownloadsService() =>
- Initialize();
-
- private static async void Initialize()
+ public static async Task Initialize()
{
- StorageFile file = await Storage.Folder.CreateFileAsync("DownloadHistory.json", CreationCollisionOption.OpenIfExists);
+ StorageFile file = await StorageService.Folder.CreateFileAsync("DownloadHistory.json", CreationCollisionOption.OpenIfExists);
try
{
List savedVideos = JsonConvert.DeserializeObject>(File.ReadAllText(file.Path) ?? "") ?? new List();
@@ -70,7 +67,7 @@ namespace FoxTube.Services
History.Add(savedItem);
- StorageFile file = await Storage.Folder.CreateFileAsync("DownloadHistory.json", CreationCollisionOption.OpenIfExists);
+ StorageFile file = await StorageService.Folder.CreateFileAsync("DownloadHistory.json", CreationCollisionOption.OpenIfExists);
File.WriteAllText(file.Path, JsonConvert.SerializeObject(History));
}
catch (OperationCanceledException) { }
@@ -112,7 +109,7 @@ namespace FoxTube.Services
public static async Task GetDefaultDownloadsFolder()
{
- if (Storage.GetValue(Storage.Settings.DefaultDownloadsFolder) is string token && !string.IsNullOrWhiteSpace(token))
+ if (SettingsService.DefaultDownloadsFolder is string token && !string.IsNullOrWhiteSpace(token))
return await StorageApplicationPermissions.FutureAccessList.GetFolderAsync(token) ??
await KnownFolders.VideosLibrary.CreateFolderAsync("FoxTube", CreationCollisionOption.OpenIfExists);
else
@@ -137,12 +134,12 @@ namespace FoxTube.Services
if (folder != null)
{
- if (Storage.GetValue(Storage.Settings.DefaultDownloadsFolder) is string token && !string.IsNullOrWhiteSpace(token))
+ if (SettingsService.DefaultDownloadsFolder is string token && !string.IsNullOrWhiteSpace(token))
StorageApplicationPermissions.FutureAccessList.AddOrReplace(token, folder);
else
{
token = StorageApplicationPermissions.FutureAccessList.Add(folder);
- Storage.SetValue(Storage.Settings.DefaultDownloadsFolder, token);
+ SettingsService.DefaultDownloadsFolder = token;
}
}
diff --git a/FoxTube.Core/Services/InboxService.cs b/FoxTube.Core/Services/InboxService.cs
index ef3cbc4..3338ec6 100644
--- a/FoxTube.Core/Services/InboxService.cs
+++ b/FoxTube.Core/Services/InboxService.cs
@@ -1,18 +1,24 @@
using FoxTube.Models.Collections;
using FoxTube.Utils;
-using Newtonsoft.Json;
using System;
-using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Windows.UI.Notifications;
+using Google.Apis.Blogger.v3;
+using Google.Apis.Blogger.v3.Data;
+using System.Linq;
+using System.Globalization;
+using Windows.Foundation.Metadata;
namespace FoxTube.Services
{
public static class InboxService
{
- public const string lastChangelogVersionKey = "Inbox.lastChangelogVersion";
- public const string lastCheckKey = "Inbox.lastChangelogVersion";
+ public static BloggerService Service { get; } = new BloggerService(new Google.Apis.Services.BaseClientService.Initializer
+ {
+ ApplicationName = "FoxTube",
+ ApiKey = SecretConstants.BloggerApiKey
+ });
private static readonly HttpClient client = new HttpClient();
@@ -23,22 +29,19 @@ namespace FoxTube.Services
{
try
{
- // TODO: Add backend
- HttpResponseMessage response = await client.GetAsync($"https://xfox111.net/FoxTube/Inbox?" +
- $"toast=true&" +
- $"publishedAfter={Storage.Registry.Values[lastCheckKey]}&" +
- $"lang={Storage.GetValue(Storage.Settings.UILanguage)}&" +
- $"appVersion={Metrics.CurrentVersion}");
+ PostsResource.ListRequest request = Service.Posts.List(SecretConstants.BlogId);
+ request.FetchImages = false;
+ request.Labels = "FoxTube";
+ request.MaxResults = 500;
+ request.StartDate = StorageService.LastInboxCheck.ToString("yyyy-MM-dd'T'HH:mm:ss.fffK", DateTimeFormatInfo.InvariantInfo);
+ request.OrderBy = PostsResource.ListRequest.OrderByEnum.UPDATED;
- Storage.Registry.Values[lastCheckKey] = DateTime.UtcNow.Ticks;
+ PostList response = await request.ExecuteAsync();
- if (response.StatusCode == HttpStatusCode.NoContent)
- return;
+ foreach(Post post in response.Items.Where(i => !i.Labels.Contains("Changelog")))
+ ToastNotificationManager.CreateToastNotifier().Show(ToastTemplates.GetBlogpostToast(post));
- string[] toasts = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync());
-
- foreach (string toast in toasts)
- ToastNotificationManager.CreateToastNotifier().Show(new ToastNotification(toast.ToXml()));
+ StorageService.LastInboxCheck = DateTime.UtcNow;
}
catch (Exception e)
{
@@ -46,27 +49,33 @@ namespace FoxTube.Services
}
}
+ // TODO: Add changelog retrieval
///
/// Fires toast notification with the last changelog content
///
+ [Deprecated("In future versions it will be replaced with splash screen full size message", DeprecationType.Deprecate, 1)]
public static async void PushChangelog()
{
try
{
- // TODO: Add backend
- if ((string)Storage.Registry.Values[lastChangelogVersionKey] == Metrics.CurrentVersion)
+ if (string.IsNullOrWhiteSpace(StorageService.LastOpenedVersion))
+ StorageService.LastOpenedVersion = Metrics.CurrentVersion;
+
+ string lastVersion = StorageService.LastOpenedVersion;
+ if (string.IsNullOrWhiteSpace(lastVersion) || lastVersion == Metrics.CurrentVersion)
return;
- Storage.Registry.Values[lastChangelogVersionKey] = Metrics.CurrentVersion;
+ PostsResource.ListRequest request = Service.Posts.List(SecretConstants.BlogId);
+ request.FetchImages = false;
+ request.Labels = $"FoxTube,Changelog,v{Metrics.CurrentVersion}";
+ request.MaxResults = 1;
- HttpResponseMessage response = await client.GetAsync($"https://xfox111.net/API/FoxTube/Changelog?" +
- $"lang={Storage.GetValue(Storage.Settings.UILanguage)}&" +
- $"version={Metrics.CurrentVersion}");
+ PostList response = await request.ExecuteAsync();
- if (response.StatusCode == HttpStatusCode.NoContent)
- return;
+ if (response.Items.Count > 0)
+ ToastNotificationManager.CreateToastNotifier().Show(ToastTemplates.GetBlogpostToast(response.Items.First()));
- ToastNotificationManager.CreateToastNotifier().Show(new ToastNotification((await response.Content.ReadAsStringAsync()).ToXml()));
+ StorageService.LastOpenedVersion = Metrics.CurrentVersion;
}
catch (Exception e)
{
diff --git a/FoxTube.Core/Services/Search.cs b/FoxTube.Core/Services/Search.cs
index 17f3d00..7b48e6b 100644
--- a/FoxTube.Core/Services/Search.cs
+++ b/FoxTube.Core/Services/Search.cs
@@ -16,7 +16,12 @@ namespace FoxTube.Services
try
{
using HttpClient client = new HttpClient();
- string results = await client.GetStringAsync($"http://suggestqueries.google.com/complete/search?ds=yt&client=toolbar&q={term}&hl={Storage.GetValue(Storage.Settings.RelevanceLanguage)}");
+ string results = await client.GetStringAsync($"http://suggestqueries.google.com/complete/search?" +
+ $"ds=yt&" +
+ $"client=toolbar&" +
+ $"q={term}&" +
+ $"hl={SettingsService.RelevanceLanguage}");
+
XmlDocument doc = new XmlDocument();
doc.LoadXml(results);
diff --git a/FoxTube.Core/Services/SettingsService.cs b/FoxTube.Core/Services/SettingsService.cs
new file mode 100644
index 0000000..41cb82d
--- /dev/null
+++ b/FoxTube.Core/Services/SettingsService.cs
@@ -0,0 +1,67 @@
+using Windows.Storage;
+using System.Globalization;
+using System.Diagnostics;
+using Windows.UI.Xaml;
+
+namespace FoxTube.Services
+{
+ public class SettingsService
+ {
+ private static readonly ApplicationDataContainer storage = ApplicationData.Current.RoamingSettings;
+
+ public static void ResetSettings() =>
+ storage.Values.Clear();
+
+ public static ElementTheme Theme
+ {
+ get => (ElementTheme)GetValue(ElementTheme.Default);
+ set => SetValue((int)value);
+ }
+
+ public static string RelevanceLanguage
+ {
+ get => GetValue(GetDefaultLanguage());
+ set => SetValue(value);
+ }
+
+ public static bool AllowAnalytics
+ {
+ get => GetValue(true);
+ set => SetValue(value);
+ }
+
+ public static bool AskEveryDownload
+ {
+ get => GetValue(true);
+ set => SetValue(value);
+ }
+
+ public static string DefaultDownloadsFolder
+ {
+ get => GetValue(null);
+ set => SetValue(value);
+ }
+
+ #region Service methods
+ private static string GetDefaultLanguage()
+ {
+ if (CultureInfo.InstalledUICulture.TwoLetterISOLanguageName.Belongs("ua", "ru", "by", "kz", "kg", "md", "lv", "ee")) // Languages for Russian-speaking countries
+ return "ru-RU";
+ else
+ return "en-US";
+ }
+
+ private static dynamic GetValue(object defaultValue)
+ {
+ string propName = (new StackTrace()).GetFrame(1).GetMethod().Name.Substring(4);
+ return storage.Values[$"Settings.{propName}"] ?? defaultValue;
+ }
+
+ private static void SetValue(object value)
+ {
+ string propName = (new StackTrace()).GetFrame(1).GetMethod().Name.Substring(4);
+ storage.Values[$"Settings.{propName}"] = value;
+ }
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/FoxTube.Core/Services/Storage.cs b/FoxTube.Core/Services/Storage.cs
deleted file mode 100644
index 3f373e6..0000000
--- a/FoxTube.Core/Services/Storage.cs
+++ /dev/null
@@ -1,101 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.Threading.Tasks;
-using Windows.Storage;
-using Windows.UI.Xaml;
-
-namespace FoxTube.Services
-{
- public static class Storage
- {
- public static event EventHandler SettingsChanged;
-
- public static StorageFolder Folder => ApplicationData.Current.RoamingFolder;
- public static ApplicationDataContainer Registry { get; } = ApplicationData.Current.RoamingSettings;
-
- private static readonly Dictionary _defaultSettings = new Dictionary
- {
- { Settings.Theme, ElementTheme.Default },
- { Settings.UILanguage, GetDefaultLanguage() },
- { Settings.RelevanceLanguage, GetDefaultLanguage() },
- { Settings.PromptFeedback, true },
- { Settings.PromptReview, true },
- { Settings.AllowAnalytics, true }
- };
-
- public enum Settings
- {
- ///
- /// ElementTheme
- ///
- Theme,
- ///
- /// string
- ///
- UILanguage,
- ///
- /// string
- ///
- RelevanceLanguage,
- ///
- /// string
- ///
- DefaultDownloadsFolder,
- ///
- /// bool
- ///
- PromptFeedback,
- ///
- /// bool
- ///
- PromptReview,
- ///
- /// bool
- ///
- AllowAnalytics,
- ///
- /// string
- ///
- Region
- }
-
- public enum Metrics
- {
- ///
- /// TimeSpan
- ///
- Uptime
- }
-
-
- public static void SetValue(Settings key, object value)
- {
- Registry.Values[$"{key.GetType().Name}.{key}"] = value;
- SettingsChanged?.Invoke(value, key);
- }
- public static void SetValue(Metrics key, object value) =>
- Registry.Values[$"{key.GetType().Name}.{key}"] = value;
-
- public static T GetValue(Settings key) =>
- (T)(Registry.Values[$"{key.GetType().Name}.{key}"] ?? (_defaultSettings.ContainsKey(key) ? _defaultSettings[key] : null));
- public static T GetValue(Metrics key) =>
- (T)Registry.Values[$"{key.GetType().Name}.{key}"];
-
-
- private static string GetDefaultLanguage()
- {
- if (CultureInfo.InstalledUICulture.TwoLetterISOLanguageName.Belongs("ua", "ru", "by", "kz", "kg", "md", "lv", "ee")) //Languages for Russian-speaking countries
- return "ru-RU";
- else
- return "en-US";
- }
-
- public static async Task ResetStorage()
- {
- Registry.Values.Clear();
- foreach (IStorageItem i in await Folder.GetItemsAsync())
- await i.DeleteAsync();
- }
- }
-}
\ No newline at end of file
diff --git a/FoxTube.Core/Services/StorageService.cs b/FoxTube.Core/Services/StorageService.cs
new file mode 100644
index 0000000..1ff8286
--- /dev/null
+++ b/FoxTube.Core/Services/StorageService.cs
@@ -0,0 +1,77 @@
+using System;
+using System.Diagnostics;
+using System.Threading.Tasks;
+using Windows.Storage;
+
+namespace FoxTube.Services
+{
+ public static class StorageService
+ {
+ private static readonly ApplicationDataContainer storage = ApplicationData.Current.RoamingSettings;
+
+ public static StorageFolder Folder => ApplicationData.Current.RoamingFolder;
+
+ public static bool PromptFeedback
+ {
+ get => GetValue(Uptime.TotalHours > 12);
+ set => SetValue(value);
+ }
+
+ public static bool PromptReview
+ {
+ get => GetValue(Uptime.TotalHours > 24);
+ set => SetValue(value);
+ }
+
+ public static TimeSpan Uptime
+ {
+ get => GetValue(TimeSpan.FromSeconds(0));
+ set => SetValue(value);
+ }
+
+ public static DateTime LastInboxCheck
+ {
+ get => GetValue(DateTime.UtcNow);
+ set => SetValue(value);
+ }
+
+ public static string LastOpenedVersion
+ {
+ get => GetValue(null);
+ set => SetValue(value);
+ }
+
+ public static int? LastUserIndex
+ {
+ get => GetValue(null);
+ set => SetValue(value);
+ }
+
+ public static string UserInfos
+ {
+ get => GetValue(null);
+ set => SetValue(value);
+ }
+
+ public static async Task ClearStorage()
+ {
+ storage.Values.Clear();
+ foreach (IStorageItem i in await Folder.GetItemsAsync())
+ await i.DeleteAsync();
+ }
+
+ #region Service methods
+ private static dynamic GetValue(object defaultValue)
+ {
+ string propName = (new StackTrace()).GetFrame(1).GetMethod().Name.Substring(4);
+ return storage.Values[$"Storage.{propName}"] ?? defaultValue;
+ }
+
+ private static void SetValue(object value)
+ {
+ string propName = (new StackTrace()).GetFrame(1).GetMethod().Name.Substring(4);
+ storage.Values[$"Storage.{propName}"] = value;
+ }
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/FoxTube.Core/Services/UserService.cs b/FoxTube.Core/Services/UserService.cs
index d0b4aec..66384e4 100644
--- a/FoxTube.Core/Services/UserService.cs
+++ b/FoxTube.Core/Services/UserService.cs
@@ -20,9 +20,6 @@ namespace FoxTube.Services
{
public static class UserService
{
- public const string UsersStorageKey = "UserService.Users";
- public const string LastUserInfoKey = "UserService.LastUser";
-
public const int MaxUsersCount = 1;
#region Private members
@@ -74,9 +71,6 @@ namespace FoxTube.Services
public static event EventHandler UserStateUpdated;
public static event EventHandler SubscriptionsChanged;
- static UserService() =>
- Initialize();
-
public static async Task AddUser()
{
int queueIndex = Users.ToList().FindIndex(i => i == null);
@@ -117,10 +111,10 @@ namespace FoxTube.Services
return false;
}
- public static async void Initialize()
+ public static async Task Initialize()
{
- Users = JsonConvert.DeserializeObject(Storage.Registry.Values[UsersStorageKey] as string ?? "") ?? new Userinfoplus[MaxUsersCount];
- int? lastUserIndex = Storage.Registry.Values[LastUserInfoKey] as int?;
+ Users = JsonConvert.DeserializeObject(StorageService.UserInfos ?? "") ?? new Userinfoplus[MaxUsersCount];
+ int? lastUserIndex = StorageService.LastUserIndex;
if (lastUserIndex.HasValue && Users[lastUserIndex.Value] != null ||
(lastUserIndex = Users.ToList().FindIndex(i => i != null)) > -1)
@@ -146,12 +140,11 @@ namespace FoxTube.Services
await CurrentUser.Credential.RevokeTokenAsync(CancellationToken.None);
- Storage.Registry.Values.Remove($"Subscriptions.{CurrentUser.UserInfo.Id}");
CurrentUser = null;
Users[Users.ToList().FindIndex(i => i.Id == userId)] = null;
- Storage.Registry.Values[UsersStorageKey] = JsonConvert.SerializeObject(Users);
- Storage.Registry.Values[LastUserInfoKey] = null;
+ StorageService.UserInfos = JsonConvert.SerializeObject(Users);
+ StorageService.LastUserIndex = null;
if (Users.Any(i => i != null))
await SwitchUser(Users.ToList().FindIndex(i => i != null));
@@ -202,8 +195,8 @@ namespace FoxTube.Services
CurrentUser = await User.GetUser(credential);
Users[userIndex] = CurrentUser.UserInfo;
- Storage.Registry.Values[UsersStorageKey] = JsonConvert.SerializeObject(Users);
- Storage.Registry.Values[LastUserInfoKey] = userIndex;
+ StorageService.UserInfos = JsonConvert.SerializeObject(Users);
+ StorageService.LastUserIndex = userIndex;
credential.RefreshTokenUpdated += (s, e) => UpdateToken(CurrentUser.UserInfo.Id, credential.Token.RefreshToken);
UpdateToken(CurrentUser.UserInfo.Id, credential.Token.RefreshToken);
diff --git a/FoxTube.Core/Utils/AddonsInterop.cs b/FoxTube.Core/Utils/AddonsInterop.cs
index 66a13d1..1fd8d86 100644
--- a/FoxTube.Core/Utils/AddonsInterop.cs
+++ b/FoxTube.Core/Utils/AddonsInterop.cs
@@ -18,18 +18,15 @@ namespace FoxTube.Utils
public static NativeAdsManagerV2 AdsManager => new NativeAdsManagerV2(ApplicationId, AdsId);
- static AddonsInterop() =>
- UpdateStoreState();
-
- public static async void UpdateStoreState()
+ public static async Task UpdateProPurchasedState()
{
StoreProductQueryResult requset = await StoreContext.GetDefault().GetAssociatedStoreProductsAsync(new[] { "Durable" });
if (requset.Products[ProProductId].IsInUserCollection)
- return;
+ return AdsDisabled = true;
Price = requset.Products[ProProductId].Price.FormattedPrice;
- AdsDisabled = false;
+ return AdsDisabled = false;
}
public static async Task PurchaseApp()
diff --git a/FoxTube.Core/Utils/BackgroundManager.cs b/FoxTube.Core/Utils/BackgroundManager.cs
new file mode 100644
index 0000000..94a953a
--- /dev/null
+++ b/FoxTube.Core/Utils/BackgroundManager.cs
@@ -0,0 +1,64 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Windows.ApplicationModel.Activation;
+using Windows.ApplicationModel.Background;
+using Windows.System.Power;
+using Windows.UI.Notifications;
+
+namespace FoxTube.Utils
+{
+ // TODO: Complete class
+ public static class BackgroundManager
+ {
+ public static async Task PerformBackgroundTask(BackgroundActivatedEventArgs args)
+ {
+
+ if (args.TaskInstance.TriggerDetails is ToastNotificationActionTriggerDetail details)
+ {
+ ProcessBackgroundAction(details.Argument);
+ // TODO: Process toast parameters
+ }
+ else
+ {
+ // TODO: Restore user
+ // TODO: Update subscriptions
+ // TODO: Update homepage cache
+ }
+
+ //var saverRequest = PowerManager.EnergySaverStatus;
+ }
+
+ public static async Task ProcessBackgroundAction(string uri)
+ {
+
+ }
+
+ public static async void RegisterBackgroundTasks()
+ {
+ var backgroundRequest = await BackgroundExecutionManager.RequestAccessAsync();
+ if (backgroundRequest == BackgroundAccessStatus.DeniedBySystemPolicy || backgroundRequest == BackgroundAccessStatus.DeniedByUser)
+ return;
+
+ RegisterBackgoundTask("FoxtubeToastBackground", new ToastNotificationActionTrigger());
+ RegisterBackgoundTask("FoxtubeBackground", new TimeTrigger(15, false));
+ }
+
+ private static void RegisterBackgoundTask(string taskName, IBackgroundTrigger trigger)
+ {
+ if (BackgroundTaskRegistration.AllTasks.Any(i => i.Value.Name.Equals(taskName)))
+ return;
+
+ BackgroundTaskBuilder builder = new BackgroundTaskBuilder
+ {
+ Name = taskName,
+ IsNetworkRequested = true
+ };
+ builder.SetTrigger(trigger);
+
+ BackgroundTaskRegistration registration = builder.Register();
+ }
+ }
+}
diff --git a/FoxTube.Core/Utils/FeedbackIterop.cs b/FoxTube.Core/Utils/FeedbackIterop.cs
index 8820bc9..bae5b12 100644
--- a/FoxTube.Core/Utils/FeedbackIterop.cs
+++ b/FoxTube.Core/Utils/FeedbackIterop.cs
@@ -33,7 +33,7 @@ namespace FoxTube.Utils
{
if (!HasFeedbackHub)
{
- Storage.SetValue(Storage.Settings.PromptFeedback, false);
+ StorageService.PromptFeedback = false;
return;
}
@@ -53,7 +53,7 @@ namespace FoxTube.Utils
ContentDialogResult result = await dialog.ShowAsync();
if (result != ContentDialogResult.None)
- Storage.SetValue(Storage.Settings.PromptFeedback, false);
+ StorageService.PromptFeedback = false;
if (result == ContentDialogResult.Primary)
OpenFeedbackHub();
@@ -80,7 +80,7 @@ namespace FoxTube.Utils
ContentDialogResult result = await dialog.ShowAsync();
if (result != ContentDialogResult.None)
- Storage.SetValue(Storage.Settings.PromptReview, false);
+ StorageService.PromptFeedback = false;
if (result == ContentDialogResult.Primary)
RequestStoreReview();
diff --git a/FoxTube.Core/Utils/Metrics.cs b/FoxTube.Core/Utils/Metrics.cs
index 8e296cd..c08227f 100644
--- a/FoxTube.Core/Utils/Metrics.cs
+++ b/FoxTube.Core/Utils/Metrics.cs
@@ -5,8 +5,8 @@ using System;
using System.Linq;
using System.Collections.Generic;
using System.Diagnostics;
-using Windows.ApplicationModel;
using FoxTube.Services;
+using System.Globalization;
namespace FoxTube.Utils
{
@@ -15,26 +15,29 @@ namespace FoxTube.Utils
static readonly Stopwatch sw = new Stopwatch();
public static TimeSpan Uptime
{
- get => Storage.GetValue(Storage.Metrics.Uptime) ?? TimeSpan.FromSeconds(0);
- set => Storage.SetValue(Storage.Metrics.Uptime, value);
+ get => StorageService.Uptime;
+ set => StorageService.Uptime = value;
}
+
public static string CurrentVersion
{
get
{
- PackageVersion v = Package.Current.Id.Version;
- return $"{v.Major}.{v.Minor}.{v.Revision}.{v.Build}";
+ // TODO: Remove on release
+ /*PackageVersion v = Package.Current.Id.Version;
+ return $"{v.Major}.{v.Minor}.{v.Revision}.{v.Build}";*/
+ return "2.0 Preview 1";
}
}
static Metrics()
{
sw.Start();
- if (!Storage.GetValue(Storage.Settings.AllowAnalytics))
+ if (!SettingsService.AllowAnalytics)
return;
AppCenter.Start(SecretConstants.MetricsId, typeof(Analytics), typeof(Crashes));
- AppCenter.SetCountryCode(Storage.GetValue(Storage.Settings.Region));
+ AppCenter.SetCountryCode(RegionInfo.CurrentRegion.TwoLetterISORegionName);
AppCenter.LogLevel = LogLevel.Verbose;
}
@@ -43,7 +46,7 @@ namespace FoxTube.Utils
sw.Stop();
Uptime += sw.Elapsed;
- if (Storage.GetValue(Storage.Settings.AllowAnalytics))
+ if (SettingsService.AllowAnalytics)
AddEvent("Session closed",
("Duration", sw.Elapsed.ToString()),
("Spend time total", Uptime.ToString()));
@@ -51,7 +54,7 @@ namespace FoxTube.Utils
public static void AddEvent(string eventName, params (string key, string value)[] details)
{
- if (Storage.GetValue(Storage.Settings.AllowAnalytics))
+ if (SettingsService.AllowAnalytics)
Analytics.TrackEvent(eventName,
details.Length < 1 ? null :
details.Select(i => new KeyValuePair(i.key, i.value)) as Dictionary);
@@ -59,7 +62,7 @@ namespace FoxTube.Utils
public static void SendReport(Exception exception, ErrorAttachmentLog[] logs = null, params (string key, string value)[] details)
{
- if (Storage.GetValue(Storage.Settings.AllowAnalytics))
+ if (SettingsService.AllowAnalytics)
{
logs ??= new ErrorAttachmentLog[0];
Crashes.TrackError(exception ?? new Exception("Unknown exception"),
diff --git a/FoxTube.Core/Utils/SecretConstants.cs b/FoxTube.Core/Utils/SecretConstants.cs
index b3d3b39..3ff1d7d 100644
--- a/FoxTube.Core/Utils/SecretConstants.cs
+++ b/FoxTube.Core/Utils/SecretConstants.cs
@@ -11,6 +11,8 @@ namespace FoxTube.Utils
public static class SecretConstants
{
public const string YoutubeApiKey = "AIzaSyBgHrCnrlzlVmk0cJKL8RqP9Y8x6XSuk_0";
+ public const string BloggerApiKey = "AIzaSyD7tpbuvmYDv9h4udo9L_g3r0sLPFAnN00";
+ public const string BlogId = "8566398713922921363";
public const string MetricsId = "45774462-9ea7-438a-96fc-03982666f39e";
public const string ProAddonId = "9NP1QK556625";
public const string AdsUnitId = "1100044398";
diff --git a/FoxTube.Core/Utils/ToastTemplates.cs b/FoxTube.Core/Utils/ToastTemplates.cs
new file mode 100644
index 0000000..b658e60
--- /dev/null
+++ b/FoxTube.Core/Utils/ToastTemplates.cs
@@ -0,0 +1,51 @@
+using System.Linq;
+using Microsoft.Toolkit.Uwp.Notifications;
+using Google.Apis.Blogger.v3.Data;
+using Windows.UI.Notifications;
+using AngleSharp.Html.Parser;
+
+namespace FoxTube.Utils
+{
+ public static class ToastTemplates
+ {
+ public static ToastNotification GetBlogpostToast(Post post)
+ {
+ ToastContent toastContent = new ToastContent
+ {
+ Visual = new ToastVisual
+ {
+ BindingGeneric = new ToastBindingGeneric
+ {
+ Children =
+ {
+ new AdaptiveText
+ {
+ Text = new BindableString(post.Title)
+ },
+ new AdaptiveText()
+ {
+ Text = new BindableString(new HtmlParser().ParseDocument(post.Content).QuerySelector("p").TextContent),
+ HintMaxLines = 2
+ }
+ },
+ AppLogoOverride = new ToastGenericAppLogo
+ {
+ Source = post.Author.Image.Url,
+ HintCrop = ToastGenericAppLogoCrop.Circle
+ }
+ }
+ },
+ Launch = $"Settings/Inbox/{post.Id}",
+ ActivationType = ToastActivationType.Foreground
+ };
+
+ if (post.Images.Count > 0)
+ toastContent.Visual.BindingGeneric.HeroImage = new ToastGenericHeroImage
+ {
+ Source = post.Images.FirstOrDefault()?.Url
+ };
+
+ return new ToastNotification(toastContent.GetXml());
+ }
+ }
+}
diff --git a/FoxTube.Core/Utils/Utils.cs b/FoxTube.Core/Utils/Utils.cs
index c3de3c6..089222a 100644
--- a/FoxTube.Core/Utils/Utils.cs
+++ b/FoxTube.Core/Utils/Utils.cs
@@ -2,6 +2,8 @@
using System;
using Windows.ApplicationModel.Core;
using Windows.Security.Credentials;
+using Windows.UI;
+using Windows.UI.ViewManagement;
namespace FoxTube.Utils
{
@@ -29,11 +31,36 @@ namespace FoxTube.Utils
public static async void InitializeFailsafeProtocol()
{
Metrics.AddEvent("Failsafe protocol initiated");
- await Storage.ResetStorage();
+ await StorageService.ClearStorage();
PasswordVault passwordVault = new PasswordVault();
foreach (PasswordCredential credential in passwordVault.RetrieveAll())
passwordVault.Remove(credential);
RestartApp();
}
+
+ public static void UpdateTitleBarTheme(bool isDark)
+ {
+ ApplicationViewTitleBar titleBar = ApplicationView.GetForCurrentView().TitleBar;
+ titleBar.ButtonBackgroundColor = Colors.Transparent;
+ titleBar.ButtonInactiveBackgroundColor = Colors.Transparent;
+ titleBar.ButtonInactiveForegroundColor = Colors.Gray;
+
+ if (isDark)
+ {
+ titleBar.ButtonForegroundColor =
+ titleBar.ButtonHoverForegroundColor =
+ titleBar.ButtonPressedForegroundColor = Colors.White;
+ titleBar.ButtonHoverBackgroundColor = Color.FromArgb(50, 255, 255, 255);
+ titleBar.ButtonPressedBackgroundColor = Color.FromArgb(30, 255, 255, 255);
+ }
+ else
+ {
+ titleBar.ButtonForegroundColor =
+ titleBar.ButtonHoverForegroundColor =
+ titleBar.ButtonPressedForegroundColor = Colors.Black;
+ titleBar.ButtonHoverBackgroundColor = Color.FromArgb(50, 0, 0, 0);
+ titleBar.ButtonPressedBackgroundColor = Color.FromArgb(70, 0, 0, 0);
+ }
+ }
}
}
diff --git a/FoxTube/App.xaml b/FoxTube/App.xaml
index be15912..1a5c405 100644
--- a/FoxTube/App.xaml
+++ b/FoxTube/App.xaml
@@ -1,13 +1,22 @@
+ x:Class="FoxTube.App"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
+
+
+
+
+
+
+
+
+
Red
diff --git a/FoxTube/App.xaml.cs b/FoxTube/App.xaml.cs
index 1ff2f5f..d4fa856 100644
--- a/FoxTube/App.xaml.cs
+++ b/FoxTube/App.xaml.cs
@@ -1,11 +1,8 @@
using System;
-using FoxTube.Services;
using FoxTube.Utils;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation;
-using Windows.UI;
-using Windows.UI.Popups;
-using Windows.UI.ViewManagement;
+using Windows.ApplicationModel.Background;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
@@ -21,52 +18,50 @@ namespace FoxTube
UnhandledException += ErrorOccured;
}
- protected override async void OnLaunched(LaunchActivatedEventArgs args)
+ protected override void OnLaunched(LaunchActivatedEventArgs args)
{
- try
- {
- await UserManagement.Initialize();
- await StoreInterop.UpdateStoreState();
- if (Settings.LastReviewedVersion != Metrics.CurrentVersion)
- Inbox.PushChangelog();
- }
- catch (Exception e)
- {
- Metrics.SendReport(new Exception("OuLaunch initialization failed", e));
- await new MessageDialog("There can be a temporary server issue or weak internet connection. Please, check your internet connection and try again later", "Something went wrong...").ShowAsync();
- Utils.Utils.CloseApp();
- }
-
- if (!args.PrelaunchActivated && Window.Current.Content == null)
- Window.Current.Content = new MainPage();
- Window.Current.Activate();
+ base.OnLaunched(args);
+ ActivateWindow(args);
}
- protected override void OnBackgroundActivated(BackgroundActivatedEventArgs args)
+ protected override async void OnBackgroundActivated(BackgroundActivatedEventArgs args)
{
- var deferral = args.TaskInstance.GetDeferral();
base.OnBackgroundActivated(args);
+ BackgroundTaskDeferral defferal = args.TaskInstance.GetDeferral();
- deferral.Complete();
+ await BackgroundManager.PerformBackgroundTask(args);
+
+ defferal.Complete();
}
protected override void OnActivated(IActivatedEventArgs e)
{
base.OnActivated(e);
-
- if (Window.Current.Content == null)
- Window.Current.Content = new MainPage();
- Window.Current.Activate();
+ ActivateWindow(e);
}
- void OnSuspending(object sender, SuspendingEventArgs e)
+ private void ActivateWindow(IActivatedEventArgs args)
+ {
+ if (!(Window.Current.Content is Frame rootFrame))
+ Window.Current.Content = rootFrame = new Frame();
+
+ if (rootFrame.Content == null && args.PreviousExecutionState != ApplicationExecutionState.Running)
+ {
+ if (rootFrame.Content == null)
+ rootFrame.Content = new SplashScreen(args);
+ Window.Current.Activate();
+ }
+ }
+
+ private void OnSuspending(object sender, SuspendingEventArgs e)
{
Metrics.EndSession();
+ // TODO: Perform suspending tasks (complete downloads or cancel closing)
}
- async void ErrorOccured(object sender, Windows.UI.Xaml.UnhandledExceptionEventArgs e)
+ private async void ErrorOccured(object sender, Windows.UI.Xaml.UnhandledExceptionEventArgs e)
{
- Metrics.AddEvent("Application chrashed",
+ Metrics.AddEvent("Application crashed",
("Exception", e.Exception.GetType().ToString()),
("Message", e.Message),
("StackTrace", e.Exception.StackTrace));
@@ -79,46 +74,22 @@ namespace FoxTube
Content = "It may be a bug or temporary server issues. Please, try again later\n\nIf this happens again try to reset your app settings or report the problem",
PrimaryButtonText = "Report the problem",
SecondaryButtonText = "Reset application",
- CloseButtonText = "Close",
+ CloseButtonText = "Restart the app",
DefaultButton = ContentDialogButton.Primary
}.ShowAsync();
switch (result)
{
case ContentDialogResult.Primary:
- Feedback.OpenFeedbackHub();
+ FeedbackInterop.OpenFeedbackHub();
break;
case ContentDialogResult.Secondary:
Utils.Utils.InitializeFailsafeProtocol();
break;
default:
+ Utils.Utils.RestartApp();
break;
}
}
-
- public static void UpdateTitleBar(bool isDark)
- {
- ApplicationViewTitleBar titleBar = ApplicationView.GetForCurrentView().TitleBar;
- titleBar.ButtonBackgroundColor = Colors.Transparent;
- titleBar.ButtonInactiveBackgroundColor = Colors.Transparent;
- titleBar.ButtonInactiveForegroundColor = Colors.Gray;
-
- if (isDark)
- {
- titleBar.ButtonForegroundColor =
- titleBar.ButtonHoverForegroundColor =
- titleBar.ButtonPressedForegroundColor = Colors.White;
- titleBar.ButtonHoverBackgroundColor = Color.FromArgb(50, 255, 255, 255);
- titleBar.ButtonPressedBackgroundColor = Color.FromArgb(30, 255, 255, 255);
- }
- else
- {
- titleBar.ButtonForegroundColor =
- titleBar.ButtonHoverForegroundColor =
- titleBar.ButtonPressedForegroundColor = Colors.Black;
- titleBar.ButtonHoverBackgroundColor = Color.FromArgb(50, 0, 0, 0);
- titleBar.ButtonPressedBackgroundColor = Color.FromArgb(70, 0, 0, 0);
- }
- }
}
}
\ No newline at end of file
diff --git a/FoxTube/Classes/MenuItemsList.cs b/FoxTube/Classes/MenuItemsList.cs
index 4bf0d3a..a818327 100644
--- a/FoxTube/Classes/MenuItemsList.cs
+++ b/FoxTube/Classes/MenuItemsList.cs
@@ -3,6 +3,9 @@ using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Media.Imaging;
using FoxTube.Models;
+using FoxTube.Views.HomeSections;
+using FoxTube.Views;
+using FoxTube.Services;
namespace FoxTube.Utils
{
@@ -10,26 +13,25 @@ namespace FoxTube.Utils
{
public static List GetMenuItems(bool authorized)
{
- List list = new List
- {
- GetItem("Home", new SymbolIcon(Symbol.Home), "home")
- };
+ List list = new List();
if (authorized)
list.AddRange(new Microsoft.UI.Xaml.Controls.NavigationViewItemBase[]
{
- GetItem("Subscriptions", new SymbolIcon(Symbol.People), "subscriptions"),
+ GetItem("Home", new SymbolIcon(Symbol.Home), typeof(HomeView)),
new Microsoft.UI.Xaml.Controls.NavigationViewItemHeader { Content = "Library" },
- GetItem("History", new FontIcon { Glyph = "\xE81C" }, "history"),
- GetItem("Liked videos", new SymbolIcon(Symbol.Like), "liked"),
- GetItem("Watch later", new SymbolIcon(Symbol.Clock), "watchLater"),
- GetItem("Downloads", new SymbolIcon(Symbol.Download), "downloads")
+ GetItem("History", new FontIcon { Glyph = "\xE81C" }, typeof(HistoryView)),
+ GetItem("Liked videos", new SymbolIcon(Symbol.Like), (typeof(PlaylistView), UserService.CurrentUser.Channel.ContentDetails.RelatedPlaylists.Likes)),
+ GetItem("Watch later", new SymbolIcon(Symbol.Clock), (typeof(PlaylistView), "WL")),
+ GetItem("Downloads", new SymbolIcon(Symbol.Download), typeof(DownloadsView)),
+ GetItem("Subscriptions", new SymbolIcon(Symbol.People), typeof(SubscriptionsView))
});
else
list.AddRange(new Microsoft.UI.Xaml.Controls.NavigationViewItemBase[]
{
- GetItem("Downloads", new SymbolIcon(Symbol.Download), "downloads"),
+ GetItem("Home", new SymbolIcon(Symbol.Home), typeof(TrendingView)),
+ GetItem("Downloads", new SymbolIcon(Symbol.Download), typeof(DownloadsView)),
new Microsoft.UI.Xaml.Controls.NavigationViewItemHeader { Content = "Best of YouTube" },
GetItem("Music", new FontIcon { Glyph = "\xE189" }, "UC-9-kyTW8ZkZNDHQJ6FgpwQ"),
@@ -44,7 +46,7 @@ namespace FoxTube.Utils
return list;
}
- private static Microsoft.UI.Xaml.Controls.NavigationViewItem GetItem(string content, IconElement icon, string tag) =>
+ private static Microsoft.UI.Xaml.Controls.NavigationViewItem GetItem(string content, IconElement icon, object tag) =>
new Microsoft.UI.Xaml.Controls.NavigationViewItem
{
Content = content,
@@ -54,29 +56,29 @@ namespace FoxTube.Utils
public static Microsoft.UI.Xaml.Controls.NavigationViewItem GenerateItemFromSubscription(Subscription subscription)
{
- StackPanel stack = new StackPanel
+ Grid grid = new Grid
{
- Orientation = Orientation.Horizontal,
- Padding = new Thickness(5),
- Margin = new Thickness(-5, 0, 0, 0)
+ ColumnSpacing = 12
};
- stack.Children.Add(new Microsoft.UI.Xaml.Controls.PersonPicture
+ grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(20) });
+ grid.ColumnDefinitions.Add(new ColumnDefinition());
+
+ grid.Children.Add(new Microsoft.UI.Xaml.Controls.PersonPicture
{
- Height = 20,
- Margin = new Thickness(-5, 0, 15, 0),
+ Width = 20,
ProfilePicture = new BitmapImage().LoadImage(subscription.Avatar.Default__.Url, 20, 20)
});
- stack.Children.Add(new TextBlock
+ grid.Children.Add(new TextBlock
{
- FontSize = 14,
Text = subscription.Title
});
+ Grid.SetColumn(grid.Children[1] as TextBlock, 1);
return new Microsoft.UI.Xaml.Controls.NavigationViewItem
{
- Content = stack,
+ Content = grid,
Tag = subscription.ChannelId
};
}
diff --git a/FoxTube/Classes/Navigation.cs b/FoxTube/Classes/Navigation.cs
deleted file mode 100644
index e092b08..0000000
--- a/FoxTube/Classes/Navigation.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-namespace FoxTube
-{
- public enum NavigationTarget
- {
- Home,
- Settings,
- Downloads,
- Subscriptions
- }
-
- public static class Navigation
- {
- public static NavigationTarget CurrentPage { get; private set; }
- public static object CurrentParameter { get; private set; }
-
- public static void NavigateTo(NavigationTarget destination) =>
- NavigateTo(destination, null);
-
- public static void NavigateTo(NavigationTarget destination, object parameters)
- {
- MainPage.Current.Navigate(destination switch
- {
- NavigationTarget.Settings => typeof(Views.Settings),
- NavigationTarget.Downloads => typeof(Views.Downloads),
- NavigationTarget.Subscriptions => typeof(Views.Subscriptions),
- _ => UserManagement.Authorized ? typeof(Views.Home) : typeof(Views.HomeSections.Trending),
- },
- parameters);
-
- CurrentPage = destination;
- CurrentParameter = parameters;
- }
-
- public static void RefreshCurrentPage() =>
- MainPage.Current.Refresh();
- }
-}
\ No newline at end of file
diff --git a/FoxTube/Classes/ScrollPage.cs b/FoxTube/Classes/ScrollPage.cs
new file mode 100644
index 0000000..8a74999
--- /dev/null
+++ b/FoxTube/Classes/ScrollPage.cs
@@ -0,0 +1,16 @@
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
+
+namespace FoxTube.Pages
+{
+ public class ScrollPage : Page
+ {
+ public ScrollViewer ScrollViewer => base.Content as ScrollViewer;
+ public new UIElement Content => ScrollViewer.Content as UIElement;
+
+ public ScrollPage()
+ {
+ base.Content = new ScrollViewer();
+ }
+ }
+}
\ No newline at end of file
diff --git a/FoxTube/Classes/TemplatedPage.cs b/FoxTube/Classes/TemplatedPage.cs
new file mode 100644
index 0000000..f99379b
--- /dev/null
+++ b/FoxTube/Classes/TemplatedPage.cs
@@ -0,0 +1,27 @@
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
+
+namespace FoxTube.Classes
+{
+ public class TemplatedPage : Page
+ {
+ public UIElement PageDummy
+ {
+ get => ((base.Content as Grid).Children[0] as ContentPresenter).Content as UIElement;
+ set => ((base.Content as Grid).Children[0] as ContentPresenter).Content = value;
+ }
+ public new UIElement Content
+ {
+ get => ((base.Content as Grid).Children[1] as ContentPresenter).Content as UIElement;
+ set => ((base.Content as Grid).Children[1] as ContentPresenter).Content = value;
+ }
+
+ public TemplatedPage()
+ {
+ Grid grid = new Grid();
+ grid.Children.Add(new ContentPresenter());
+ grid.Children.Add(new ContentPresenter());
+ base.Content = grid;
+ }
+ }
+}
diff --git a/FoxTube/Controls/AccountManager.xaml b/FoxTube/Controls/AccountManager.xaml
index c9e0dc3..5fe73f0 100644
--- a/FoxTube/Controls/AccountManager.xaml
+++ b/FoxTube/Controls/AccountManager.xaml
@@ -2,94 +2,164 @@
x:Class="FoxTube.Controls.AccountManager"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ xmlns:data="using:Google.Apis.Oauth2.v2.Data"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- mc:Ignorable="d"
xmlns:ui="using:Microsoft.UI.Xaml.Controls"
- xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls" xmlns:data="using:Google.Apis.Oauth2.v2.Data"
- Loaded="AppBarButton_Loaded"
- Style="{StaticResource ButtonRevealStyle}"
- CornerRadius="0"
- Padding="10,0"
- Height="32"
- Background="Transparent">
+ Height="32"
+ Padding="10,0"
+ Background="Transparent"
+ CornerRadius="0"
+ Loaded="AppBarButton_Loaded"
+ Style="{StaticResource ButtonRevealStyle}"
+ mc:Ignorable="d">
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/FoxTube/Controls/AccountManager.xaml.cs b/FoxTube/Controls/AccountManager.xaml.cs
index 21a26b0..962a6e1 100644
--- a/FoxTube/Controls/AccountManager.xaml.cs
+++ b/FoxTube/Controls/AccountManager.xaml.cs
@@ -4,6 +4,9 @@ using FoxTube.Models;
using System.Linq;
using Google.Apis.Oauth2.v2.Data;
using Windows.UI.Xaml.Media.Imaging;
+using FoxTube.Services;
+using System;
+using FoxTube.Utils;
namespace FoxTube.Controls
{
@@ -14,27 +17,40 @@ namespace FoxTube.Controls
public AccountManager() =>
InitializeComponent();
- private async void Flyout_Opening(object sender, object e)
+ private async void Flyout_Opening(object sender, object args)
{
- if (UserManagement.Authorized)
+ if (UserService.Authorized)
return;
(sender as Flyout).Hide();
- await UserManagement.AddUser();
+ try
+ {
+ await UserService.AddUser();
+ }
+ catch (Exception e)
+ {
+ await new ContentDialog
+ {
+ Title = "Failed to add account",
+ Content = "Something went wrong. Please, try again later"
+ }.ShowAsync();
+
+ Metrics.SendReport(new Exception("Failed to login", e));
+ }
}
private void AppBarButton_Loaded(object sender, RoutedEventArgs e)
{
- if (UserManagement.Authorized)
+ if (UserService.Authorized)
UpdateData(true);
- UserManagement.UserStateUpdated += (s, e) => UpdateData(e);
+ UserService.UserStateUpdated += (s, e) => UpdateData(e);
}
private void UpdateData(bool authorized)
{
- CurrentUser = UserManagement.CurrentUser;
+ CurrentUser = UserService.CurrentUser;
if (authorized)
{
buttonLabel.Text = name.Text = CurrentUser.Channel.Snippet.Title;
@@ -49,11 +65,11 @@ namespace FoxTube.Controls
icon.Visibility = Visibility.Collapsed;
profileIcon.Visibility = Visibility.Visible;
- var users = UserManagement.Users.Where(i => i.Id != CurrentUser.UserInfo.Id).ToList();
+ var users = UserService.Users.Where(i => i.Id != CurrentUser.UserInfo.Id).ToList();
usersList.ItemsSource = users;
usersList.Visibility = users.Count > 0 ? Visibility.Visible : Visibility.Visible;
- addAccountButton.Visibility = UserManagement.CanAddAccounts ? Visibility.Visible : Visibility.Collapsed;
+ addAccountButton.Visibility = UserService.CanAddAccounts ? Visibility.Visible : Visibility.Collapsed;
}
else
{
@@ -68,7 +84,7 @@ namespace FoxTube.Controls
private async void SwitchUser(object sender, ItemClickEventArgs e)
{
Userinfoplus user = (Userinfoplus)e.ClickedItem;
- await UserManagement.SwitchUser(UserManagement.Users.ToList().IndexOf(user));
+ await UserService.SwitchUser(UserService.Users.ToList().IndexOf(user));
}
private async void NavigationViewItem_Tapped(object sender, Windows.UI.Xaml.Input.TappedRoutedEventArgs e)
@@ -81,10 +97,10 @@ namespace FoxTube.Controls
case "creatorStudio":
break;
case "addUser":
- await UserManagement.AddUser();
+ await UserService.AddUser();
break;
case "logout":
- await UserManagement.Logout();
+ await UserService.Logout();
break;
}
}
@@ -98,22 +114,17 @@ namespace FoxTube.Controls
MainPage.Current.RequestedTheme = ElementTheme.Dark;
else
{
- if (Settings.Theme == 0)
- MainPage.Current.RequestedTheme = ElementTheme.Light;
- else if (Settings.Theme == 1)
- MainPage.Current.RequestedTheme = ElementTheme.Dark;
- else
- MainPage.Current.RequestedTheme = ElementTheme.Default;
+ MainPage.Current.RequestedTheme = ElementTheme.Default;
- if (RequestedTheme == ElementTheme.Default)
- App.UpdateTitleBar(Application.Current.RequestedTheme == ApplicationTheme.Dark);
+ if ((Window.Current.Content as Frame).RequestedTheme == ElementTheme.Default)
+ Utils.Utils.UpdateTitleBarTheme(Application.Current.RequestedTheme == ApplicationTheme.Dark);
else
- App.UpdateTitleBar(MainPage.Current.RequestedTheme == ElementTheme.Dark);
+ Utils.Utils.UpdateTitleBarTheme(MainPage.Current.RequestedTheme == ElementTheme.Dark);
}
- UpdateLayout();
+ MainPage.Current.UpdateLayout();
- UserManagement.IncognitoMode = incognito.IsOn;
+ UserService.IncognitoMode = incognito.IsOn;
}
}
}
\ No newline at end of file
diff --git a/FoxTube/Controls/Cards/AdvertCard.xaml.cs b/FoxTube/Controls/Cards/AdvertCard.xaml.cs
index 06e683c..dcbb4a5 100644
--- a/FoxTube/Controls/Cards/AdvertCard.xaml.cs
+++ b/FoxTube/Controls/Cards/AdvertCard.xaml.cs
@@ -1,4 +1,5 @@
-using FoxTube.Utils;
+using FoxTube.Services;
+using FoxTube.Utils;
using Microsoft.Advertising.WinRT.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
@@ -10,7 +11,7 @@ namespace FoxTube.Controls.Cards
///
public sealed partial class AdvertCard : UserControl
{
- readonly NativeAdsManagerV2 manager = new NativeAdsManagerV2(StoreInterop.ApplicationId, StoreInterop.AdsId);
+ readonly NativeAdsManagerV2 manager = AddonsInterop.AdsManager;
NativeAdV2 advert;
public AdvertCard()
@@ -23,6 +24,7 @@ namespace FoxTube.Controls.Cards
void ErrorOccurred(object sender, NativeAdErrorEventArgs e)
{
+ UnsubscribeEvents();
(Parent as Panel)?.Children.Remove(this);
Metrics.AddEvent("Error has occured while loading ad",
("Code", e.ErrorCode.ToString()),
@@ -32,6 +34,7 @@ namespace FoxTube.Controls.Cards
void AdReady(object sender, NativeAdReadyEventArgs e)
{
+ UnsubscribeEvents();
advert = e.NativeAd;
if (string.IsNullOrWhiteSpace(advert.CallToActionText))
@@ -43,9 +46,15 @@ namespace FoxTube.Controls.Cards
Opacity = 1;
- Metrics.AddEvent("Advert loaded",
- ("Region", Settings.Region),
- ("Version", Metrics.CurrentVersion));
+ /*Metrics.AddEvent("Advert loaded",
+ ("Region", Storage.GetValue(Storage.Settings.Region)),
+ ("Version", Metrics.CurrentVersion));*/
+ }
+
+ private void UnsubscribeEvents()
+ {
+ manager.AdReady -= AdReady;
+ manager.ErrorOccurred -= ErrorOccurred;
}
void UserControl_SizeChanged(object sender, SizeChangedEventArgs e) =>
diff --git a/FoxTube/Controls/Dialogs/DownloadVideoDialog.xaml.cs b/FoxTube/Controls/Dialogs/DownloadVideoDialog.xaml.cs
index 1fa3f1a..2a9b012 100644
--- a/FoxTube/Controls/Dialogs/DownloadVideoDialog.xaml.cs
+++ b/FoxTube/Controls/Dialogs/DownloadVideoDialog.xaml.cs
@@ -1,4 +1,5 @@
-using System;
+using FoxTube.Services;
+using System;
using System.Linq;
using Windows.Storage;
using Windows.Storage.Pickers;
@@ -41,7 +42,7 @@ namespace FoxTube.Controls.Dialogs
private async void ContentDialog_Loading(FrameworkElement sender, object args)
{
- StorageFolder defaultFolder = await Services.DownloadsCenter.GetDefaultDownloadsFolder();
+ StorageFolder defaultFolder = await DownloadsService.GetDefaultDownloadsFolder();
location.Text = $"{defaultFolder.Name}\\{Meta.Title.ReplaceInvalidChars('_')}.mp4";
}
diff --git a/FoxTube/Controls/Dialogs/ProOfferDialog.xaml.cs b/FoxTube/Controls/Dialogs/ProOfferDialog.xaml.cs
index fb36796..cd220d7 100644
--- a/FoxTube/Controls/Dialogs/ProOfferDialog.xaml.cs
+++ b/FoxTube/Controls/Dialogs/ProOfferDialog.xaml.cs
@@ -10,7 +10,7 @@ namespace FoxTube.Controls.Dialogs
public ProOfferDialog()
{
InitializeComponent();
- getButton.Content = $"Get for {StoreInterop.Price}!";
+ getButton.Content = $"Get for {AddonsInterop.Price}!";
}
private async void ContentDialog_PrimaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args) =>
@@ -24,7 +24,7 @@ namespace FoxTube.Controls.Dialogs
private async Task Purchase()
{
- if (!await StoreInterop.PurchaseApp())
+ if (!await AddonsInterop.PurchaseApp())
return;
ContentDialog dialog = new ContentDialog
diff --git a/FoxTube/Controls/ItemsGrid.xaml b/FoxTube/Controls/ItemsGrid.xaml
index 199cdf2..aa2aeb7 100644
--- a/FoxTube/Controls/ItemsGrid.xaml
+++ b/FoxTube/Controls/ItemsGrid.xaml
@@ -1,18 +1,18 @@
+ d:DesignHeight="1080"
+ d:DesignWidth="1920">
-
+
@@ -21,7 +21,7 @@
-
+
diff --git a/FoxTube/Controls/LoadingScreen.xaml.cs b/FoxTube/Controls/LoadingScreen.xaml.cs
index 2af8faf..3e3aed9 100644
--- a/FoxTube/Controls/LoadingScreen.xaml.cs
+++ b/FoxTube/Controls/LoadingScreen.xaml.cs
@@ -18,7 +18,7 @@ namespace FoxTube.Controls
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
- feedbackButton.Visibility = Feedback.HasFeedbackHub ? Visibility.Visible : Visibility.Collapsed;
+ feedbackButton.Visibility = FeedbackInterop.HasFeedbackHub ? Visibility.Visible : Visibility.Collapsed;
for (int i = 0; i < 25; i++)
grid.Items.Add(new Image
@@ -102,13 +102,13 @@ namespace FoxTube.Controls
}
private void LeaveFeedback(object sender, RoutedEventArgs e) =>
- Feedback.OpenFeedbackHub();
+ FeedbackInterop.OpenFeedbackHub();
private async void OpenNetworkSettings(object sender, RoutedEventArgs e) =>
await Launcher.LaunchUriAsync("ms-settings:network".ToUri());
private void RefreshPage(object sender, RoutedEventArgs e) =>
- Navigation.RefreshCurrentPage();
+ Navigation.Refresh();
private async void OpenTroubleshooter(object sender, RoutedEventArgs e) =>
await Launcher.LaunchUriAsync("ms-settings:troubleshoot".ToUri());
diff --git a/FoxTube/FoxTube.csproj b/FoxTube/FoxTube.csproj
index 7bf020c..54b5d66 100644
--- a/FoxTube/FoxTube.csproj
+++ b/FoxTube/FoxTube.csproj
@@ -106,7 +106,8 @@
App.xaml
-
+
+
DownloadVideoDialog.xaml
@@ -143,11 +144,20 @@
MainPage.xaml
-
- Downloads.xaml
+
+ SplashScreen.xaml
-
- Home.xaml
+
+ ChannelView.xaml
+
+
+ DownloadsView.xaml
+
+
+ HistoryView.xaml
+
+
+ HomeView.xaml
Recommended.xaml
@@ -155,26 +165,29 @@
Subscriptions.xaml
-
- Trending.xaml
+
+ TrendingView.xaml
-
- Search.xaml
+
+ PlaylistView.xaml
-
- Settings.xaml
+
+ SearchView.xaml
-
- About.xaml
+
+ AboutSection.xaml
-
- General.xaml
+
+ PreferencesSection.xaml
-
- Inbox.xaml
+
+ SettingsView.xaml
-
- Subscriptions.xaml
+
+ InboxSection.xaml
+
+
+ SubscriptionsView.xaml
@@ -296,11 +309,27 @@
Designer
MSBuild:Compile
-
+
Designer
MSBuild:Compile
-
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
Designer
MSBuild:Compile
@@ -312,31 +341,35 @@
Designer
MSBuild:Compile
-
+
Designer
MSBuild:Compile
-
+
Designer
MSBuild:Compile
-
+
Designer
MSBuild:Compile
-
+
+ MSBuild:Compile
+ Designer
+
+
+ MSBuild:Compile
+ Designer
+
+
Designer
MSBuild:Compile
-
+
Designer
MSBuild:Compile
-
- Designer
- MSBuild:Compile
-
-
+
Designer
MSBuild:Compile
@@ -352,7 +385,7 @@
6.0.0
- 2.4.0
+ 2.4.2
diff --git a/FoxTube/MainPage.xaml b/FoxTube/MainPage.xaml
index cb0c28c..265d85c 100644
--- a/FoxTube/MainPage.xaml
+++ b/FoxTube/MainPage.xaml
@@ -1,38 +1,75 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
-
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+ BackRequested="NavigationViewControl_BackRequested"
+ ItemInvoked="NavigationViewControl_ItemInvoked"
+ IsPaneToggleButtonVisible="False"
+ IsPaneOpen="True">
@@ -55,28 +92,13 @@
-
+
-
-
+
+
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/FoxTube/MainPage.xaml.cs b/FoxTube/MainPage.xaml.cs
index 0a3471a..23915ae 100644
--- a/FoxTube/MainPage.xaml.cs
+++ b/FoxTube/MainPage.xaml.cs
@@ -4,12 +4,16 @@ using FoxTube.Utils;
using FoxTube.Services;
using System;
using System.Linq;
-using Windows.ApplicationModel.Core;
using Windows.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using FoxTube.Models;
+using Windows.ApplicationModel;
+using Windows.UI.Xaml.Navigation;
+using System.Reflection;
+using FoxTube.Views;
+using Google.Apis.YouTube.v3.Data;
+using FoxTube.Views.HomeSections;
-// TODO: Fix header (UI)
namespace FoxTube
{
public sealed partial class MainPage : Windows.UI.Xaml.Controls.Page
@@ -21,91 +25,90 @@ namespace FoxTube
Current = this;
InitializeComponent();
- #region Setup theme
- if (Settings.Theme == 0)
- RequestedTheme = ElementTheme.Light;
- else if (Settings.Theme == 1)
- RequestedTheme = ElementTheme.Dark;
-
- if (RequestedTheme == ElementTheme.Default)
- App.UpdateTitleBar(Application.Current.RequestedTheme == ApplicationTheme.Dark);
- else
- App.UpdateTitleBar(RequestedTheme == ElementTheme.Dark);
-
Window.Current.SetTitleBar(AppTitleBar);
+ AppTitle.Text = $"{Package.Current.DisplayName} ({Metrics.CurrentVersion})";
- CoreApplication.GetCurrentView().TitleBar.ExtendViewIntoTitleBar = true;
- #endregion
+ PurchaseButton.Visibility = AddonsInterop.AdsDisabled ? Visibility.Collapsed : Visibility.Visible;
+ if (!AddonsInterop.AdsDisabled)
+ PurchaseButton.Content += $" ({AddonsInterop.Price})";
- removeAds.Visibility = StoreInterop.AdsDisabled ? Visibility.Collapsed : Visibility.Visible;
- if (!StoreInterop.AdsDisabled)
- removeAds.Content += $" ({StoreInterop.Price})";
+ if (!FeedbackInterop.HasFeedbackHub)
+ FeedbackButton.Visibility = Visibility.Collapsed;
- leaveFeedback.Visibility = Feedback.HasFeedbackHub ?
- Visibility.Visible : Visibility.Collapsed;
+ Navigation.Navigated += Content_Navigated;
- UserManagement.SubscriptionsChanged += UsersControl_SubscriptionsChanged;
- UserManagement.UserStateUpdated += UsersControl_UserStateUpdated;
- UsersControl_UserStateUpdated(this, UserManagement.Authorized);
+ UserService.SubscriptionsChanged += UsersControl_SubscriptionsChanged;
+ UserService.UserStateUpdated += UsersControl_UserStateUpdated;
+ }
- if (Settings.PromptReview)
- Feedback.PromptReview();
- if (Settings.PromptFeedback)
- Feedback.PromptFeedback();
+ protected override void OnNavigatedFrom(NavigationEventArgs e)
+ {
+ base.OnNavigatedFrom(e);
+ Current = null;
+ }
+
+ protected override void OnNavigatedTo(NavigationEventArgs e)
+ {
+ base.OnNavigatedTo(e);
+
+ Uri parameter = (e.Parameter as string)?.ToUri();
+ if (parameter != null && parameter.Segments.Length > 0)
+ {
+ Type targetType = Assembly.GetExecutingAssembly().GetTypes().FirstOrDefault(i => i.IsClass && i.Namespace.StartsWith("FoxTube.Views") && i.Name.ToLowerInvariant() == $"{parameter.Segments[0].ToLowerInvariant()}view");
+ if (targetType != null)
+ {
+ Navigation.NavigateTo(targetType, e.Parameter);
+ return;
+ }
+ }
+
+ UsersControl_UserStateUpdated(this, UserService.Authorized);
}
#region Navigation
- private void Content_Navigated(object sender, Windows.UI.Xaml.Navigation.NavigationEventArgs args)
+ private void Content_Navigated(object sender, NavigationEventArgs args)
{
- NavigationViewControl.IsBackEnabled = content.CanGoBack;
+ NavigationViewControl.IsBackEnabled = ContentFrame.CanGoBack;
+ RefreshButton.Opacity = Convert.ToInt32(Attribute.IsDefined(args.SourcePageType, typeof(RefreshableAttribute)));
- refresh.Opacity = Attribute.IsDefined(args.SourcePageType, typeof(RefreshableAttribute)) ? 1 : 0;
-
- switch (args.SourcePageType.Name)
+ NavigationViewControl.SelectedItem = args.SourcePageType.Name switch
{
- case "Settings":
- NavigationViewControl.SelectedItem = NavigationViewControl.SettingsItem;
- break;
- case "Downloads":
- NavigationViewControl.SelectedItem = NavigationViewControl.MenuItems.FirstOrDefault(i => ((FrameworkElement)i).Tag as string == "downloads");
- break;
- case "Subscriptions":
- NavigationViewControl.SelectedItem = NavigationViewControl.MenuItems.FirstOrDefault(i => ((FrameworkElement)i).Tag as string == "subscriptions");
- break;
- case "Home":
- case "Trending":
- NavigationViewControl.SelectedItem = NavigationViewControl.MenuItems.FirstOrDefault(i => ((FrameworkElement)i).Tag as string == "home");
- break;
- case "Channel":
- NavigationViewControl.SelectedItem = NavigationViewControl.MenuItems.FirstOrDefault(i => ((FrameworkElement)i).Tag == args.Parameter);
- break;
- default:
- NavigationViewControl.SelectedItem = null;
- break;
-
- // TODO: Update menu selector
- }
+ nameof(SettingsView) => NavigationViewControl.SettingsItem,
+ nameof(ChannelView) => NavigationViewControl.MenuItems.FirstOrDefault(i => ((FrameworkElement)i).Tag == args.Parameter),
+ _ => NavigationViewControl.MenuItems.FirstOrDefault(i => ((FrameworkElement)i).Tag as Type == args.SourcePageType)
+ };
}
private void NavigationViewControl_ItemInvoked(NavigationView sender, NavigationViewItemInvokedEventArgs args)
{
- (NavigationTarget target, object parameters) suggestedTransition;
-
+ Type targetType;
+ string param = null;
if (args.IsSettingsInvoked)
- suggestedTransition = (NavigationTarget.Settings, null);
+ targetType = typeof(SettingsView);
else
- suggestedTransition = args.InvokedItemContainer.Tag as string switch
+ {
+ if (args.InvokedItemContainer.Tag is Type itemType)
+ targetType = itemType;
+ else
{
- "home" => (NavigationTarget.Home, null),
- "downloads" => (NavigationTarget.Downloads, null),
- "subscriptions" => (NavigationTarget.Subscriptions, null),
- _ => (NavigationTarget.Home, null) // TODO: Navigate to channel
- };
+ targetType = typeof(ChannelView);
+ param = args.InvokedItemContainer.Tag as string;
+ }
+ }
- if (Navigation.CurrentPage == suggestedTransition.target && Navigation.CurrentParameter == suggestedTransition.parameters)
+ if (targetType == typeof(ChannelView))
+ {
+ if ((Navigation.CurrentParameter is Channel channelParam && channelParam.Id == param) ||
+ Navigation.CurrentParameter as string == param)
+ return;
+ }
+ else if (Navigation.CurrentPage == targetType)
return;
- Navigation.NavigateTo(suggestedTransition.target, suggestedTransition.parameters);
+ if (param == null)
+ Navigation.NavigateTo(targetType);
+ else
+ Navigation.NavigateTo(targetType, param);
}
#endregion
@@ -118,112 +121,77 @@ namespace FoxTube
private void AutoSuggestBox_QuerySubmitted(Windows.UI.Xaml.Controls.AutoSuggestBox sender, Windows.UI.Xaml.Controls.AutoSuggestBoxQuerySubmittedEventArgs args)
{
- if (args.QueryText.Length < 3)
- return;
-
- History.AddSearchHistoryEntry(args.QueryText);
-
- // TODO: Go to search
+ if (args.QueryText.Length >= 3)
+ Navigation.NavigateTo(typeof(SearchView), new SearchParameters(args.QueryText));
}
#endregion
#region Users management
private void UsersControl_UserStateUpdated(object sender, bool authorized)
{
- // Add general menu items
- NavigationViewControl.MenuItems.Clear();
- MenuItemsList.GetMenuItems(authorized).ForEach(i =>
- NavigationViewControl.MenuItems.Add(i));
+ UpdateMenu();
- // Add subscriptions list to the menu
- if (authorized && UserManagement.CurrentUser.Subscriptions.Count > 0)
- {
- NavigationViewControl.MenuItems.Add(new NavigationViewItemHeader { Content = "Subscriptions" });
- UserManagement.CurrentUser.Subscriptions.ToList().GetRange(0, Math.Min(UserManagement.CurrentUser.Subscriptions.Count, 10)).ForEach(i =>
- NavigationViewControl.MenuItems.Add(MenuItemsList.GenerateItemFromSubscription(i)));
- }
-
- // TODO: Menu selector resets after menu update
+ return;
// Refresh page
- if (content.CurrentSourcePageType == null || content.CurrentSourcePageType.Name.Belongs("Home", "Trending"))
- Navigation.NavigateTo(NavigationTarget.Home);
+ if (ContentFrame.CurrentSourcePageType == null || ContentFrame.CurrentSourcePageType.Name.Belongs("Home", "Trending"))
+ Navigation.NavigateTo(UserService.Authorized ? typeof(HomeView) : typeof(TrendingView));
else
- Refresh();
+ Navigation.RefreshForce();
}
- private void UsersControl_SubscriptionsChanged(object sender, Subscription subscription)
+ private void UsersControl_SubscriptionsChanged(object sender, Models.Subscription subscription)
{
- if (NavigationViewControl.MenuItems.FirstOrDefault(i => ((NavigationViewItemBase)i).Tag as string == subscription.ChannelId) is NavigationViewItem container)
- {
- NavigationViewControl.MenuItems.Remove(container);
+ NavigationViewItem subscriptionsContainer = NavigationViewControl.MenuItems.Last() as NavigationViewItem;
- if (UserManagement.CurrentUser.Subscriptions.Count < 1)
- NavigationViewControl.MenuItems.RemoveAt(NavigationViewControl.MenuItems.Count - 1);
+ if (subscriptionsContainer.MenuItems.FirstOrDefault(i => ((NavigationViewItemBase)i).Tag as string == subscription.ChannelId) is NavigationViewItem container)
+ {
+ subscriptionsContainer.MenuItems.Remove(container);
+
+ if (UserService.CurrentUser.Subscriptions.Count >= 10)
+ NavigationViewControl.MenuItems.Add(MenuItemsList.GenerateItemFromSubscription(UserService.CurrentUser.Subscriptions[9]));
}
else
{
- if (UserManagement.CurrentUser.Subscriptions.Count == 1)
- NavigationViewControl.MenuItems.Add(new NavigationViewItemHeader { Content = "Subscriptions" });
-
- if (UserManagement.CurrentUser.Subscriptions.Count.Belongs(1, 10))
+ if (UserService.CurrentUser.Subscriptions.Count.Belongs(1, 10))
NavigationViewControl.MenuItems.Add(MenuItemsList.GenerateItemFromSubscription(subscription));
}
}
- public void UpdateSubscriptions()
+ public void UpdateMenu()
{
+ object itemTag = (NavigationViewControl.SelectedItem as NavigationViewItem)?.Tag;
+
// Add general menu items
+ NavigationViewControl.SelectedItem = null;
NavigationViewControl.MenuItems.Clear();
- MenuItemsList.GetMenuItems(UserManagement.Authorized).ForEach(i =>
+ MenuItemsList.GetMenuItems(UserService.Authorized).ForEach(i =>
NavigationViewControl.MenuItems.Add(i));
// Add subscriptions list to the menu
- if (UserManagement.Authorized && UserManagement.CurrentUser.Subscriptions.Count > 0)
- {
- NavigationViewControl.MenuItems.Add(new NavigationViewItemHeader { Content = "Subscriptions" });
- UserManagement.CurrentUser.Subscriptions.ToList().GetRange(0, Math.Min(UserManagement.CurrentUser.Subscriptions.Count, 10)).ForEach(i =>
- NavigationViewControl.MenuItems.Add(MenuItemsList.GenerateItemFromSubscription(i)));
- }
+ if (UserService.Authorized)
+ UserService.CurrentUser.Subscriptions.ToList().GetRange(0, Math.Min(UserService.CurrentUser.Subscriptions.Count, 10)).ForEach(i =>
+ (NavigationViewControl.MenuItems.Last() as NavigationViewItem).MenuItems.Add(MenuItemsList.GenerateItemFromSubscription(i)));
+
+ NavigationViewControl.SelectedItem = NavigationViewControl.MenuItems.FirstOrDefault(i => (i as NavigationViewItemBase).Tag == itemTag);
}
#endregion
- #region Navigation actions
- public void Refresh()
- {
- if (!Attribute.IsDefined(content.CurrentSourcePageType, typeof(RefreshableAttribute)))
- return;
-
- content.Navigate(content.CurrentSourcePageType ?? typeof(Views.Home), Navigation.CurrentParameter);
- content.BackStack.RemoveAt(content.BackStack.Count - 1);
- }
-
- public void Navigate(Type target, object parameter) =>
- content.Navigate(target, parameter);
- #endregion
-
#region Simple button actions
- private void NavigationViewControl_BackRequested(NavigationView sender, NavigationViewBackRequestedEventArgs args)
- {
- if (content.CanGoBack)
- content.GoBack();
- }
+ private void NavigationViewControl_BackRequested(NavigationView sender, NavigationViewBackRequestedEventArgs args) =>
+ Navigation.GoBack();
private void Refresh_Click(object sender, RoutedEventArgs e) =>
- Refresh();
+ Navigation.Refresh();
private async void RemoveAds_Tapped(object sender, Windows.UI.Xaml.Input.TappedRoutedEventArgs e) =>
await new ProOfferDialog().ShowAsync();
private void LeaveFeedback_Click(object sender, RoutedEventArgs e) =>
- Feedback.OpenFeedbackHub();
+ FeedbackInterop.OpenFeedbackHub();
- private void NavigationView_DisplayModeChanged(NavigationView sender, NavigationViewDisplayModeChangedEventArgs args) =>
- AppTitleBar.Margin = new Thickness()
- {
- Left = sender.CompactPaneLength * (sender.DisplayMode == NavigationViewDisplayMode.Minimal ? 2 : 1),
- Right = toolbar.ActualWidth + 190
- };
+ private void TogglePane(object sender, RoutedEventArgs e) =>
+ NavigationViewControl.IsPaneOpen = !NavigationViewControl.IsPaneOpen;
#endregion
}
}
\ No newline at end of file
diff --git a/FoxTube/Navigation.cs b/FoxTube/Navigation.cs
new file mode 100644
index 0000000..a4ee759
--- /dev/null
+++ b/FoxTube/Navigation.cs
@@ -0,0 +1,45 @@
+using System;
+using Windows.UI.Xaml.Documents;
+using Windows.UI.Xaml.Media.Animation;
+using Windows.UI.Xaml.Navigation;
+
+namespace FoxTube
+{
+ public static class Navigation
+ {
+ public static event NavigatedEventHandler Navigated;
+ public static Type CurrentPage { get; private set; }
+ public static object CurrentParameter { get; private set; }
+ public static bool CanRefresh { get; private set; }
+ public static bool CanGoBack { get; private set; }
+
+ public static void NavigateTo(Type view) =>
+ NavigateTo(view, null, null);
+
+ public static void NavigateTo(Type view, object parameters) =>
+ NavigateTo(view, parameters, new EntranceNavigationTransitionInfo());
+
+ public static void NavigateTo(Type view, object parameters, NavigationTransitionInfo transitionInfo)
+ {
+ MainPage.Current.ContentFrame.Navigate(view, parameters, transitionInfo);
+
+ CurrentPage = view;
+ CurrentParameter = parameters;
+ }
+
+ public static void Refresh()
+ {
+
+ }
+
+ public static void RefreshForce()
+ {
+
+ }
+
+ public static void GoBack()
+ {
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/FoxTube/Package.appxmanifest b/FoxTube/Package.appxmanifest
index cbed62c..01b0e34 100644
--- a/FoxTube/Package.appxmanifest
+++ b/FoxTube/Package.appxmanifest
@@ -1,6 +1,6 @@
-
+
FoxTube
diff --git a/FoxTube/ResourceDictionaries/NavigationViewTemplate.xaml b/FoxTube/ResourceDictionaries/NavigationViewTemplate.xaml
new file mode 100644
index 0000000..7fb12b7
--- /dev/null
+++ b/FoxTube/ResourceDictionaries/NavigationViewTemplate.xaml
@@ -0,0 +1,342 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FoxTube/SplashScreen.xaml b/FoxTube/SplashScreen.xaml
new file mode 100644
index 0000000..f9fcc80
--- /dev/null
+++ b/FoxTube/SplashScreen.xaml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FoxTube/SplashScreen.xaml.cs b/FoxTube/SplashScreen.xaml.cs
new file mode 100644
index 0000000..f228bc2
--- /dev/null
+++ b/FoxTube/SplashScreen.xaml.cs
@@ -0,0 +1,91 @@
+using FoxTube.Services;
+using FoxTube.Utils;
+using System;
+using Windows.ApplicationModel.Activation;
+using Windows.ApplicationModel.Core;
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Media.Animation;
+using Windows.UI.Xaml.Navigation;
+
+namespace FoxTube
+{
+ ///
+ /// Extended splash screen. Does all initialization
+ ///
+ public sealed partial class SplashScreen : Page
+ {
+ private readonly Windows.ApplicationModel.Activation.SplashScreen splashScreen;
+ private readonly string navigationParameter;
+
+ public SplashScreen(IActivatedEventArgs args, string parameter = null)
+ {
+ InitializeComponent();
+ splashScreen = args.SplashScreen;
+ navigationParameter = parameter;
+
+ Window.Current.SizeChanged += Current_SizeChanged;
+
+ UpdateImagePosition();
+ }
+
+ private void Page_Loaded(object sender, RoutedEventArgs e)
+ {
+ ProgressRingControl.IsActive = true;
+
+ Initialize();
+ }
+
+ public async void Initialize()
+ {
+ Frame frame = Window.Current.Content as Frame;
+
+ frame.RequestedTheme = SettingsService.Theme;
+ if (frame.RequestedTheme == ElementTheme.Default)
+ Utils.Utils.UpdateTitleBarTheme(Application.Current.RequestedTheme == ApplicationTheme.Dark);
+ else
+ Utils.Utils.UpdateTitleBarTheme(frame.RequestedTheme == ElementTheme.Dark);
+
+ CoreApplication.GetCurrentView().TitleBar.ExtendViewIntoTitleBar = true;
+
+ if (StorageService.PromptReview)
+ FeedbackInterop.PromptReview();
+ if (StorageService.PromptFeedback)
+ FeedbackInterop.PromptFeedback();
+
+ #region App init
+ await UserService.Initialize();
+ await DownloadsService.Initialize();
+ await AddonsInterop.UpdateProPurchasedState();
+ InboxService.PushChangelog();
+
+ BackgroundManager.RegisterBackgroundTasks();
+ #endregion
+
+ if (navigationParameter.ToUri() is Uri uri && uri.Segments.Length > 0)
+ {
+ if (uri.Segments[0].ToLowerInvariant() == "action")
+ await BackgroundManager.ProcessBackgroundAction(navigationParameter);
+ }
+
+ frame.Navigate(typeof(MainPage), navigationParameter, new SlideNavigationTransitionInfo { Effect = SlideNavigationTransitionEffect.FromLeft });
+ }
+
+ protected override void OnNavigatedFrom(NavigationEventArgs e)
+ {
+ base.OnNavigatedFrom(e);
+ Window.Current.SizeChanged -= Current_SizeChanged;
+ }
+
+ private void Current_SizeChanged(object sender, Windows.UI.Core.WindowSizeChangedEventArgs e) =>
+ UpdateImagePosition();
+
+ private void UpdateImagePosition()
+ {
+ Canvas.SetLeft(SplashScreenImage, splashScreen.ImageLocation.Left);
+ Canvas.SetTop(SplashScreenImage, splashScreen.ImageLocation.Top);
+ SplashScreenImage.Height = splashScreen.ImageLocation.Height;
+ SplashScreenImage.Width = splashScreen.ImageLocation.Width;
+ }
+ }
+}
diff --git a/FoxTube/Views/HomeSections/Trending.xaml b/FoxTube/Views/ChannelView.xaml
similarity index 53%
rename from FoxTube/Views/HomeSections/Trending.xaml
rename to FoxTube/Views/ChannelView.xaml
index 6b77560..2c19eac 100644
--- a/FoxTube/Views/HomeSections/Trending.xaml
+++ b/FoxTube/Views/ChannelView.xaml
@@ -1,17 +1,14 @@
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ mc:Ignorable="d"
+ Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
-
-
-
-
-
-
\ No newline at end of file
+
+
+
+
diff --git a/FoxTube/Views/ChannelView.xaml.cs b/FoxTube/Views/ChannelView.xaml.cs
new file mode 100644
index 0000000..136298b
--- /dev/null
+++ b/FoxTube/Views/ChannelView.xaml.cs
@@ -0,0 +1,30 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices.WindowsRuntime;
+using Windows.Foundation;
+using Windows.Foundation.Collections;
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Controls.Primitives;
+using Windows.UI.Xaml.Data;
+using Windows.UI.Xaml.Input;
+using Windows.UI.Xaml.Media;
+using Windows.UI.Xaml.Navigation;
+
+// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238
+
+namespace FoxTube.Views
+{
+ ///
+ /// An empty page that can be used on its own or navigated to within a Frame.
+ ///
+ public sealed partial class ChannelView : Page
+ {
+ public ChannelView()
+ {
+ this.InitializeComponent();
+ }
+ }
+}
diff --git a/FoxTube/Views/Downloads.xaml b/FoxTube/Views/DownloadsView.xaml
similarity index 97%
rename from FoxTube/Views/Downloads.xaml
rename to FoxTube/Views/DownloadsView.xaml
index 7390f9f..1f4b27b 100644
--- a/FoxTube/Views/Downloads.xaml
+++ b/FoxTube/Views/DownloadsView.xaml
@@ -1,13 +1,13 @@
+ Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
diff --git a/FoxTube/Views/Downloads.xaml.cs b/FoxTube/Views/DownloadsView.xaml.cs
similarity index 85%
rename from FoxTube/Views/Downloads.xaml.cs
rename to FoxTube/Views/DownloadsView.xaml.cs
index 7683c08..f853c40 100644
--- a/FoxTube/Views/Downloads.xaml.cs
+++ b/FoxTube/Views/DownloadsView.xaml.cs
@@ -16,13 +16,13 @@ namespace FoxTube.Views
///
/// Video download page
///
- public sealed partial class Downloads : Page
+ public sealed partial class DownloadsView : Page
{
- public Downloads()
+ public DownloadsView()
{
InitializeComponent();
- downloadHistoryList.ItemsSource = DownloadsCenter.History;
+ downloadHistoryList.ItemsSource = DownloadsService.History;
// TODO: Add downloads list
UpdateList();
@@ -50,24 +50,24 @@ namespace FoxTube.Views
}
private async void OpenDefaultFolder(object sender, RoutedEventArgs e) =>
- await Launcher.LaunchFolderAsync(await DownloadsCenter.GetDefaultDownloadsFolder());
+ await Launcher.LaunchFolderAsync(await DownloadsService.GetDefaultDownloadsFolder());
private void OpenDownloadSettings(object sender, RoutedEventArgs e) =>
- Navigation.NavigateTo(NavigationTarget.Settings, "downloads");
+ Navigation.NavigateTo(typeof(SettingsView), "downloads");
public void UpdateList() =>
empty.Opacity = (((list.ItemsSource as List