Archived
1
0

Refactored core

UI navigation framework

Related Work Items: #408, #414, #416
This commit is contained in:
Michael Gordeev
2020-06-15 15:46:38 +03:00
parent c58d846057
commit 787a6e9f48
72 changed files with 2002 additions and 1227 deletions
+6 -9
View File
@@ -18,12 +18,9 @@ namespace FoxTube.Services
public static List<SavedVideo> History { get; } = new List<SavedVideo>();
public static List<DownloadItem> Queue { get; } = new List<DownloadItem>();
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<SavedVideo> savedVideos = JsonConvert.DeserializeObject<List<SavedVideo>>(File.ReadAllText(file.Path) ?? "") ?? new List<SavedVideo>();
@@ -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<StorageFolder> GetDefaultDownloadsFolder()
{
if (Storage.GetValue<string>(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<string>(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;
}
}
+35 -26
View File
@@ -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<string>(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<string[]>(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
/// <summary>
/// Fires toast notification with the last changelog content
/// </summary>
[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<string>(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)
{
+6 -1
View File
@@ -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<string>(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);
+67
View File
@@ -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
}
}
-101
View File
@@ -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<Settings> SettingsChanged;
public static StorageFolder Folder => ApplicationData.Current.RoamingFolder;
public static ApplicationDataContainer Registry { get; } = ApplicationData.Current.RoamingSettings;
private static readonly Dictionary<Settings, object> _defaultSettings = new Dictionary<Settings, object>
{
{ Settings.Theme, ElementTheme.Default },
{ Settings.UILanguage, GetDefaultLanguage() },
{ Settings.RelevanceLanguage, GetDefaultLanguage() },
{ Settings.PromptFeedback, true },
{ Settings.PromptReview, true },
{ Settings.AllowAnalytics, true }
};
public enum Settings
{
/// <summary>
/// ElementTheme
/// </summary>
Theme,
/// <summary>
/// string
/// </summary>
UILanguage,
/// <summary>
/// string
/// </summary>
RelevanceLanguage,
/// <summary>
/// string
/// </summary>
DefaultDownloadsFolder,
/// <summary>
/// bool
/// </summary>
PromptFeedback,
/// <summary>
/// bool
/// </summary>
PromptReview,
/// <summary>
/// bool
/// </summary>
AllowAnalytics,
/// <summary>
/// string
/// </summary>
Region
}
public enum Metrics
{
/// <summary>
/// TimeSpan
/// </summary>
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<T>(Settings key) =>
(T)(Registry.Values[$"{key.GetType().Name}.{key}"] ?? (_defaultSettings.ContainsKey(key) ? _defaultSettings[key] : null));
public static T GetValue<T>(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();
}
}
}
+77
View File
@@ -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
}
}
+7 -14
View File
@@ -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<bool> UserStateUpdated;
public static event EventHandler<Subscription> SubscriptionsChanged;
static UserService() =>
Initialize();
public static async Task<bool> 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<Userinfoplus[]>(Storage.Registry.Values[UsersStorageKey] as string ?? "") ?? new Userinfoplus[MaxUsersCount];
int? lastUserIndex = Storage.Registry.Values[LastUserInfoKey] as int?;
Users = JsonConvert.DeserializeObject<Userinfoplus[]>(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);