From bfc8689136137acfe491bd9fe525a9bb0e1863ac Mon Sep 17 00:00:00 2001 From: Michael Gordeev Date: Mon, 2 Dec 2019 16:52:49 +0300 Subject: [PATCH] Anyway, I am the only one who reads this, right? --- FoxTube.Background/FoxTube.Background.csproj | 26 +- FoxTube.Core/FoxTube.Core.csproj | 53 +- FoxTube.Core/Helpers.cs | 14 - FoxTube.Core/Helpers/Extensions.cs | 49 + FoxTube.Core/Helpers/Feedback.cs | 52 + FoxTube.Core/Helpers/Inbox.cs | 137 + FoxTube.Core/Helpers/Metrics.cs | 76 + FoxTube.Core/Helpers/Settings.cs | 118 + .../{Controllers => Helpers}/StoreInterop.cs | 12 +- FoxTube.Core/Helpers/Utils.cs | 36 + .../{Class1.cs => Models/IRefreshable.cs} | 5 +- FoxTube.Core/Models/Inbox/Changelog.cs | 19 + FoxTube.Core/Models/Inbox/DeveloperMessage.cs | 22 + FoxTube.Core/Models/Inbox/InboxItem.cs | 17 + FoxTube.Core/Models/Notifications.cs | 27 + FoxTube.Core/Properties/FoxTube.Core.rd.xml | 33 + FoxTube.sln | 42 +- FoxTube/App.xaml | 22 +- FoxTube/App.xaml.cs | 41 +- FoxTube/Controls/ItemsGrid.xaml.cs | 5 +- FoxTube/FoxTube.csproj | 79 +- FoxTube/Helpers/Utils.cs | 23 - FoxTube/MainPage.xaml | 9 +- FoxTube/MainPage.xaml.cs | 46 +- FoxTube/Themes/Resources.xaml | 18 - FoxTube/Views/Home.xaml | 6 +- FoxTube/Views/Home.xaml.cs | 8 +- FoxTube/Views/Settings.xaml | 38 + FoxTube/Views/Settings.xaml.cs | 35 + FoxTube/Views/SettingsSections/About.xaml | 62 + FoxTube/Views/SettingsSections/About.xaml.cs | 27 + FoxTube/Views/SettingsSections/General.xaml | 64 + .../Views/SettingsSections/General.xaml.cs | 137 + FoxTube/Views/SettingsSections/Inbox.xaml | 78 + FoxTube/Views/SettingsSections/Inbox.xaml.cs | 42 + FoxTube/Views/SettingsSections/Translate.xaml | 13 + .../Views/SettingsSections/Translate.xaml.cs | 30 + Src/18_Full.txt | 31 + Src/Untitled-1.json | 1 + Src/response.json | 7347 +++++++++++++++++ 40 files changed, 8722 insertions(+), 178 deletions(-) delete mode 100644 FoxTube.Core/Helpers.cs create mode 100644 FoxTube.Core/Helpers/Extensions.cs create mode 100644 FoxTube.Core/Helpers/Feedback.cs create mode 100644 FoxTube.Core/Helpers/Inbox.cs create mode 100644 FoxTube.Core/Helpers/Metrics.cs create mode 100644 FoxTube.Core/Helpers/Settings.cs rename FoxTube.Core/{Controllers => Helpers}/StoreInterop.cs (66%) create mode 100644 FoxTube.Core/Helpers/Utils.cs rename FoxTube.Core/{Class1.cs => Models/IRefreshable.cs} (59%) create mode 100644 FoxTube.Core/Models/Inbox/Changelog.cs create mode 100644 FoxTube.Core/Models/Inbox/DeveloperMessage.cs create mode 100644 FoxTube.Core/Models/Inbox/InboxItem.cs create mode 100644 FoxTube.Core/Models/Notifications.cs create mode 100644 FoxTube.Core/Properties/FoxTube.Core.rd.xml delete mode 100644 FoxTube/Helpers/Utils.cs delete mode 100644 FoxTube/Themes/Resources.xaml create mode 100644 FoxTube/Views/Settings.xaml create mode 100644 FoxTube/Views/Settings.xaml.cs create mode 100644 FoxTube/Views/SettingsSections/About.xaml create mode 100644 FoxTube/Views/SettingsSections/About.xaml.cs create mode 100644 FoxTube/Views/SettingsSections/General.xaml create mode 100644 FoxTube/Views/SettingsSections/General.xaml.cs create mode 100644 FoxTube/Views/SettingsSections/Inbox.xaml create mode 100644 FoxTube/Views/SettingsSections/Inbox.xaml.cs create mode 100644 FoxTube/Views/SettingsSections/Translate.xaml create mode 100644 FoxTube/Views/SettingsSections/Translate.xaml.cs create mode 100644 Src/18_Full.txt create mode 100644 Src/Untitled-1.json create mode 100644 Src/response.json diff --git a/FoxTube.Background/FoxTube.Background.csproj b/FoxTube.Background/FoxTube.Background.csproj index 3eec541..f154294 100644 --- a/FoxTube.Background/FoxTube.Background.csproj +++ b/FoxTube.Background/FoxTube.Background.csproj @@ -111,32 +111,8 @@ - - 1.30.0-beta02 - - - 1.30.0-beta02 - - - 1.30.0-beta02 - - - 1.29.2.994 - - - 1.29.2.1006 - - - 2.1.1 - - 6.2.8 - - - 5.1.1 - - - 4.7.6 + 6.2.9 diff --git a/FoxTube.Core/FoxTube.Core.csproj b/FoxTube.Core/FoxTube.Core.csproj index b6c2244..727e8b5 100644 --- a/FoxTube.Core/FoxTube.Core.csproj +++ b/FoxTube.Core/FoxTube.Core.csproj @@ -4,8 +4,8 @@ Debug AnyCPU - {797951D8-BF28-4659-BDF4-C17A583E64CD} - winmdobj + {29C01E10-76E7-4527-984F-B0EEF7E1AC64} + Library Properties FoxTube.Core FoxTube.Core @@ -16,7 +16,6 @@ 14 512 {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - false AnyCPU @@ -27,6 +26,7 @@ DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP prompt 4 + 8.0 AnyCPU @@ -36,6 +36,7 @@ TRACE;NETFX_CORE;WINDOWS_UWP prompt 4 + 8.0 x86 @@ -46,6 +47,7 @@ full false prompt + 8.0 x86 @@ -56,6 +58,7 @@ pdbonly false prompt + 8.0 ARM @@ -66,6 +69,7 @@ full false prompt + 8.0 ARM @@ -76,6 +80,7 @@ pdbonly false prompt + 8.0 ARM64 @@ -86,6 +91,7 @@ full false prompt + 8.0 ARM64 @@ -96,6 +102,7 @@ pdbonly false prompt + 8.0 x64 @@ -106,6 +113,7 @@ full false prompt + 8.0 x64 @@ -116,23 +124,54 @@ pdbonly false prompt + 8.0 PackageReference - - - + + + + + + + + + + + + + + + 0.13.0 + + + 2.6.1 + + + 2.6.1 + 6.2.9 + + 10.1901.28001 + - + + + + + Microsoft Engagement Framework + + + Visual C++ 2015 Runtime for Universal Windows Platform Apps + 14.0 diff --git a/FoxTube.Core/Helpers.cs b/FoxTube.Core/Helpers.cs deleted file mode 100644 index e152ef2..0000000 --- a/FoxTube.Core/Helpers.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace FoxTube.Core -{ - public static class Helpers - { - public static Uri ToUri(this string str) => - string.IsNullOrWhiteSpace(str) ? null : new Uri(str); - } -} diff --git a/FoxTube.Core/Helpers/Extensions.cs b/FoxTube.Core/Helpers/Extensions.cs new file mode 100644 index 0000000..9fdb790 --- /dev/null +++ b/FoxTube.Core/Helpers/Extensions.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Windows.Data.Xml.Dom; +using Windows.UI; + +namespace FoxTube +{ + public static class Extensions + { + public static Uri ToUri(this string url) + { + try { return new Uri(url); } + catch { return null; } + } + + public static XmlDocument ToXml(this string text) + { + XmlDocument doc = new XmlDocument(); + try + { + doc.LoadXml(text); + return doc; + } + catch { return null; } + } + + public static bool Belongs(this T obj, params T[] args) => + args.Contains(obj); + + public static string ToHex(this Color color) => + $"#{color.R:X}{color.G:X}{color.B:X}"; + + public static Color FromHex(this Color parent, string hex) + { + hex = hex.Replace("#", ""); + List values = new List(); + for(int k = 0; k < hex.Length; k++) + values.Add(byte.Parse(string.Join("", hex[k], hex[++k]), System.Globalization.NumberStyles.HexNumber)); + + return hex.Length switch + { + 6 => Color.FromArgb(255, values[0], values[1], values[2]), + 8 => Color.FromArgb(values[0], values[1], values[2], values[3]), + _ => Colors.Black + }; + } + } +} diff --git a/FoxTube.Core/Helpers/Feedback.cs b/FoxTube.Core/Helpers/Feedback.cs new file mode 100644 index 0000000..4814833 --- /dev/null +++ b/FoxTube.Core/Helpers/Feedback.cs @@ -0,0 +1,52 @@ +using System; +using Microsoft.Services.Store.Engagement; +using Windows.UI.Popups; + +namespace FoxTube.Core.Helpers +{ + public static class Feedback + { + public static bool HasFeedbackHub => StoreServicesFeedbackLauncher.IsSupported(); + + public static async void OpenFeedbackHub() + { + if (HasFeedbackHub) + await StoreServicesFeedbackLauncher.GetDefault().LaunchAsync(); + } + + public static async void PromptFeedback() + { + if (!HasFeedbackHub) + { + Settings.PromptFeedback = false; + return; + } + + MessageDialog dialog = new MessageDialog("Have some thoughts to share about the app or any suggestions? Leave feedback!"); + dialog.Commands.Add(new UICommand("Don't ask me anymore", (command) => Settings.PromptFeedback = false)); + dialog.Commands.Add(new UICommand("Maybe later")); + dialog.Commands.Add(new UICommand("Sure!", (command) => + { + Settings.PromptFeedback = false; + OpenFeedbackHub(); + })); + dialog.DefaultCommandIndex = 2; + dialog.CancelCommandIndex = 1; + await dialog.ShowAsync(); + } + public static async void PromptReview() + { + MessageDialog dialog = new MessageDialog("Like our app? Review it on Microsoft Store!"); + dialog.Commands.Add(new UICommand("Don't ask me anymore", (command) => Settings.PromptReview = false)); + dialog.Commands.Add(new UICommand("Maybe later")); + dialog.Commands.Add(new UICommand("Sure!", (command) => + { + StoreInterop.RequestReview(); + Settings.PromptReview = false; + })); + dialog.DefaultCommandIndex = 2; + dialog.CancelCommandIndex = 1; + await dialog.ShowAsync(); + } + } +} diff --git a/FoxTube.Core/Helpers/Inbox.cs b/FoxTube.Core/Helpers/Inbox.cs new file mode 100644 index 0000000..c7d84a6 --- /dev/null +++ b/FoxTube.Core/Helpers/Inbox.cs @@ -0,0 +1,137 @@ +using FoxTube.Core.Models; +using FoxTube.Core.Models.Inbox; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Threading.Tasks; +using Windows.Data.Xml.Dom; +using Windows.Storage; +using Windows.UI.Notifications; + +namespace FoxTube.Core.Helpers +{ + public static class Inbox + { + static HttpClient client = new HttpClient(); + static ApplicationDataContainer storage = ApplicationData.Current.RoamingSettings; + + public static async Task>GetInbox() + { + List list = new List(); + list.AddRange(await GetMessages()); + list.AddRange(await GetChangelogs()); + list.OrderByDescending(i => i.TimeStamp); + + return list; + } + + public static async void PushNew() + { + try + { + // TODO: Add backend + HttpResponseMessage response = await client.GetAsync("https://xfox111.net/FoxTube/Messages?toast=true&publishedAfter=" + storage.Values["Inbox.lastCheck"] + "&lang=" + Settings.Language); + + if (response.StatusCode == System.Net.HttpStatusCode.NoContent) + return; + + XmlDocument doc = new XmlDocument(); + doc.LoadXml(await response.Content.ReadAsStringAsync()); + foreach (IXmlNode toast in doc.LastChild.ChildNodes) + ToastNotificationManager.CreateToastNotifier().Show(new ToastNotification(toast.GetXml().ToXml())); + + storage.Values["Inbox.lastCheck"] = DateTime.Now; + } + catch (Exception e) + { + Metrics.AddEvent("Unable to retrieve developers' messages", + ("Exception", e.GetType().ToString()), + ("Message", e.Message), + ("App version", Metrics.CurrentVersion), + ("StackTrace", e.StackTrace)); + } + } + + static async Task>GetChangelogs() + { + List list = new List(); + try + { + // TODO: Add backend + HttpResponseMessage response = await client.GetAsync("https://xfox111.net/FoxTube/Changelogs?lang=" + Settings.Language); + + if (response.StatusCode == System.Net.HttpStatusCode.NoContent) + return list; + + dynamic responseObj = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); + foreach (var item in responseObj) + list.Add(new Changelog(item.Version, item.Content, item.Description, item.TimeStamp)); + } + catch (Exception e) + { + Metrics.AddEvent("Unable to retrieve changelogs", + ("Exception", e.GetType().ToString()), + ("Message", e.Message), + ("App version", Metrics.CurrentVersion), + ("StackTrace", e.StackTrace)); + } + + return list; + } + static async Task>GetMessages() + { + List list = new List(); + try + { + // TODO: Add backend + HttpResponseMessage response = await client.GetAsync("https://xfox111.net/FoxTube/Messages?lang=" + Settings.Language); + + if (response.StatusCode == System.Net.HttpStatusCode.NoContent) + return list; + + dynamic responseObj = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); + foreach (var item in responseObj) + list.Add(new DeveloperMessage(item.Id, item.Title, item.Content, item.TimeStamp, item.Avatar)); + } + catch (Exception e) + { + Metrics.AddEvent("Unable to retrieve developers' messages", + ("Exception", e.GetType().ToString()), + ("Message", e.Message), + ("App version", Metrics.CurrentVersion), + ("StackTrace", e.StackTrace)); + } + + return list; + } + + /// + /// Fires toast notification with the last changelog content + /// + public static async void PushChangelog() + { + try + { + // TODO: Add backend + Settings.LastReviewedVersion = Metrics.CurrentVersion; + + HttpResponseMessage response = await client.GetAsync("https://xfox111.net/FoxTube/Changelogs?toast=true&lang=" + Settings.Language + "&version=" + Metrics.CurrentVersion); + + if (response.StatusCode == System.Net.HttpStatusCode.NoContent) + return; + + ToastNotificationManager.CreateToastNotifier().Show(new ToastNotification((await response.Content.ReadAsStringAsync()).ToXml())); + } + catch (Exception e) + { + Metrics.AddEvent("Unable to retrieve changelog", + ("Exception", e.GetType().ToString()), + ("Message", e.Message), + ("App version", Metrics.CurrentVersion), + ("StackTrace", e.StackTrace)); + } + } + } +} diff --git a/FoxTube.Core/Helpers/Metrics.cs b/FoxTube.Core/Helpers/Metrics.cs new file mode 100644 index 0000000..18069c1 --- /dev/null +++ b/FoxTube.Core/Helpers/Metrics.cs @@ -0,0 +1,76 @@ +using Microsoft.AppCenter; +using Microsoft.AppCenter.Analytics; +using Microsoft.AppCenter.Crashes; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Net.Http; +using System.Threading.Tasks; +using Windows.ApplicationModel; +using Windows.Storage; + +namespace FoxTube +{ + public static class Metrics + { + static readonly ApplicationDataContainer storage = ApplicationData.Current.RoamingSettings; + + static readonly Stopwatch sw = new Stopwatch(); + public static TimeSpan Uptime + { + get => (TimeSpan?)storage.Values["Metrics.SpentTime"] ?? TimeSpan.FromSeconds(0); + set => storage.Values["Metrics.SpentTime"] = value; + } + public static string CurrentVersion + { + get + { + PackageVersion v = Package.Current.Id.Version; + return $"{v.Major}.{v.Minor}.{v.Revision}.{v.Build}"; + } + } + + public static void StartSession() + { + sw.Start(); + AppCenter.Start("45774462-9ea7-438a-96fc-03982666f39e", typeof(Analytics), typeof(Crashes)); + AppCenter.SetCountryCode(Settings.Region); + } + + public static void EndSession() + { + sw.Stop(); + Uptime += sw.Elapsed; + + AddEvent("Session closed", + ("Duration", sw.Elapsed.ToString()), + ("Spend time total", Uptime.ToString())); + } + + public static void AddEvent(string eventName, params (string key, string value)[] details) + { + Dictionary parameters = new Dictionary(); + foreach (var (key, value) in details) + parameters.Add(key, value); + Analytics.TrackEvent(eventName, parameters.Count > 0 ? parameters : null); + } + + public static async Task SendExtendedData(string packageTitle, string content) + { + // TODO: Add backend + using(HttpClient client = new HttpClient()) + { + HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "https://xfox111.net/FoxTube/AddMetrics"); + Dictionary body = new Dictionary + { + { "Title", packageTitle }, + { "Content", content }, + { "Version", CurrentVersion } + }; + request.Content = new FormUrlEncodedContent(body); + HttpResponseMessage response = await client.SendAsync(request); + return await response.Content.ReadAsStringAsync(); + } + } + } +} diff --git a/FoxTube.Core/Helpers/Settings.cs b/FoxTube.Core/Helpers/Settings.cs new file mode 100644 index 0000000..c9d38c4 --- /dev/null +++ b/FoxTube.Core/Helpers/Settings.cs @@ -0,0 +1,118 @@ +using System.Globalization; +using Windows.Storage; + +namespace FoxTube +{ + public static class Settings + { + static readonly ApplicationDataContainer settings = ApplicationData.Current.RoamingSettings; + + public static string DesiredVideoQuality + { + get => (string)settings.Values["DesiredVideoQuality"] ?? "auto"; + set => settings.Values["DesiredVideoQuality"] = value; + } + public static string RememberedQuality + { + get => (string)settings.Values["RememberedVideoQuality"] ?? "1080p"; + set => settings.Values["RememberedVideoQuality"] = value; + } + public static bool VideoNotifications + { + get => (bool?)settings.Values["NewVideosNotificationsAll"] ?? true; + set => settings.Values["NewVideosNotificationsAll"] = value; + } + public static bool DevNotifications + { + get => (bool?)settings.Values["DevelopersNewsNotifications"] ?? true; + set => settings.Values["DevelopersNewsNotifications"] = value; + } + public static bool CheckConnection + { + get => (bool?)settings.Values["WarnIfOnMeteredConnection"] ?? false; + set => settings.Values["WarnIfOnMeteredConnection"] = value; + } + public static bool Autoplay + { + get => (bool?)settings.Values["VideoAutoplay"] ?? true; + set => settings.Values["VideoAutoplay"] = value; + } + public static double Volume + { + get => (double?)settings.Values["Volume"] ?? 1; + set => settings.Values["Volume"] = value; + } + public static string Language + { + get => (string)settings.Values["InterfaceLanguage"] ?? GetDefaultLanguage(); + set => settings.Values["InterfaceLanguage"] = value; + } + public static string RelevanceLanguage + { + get => (string)settings.Values["DesiredContentLanguage"] ?? CultureInfo.InstalledUICulture.TwoLetterISOLanguageName; + set => settings.Values["DesiredContentLanguage"] = value; + } + public static string Region + { + get => (string)settings.Values["Region"] ?? CultureInfo.InstalledUICulture.Name.Split('-')[1]; + set => settings.Values["Region"] = value; + } + public static int SafeSearch + { + get => (int?)settings.Values["SafeSearch"] ?? 0; //Moderate + set => settings.Values["SafeSearch"] = value; + } + public static bool BlockExplicitContent + { + get => (bool?)settings.Values["BlockExplicitContent"] ?? true; + set => settings.Values["BlockExplicitContent"] = value; + } + + public static bool HasAccount + { + get => (bool?)settings.Values["HasAccount"] ?? false; + set => settings.Values["HasAccount"] = value; + } + public static int Theme + { + get => (int?)settings.Values["PreferedUITheme"] ?? 2; //System + set => settings.Values["PreferedUITheme"] = value; + } + public static bool PromptReview + { + get => (bool?)settings.Values["PromptReview"] ?? Metrics.Uptime.TotalHours > 24; + set => settings.Values["PromptReview"] = value; + } + public static bool PromptFeedback + { + get => (bool?)settings.Values["PromptFeedback"] ?? Metrics.Uptime.TotalHours > 12; + set => settings.Values["PromptFeedback"] = value; + } + public static bool ProcessClipboard + { + get => (bool?)settings.Values["ProcessClipboardEntry"] ?? true; + set => settings.Values["ProcessClipboardEntry"] = value; + } + public static string LastReviewedVersion + { + get + { + if (settings.Values["LastReviewedVersion"] == null) + settings.Values["LastReviewedVersion"] = Metrics.CurrentVersion; + return (string)settings.Values["LastReviewedVersion"]; + } + set => settings.Values["LastReviewedVersion"] = value; + } + + 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 void ResetSettings() => + settings.Values.Clear(); + } +} diff --git a/FoxTube.Core/Controllers/StoreInterop.cs b/FoxTube.Core/Helpers/StoreInterop.cs similarity index 66% rename from FoxTube.Core/Controllers/StoreInterop.cs rename to FoxTube.Core/Helpers/StoreInterop.cs index 7fd706d..9ef6c22 100644 --- a/FoxTube.Core/Controllers/StoreInterop.cs +++ b/FoxTube.Core/Helpers/StoreInterop.cs @@ -2,7 +2,7 @@ using System.Threading.Tasks; using Windows.Services.Store; -namespace FoxTube.Core.Controllers +namespace FoxTube.Core.Helpers { public static class StoreInterop { @@ -34,5 +34,15 @@ namespace FoxTube.Core.Controllers return false; } } + + public static async void RequestReview() + { + StoreRateAndReviewResult result = await StoreContext.GetDefault().RequestRateAndReviewAppAsync(); + + string attachedPackageId = result.Status == StoreRateAndReviewStatus.Error ? await Metrics.SendExtendedData("StoreReviewRequestError", result.ExtendedJsonData) : "Success"; + Metrics.AddEvent("Store review request has been recieved", + ("Result", result.Status.ToString()), + ("ErrorData", attachedPackageId)); + } } } diff --git a/FoxTube.Core/Helpers/Utils.cs b/FoxTube.Core/Helpers/Utils.cs new file mode 100644 index 0000000..29d87cd --- /dev/null +++ b/FoxTube.Core/Helpers/Utils.cs @@ -0,0 +1,36 @@ +using System; +using System.Net.Http; +using Windows.ApplicationModel.Core; +using Windows.UI.Notifications; + +namespace FoxTube.Core.Helpers +{ + public static class Utils + { + /// + /// Terminates current application session + /// + public static void CloseApp() => + CoreApplication.Exit(); + + /// + /// Restarts application + /// + public static void RestartApp() => + RestartApp(null); + + /// + /// Restarts application with specified parameters + /// + /// Parameters which will be provided to new application instance + public static async void RestartApp(string args) => + await CoreApplication.RequestRestartAsync(args); + + public static void InitializeFailsafeProtocol() + { + Metrics.AddEvent("Failsafe protocol initiated"); + Settings.ResetSettings(); + RestartApp(); + } + } +} diff --git a/FoxTube.Core/Class1.cs b/FoxTube.Core/Models/IRefreshable.cs similarity index 59% rename from FoxTube.Core/Class1.cs rename to FoxTube.Core/Models/IRefreshable.cs index ada58be..59324f1 100644 --- a/FoxTube.Core/Class1.cs +++ b/FoxTube.Core/Models/IRefreshable.cs @@ -4,9 +4,10 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace FoxTube.Core +namespace FoxTube.Core.Models { - public sealed class Class1 + public interface IRefreshable { + void RefreshPage(); } } diff --git a/FoxTube.Core/Models/Inbox/Changelog.cs b/FoxTube.Core/Models/Inbox/Changelog.cs new file mode 100644 index 0000000..ec3660b --- /dev/null +++ b/FoxTube.Core/Models/Inbox/Changelog.cs @@ -0,0 +1,19 @@ +using System; + +namespace FoxTube.Core.Models.Inbox +{ + public class Changelog : InboxItem + { + public override string DefaultIcon => "\xE728"; + public override string Title => "What's new in version " + Id; + public override string Type => "Changelog"; + + public Changelog(string version, string content, string description, DateTime timeStamp) + { + Id = version; + Content = content; + Description = description; + TimeStamp = timeStamp; + } + } +} diff --git a/FoxTube.Core/Models/Inbox/DeveloperMessage.cs b/FoxTube.Core/Models/Inbox/DeveloperMessage.cs new file mode 100644 index 0000000..7202e21 --- /dev/null +++ b/FoxTube.Core/Models/Inbox/DeveloperMessage.cs @@ -0,0 +1,22 @@ +using System; + +namespace FoxTube.Core.Models.Inbox +{ + public class DeveloperMessage : InboxItem + { + public override string DefaultIcon => "\xE119"; + public override string Title => _title; + string _title; + public override string Type => "Message from developers"; + + public DeveloperMessage(string id, string title, string content, DateTime timeStamp, string avatar) + { + Id = id; + _title = title; + Content = content; + Description = content; + TimeStamp = timeStamp; + Avatar = avatar; + } + } +} diff --git a/FoxTube.Core/Models/Inbox/InboxItem.cs b/FoxTube.Core/Models/Inbox/InboxItem.cs new file mode 100644 index 0000000..0837b65 --- /dev/null +++ b/FoxTube.Core/Models/Inbox/InboxItem.cs @@ -0,0 +1,17 @@ +using System; + +namespace FoxTube.Core.Models +{ + public abstract class InboxItem + { + public string Id { get; set; } + public abstract string DefaultIcon { get; } + public string Avatar { get; set; } + public abstract string Title { get; } + public string Description { get; set; } + public string Content { get; set; } + public DateTime TimeStamp { get; set; } + public abstract string Type { get; } + + } +} diff --git a/FoxTube.Core/Models/Notifications.cs b/FoxTube.Core/Models/Notifications.cs new file mode 100644 index 0000000..2e88e3f --- /dev/null +++ b/FoxTube.Core/Models/Notifications.cs @@ -0,0 +1,27 @@ +using Windows.Data.Xml.Dom; +using Windows.UI.Notifications; + +namespace FoxTube.Core.Models +{ + public static class Notifications + { + public static ToastNotification GetChangelogToast(string version) + { + XmlDocument template = new XmlDocument(); + + // TODO: Add backend + template.LoadXml($@" + + + + + Changelog + See what's new in {version} + + + "); + + return new ToastNotification(template); + } + } +} diff --git a/FoxTube.Core/Properties/FoxTube.Core.rd.xml b/FoxTube.Core/Properties/FoxTube.Core.rd.xml new file mode 100644 index 0000000..3060f4c --- /dev/null +++ b/FoxTube.Core/Properties/FoxTube.Core.rd.xml @@ -0,0 +1,33 @@ + + + + + + + + + diff --git a/FoxTube.sln b/FoxTube.sln index 46772a3..666217c 100644 --- a/FoxTube.sln +++ b/FoxTube.sln @@ -9,7 +9,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FoxTube.Background", "FoxTu EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FoxTube.Tests", "FoxTube.Tests\FoxTube.Tests.csproj", "{3D864717-2D87-4E54-BFC0-755FC2FCA2A7}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FoxTube.Core", "FoxTube.Core\FoxTube.Core.csproj", "{797951D8-BF28-4659-BDF4-C17A583E64CD}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FoxTube.Core", "FoxTube.Core\FoxTube.Core.csproj", "{29C01E10-76E7-4527-984F-B0EEF7E1AC64}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -93,26 +93,26 @@ Global {3D864717-2D87-4E54-BFC0-755FC2FCA2A7}.Release|x86.ActiveCfg = Release|x86 {3D864717-2D87-4E54-BFC0-755FC2FCA2A7}.Release|x86.Build.0 = Release|x86 {3D864717-2D87-4E54-BFC0-755FC2FCA2A7}.Release|x86.Deploy.0 = Release|x86 - {797951D8-BF28-4659-BDF4-C17A583E64CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {797951D8-BF28-4659-BDF4-C17A583E64CD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {797951D8-BF28-4659-BDF4-C17A583E64CD}.Debug|ARM.ActiveCfg = Debug|ARM - {797951D8-BF28-4659-BDF4-C17A583E64CD}.Debug|ARM.Build.0 = Debug|ARM - {797951D8-BF28-4659-BDF4-C17A583E64CD}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {797951D8-BF28-4659-BDF4-C17A583E64CD}.Debug|ARM64.Build.0 = Debug|ARM64 - {797951D8-BF28-4659-BDF4-C17A583E64CD}.Debug|x64.ActiveCfg = Debug|x64 - {797951D8-BF28-4659-BDF4-C17A583E64CD}.Debug|x64.Build.0 = Debug|x64 - {797951D8-BF28-4659-BDF4-C17A583E64CD}.Debug|x86.ActiveCfg = Debug|x86 - {797951D8-BF28-4659-BDF4-C17A583E64CD}.Debug|x86.Build.0 = Debug|x86 - {797951D8-BF28-4659-BDF4-C17A583E64CD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {797951D8-BF28-4659-BDF4-C17A583E64CD}.Release|Any CPU.Build.0 = Release|Any CPU - {797951D8-BF28-4659-BDF4-C17A583E64CD}.Release|ARM.ActiveCfg = Release|ARM - {797951D8-BF28-4659-BDF4-C17A583E64CD}.Release|ARM.Build.0 = Release|ARM - {797951D8-BF28-4659-BDF4-C17A583E64CD}.Release|ARM64.ActiveCfg = Release|ARM64 - {797951D8-BF28-4659-BDF4-C17A583E64CD}.Release|ARM64.Build.0 = Release|ARM64 - {797951D8-BF28-4659-BDF4-C17A583E64CD}.Release|x64.ActiveCfg = Release|x64 - {797951D8-BF28-4659-BDF4-C17A583E64CD}.Release|x64.Build.0 = Release|x64 - {797951D8-BF28-4659-BDF4-C17A583E64CD}.Release|x86.ActiveCfg = Release|x86 - {797951D8-BF28-4659-BDF4-C17A583E64CD}.Release|x86.Build.0 = Release|x86 + {29C01E10-76E7-4527-984F-B0EEF7E1AC64}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {29C01E10-76E7-4527-984F-B0EEF7E1AC64}.Debug|Any CPU.Build.0 = Debug|Any CPU + {29C01E10-76E7-4527-984F-B0EEF7E1AC64}.Debug|ARM.ActiveCfg = Debug|ARM + {29C01E10-76E7-4527-984F-B0EEF7E1AC64}.Debug|ARM.Build.0 = Debug|ARM + {29C01E10-76E7-4527-984F-B0EEF7E1AC64}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {29C01E10-76E7-4527-984F-B0EEF7E1AC64}.Debug|ARM64.Build.0 = Debug|ARM64 + {29C01E10-76E7-4527-984F-B0EEF7E1AC64}.Debug|x64.ActiveCfg = Debug|x64 + {29C01E10-76E7-4527-984F-B0EEF7E1AC64}.Debug|x64.Build.0 = Debug|x64 + {29C01E10-76E7-4527-984F-B0EEF7E1AC64}.Debug|x86.ActiveCfg = Debug|x86 + {29C01E10-76E7-4527-984F-B0EEF7E1AC64}.Debug|x86.Build.0 = Debug|x86 + {29C01E10-76E7-4527-984F-B0EEF7E1AC64}.Release|Any CPU.ActiveCfg = Release|Any CPU + {29C01E10-76E7-4527-984F-B0EEF7E1AC64}.Release|Any CPU.Build.0 = Release|Any CPU + {29C01E10-76E7-4527-984F-B0EEF7E1AC64}.Release|ARM.ActiveCfg = Release|ARM + {29C01E10-76E7-4527-984F-B0EEF7E1AC64}.Release|ARM.Build.0 = Release|ARM + {29C01E10-76E7-4527-984F-B0EEF7E1AC64}.Release|ARM64.ActiveCfg = Release|ARM64 + {29C01E10-76E7-4527-984F-B0EEF7E1AC64}.Release|ARM64.Build.0 = Release|ARM64 + {29C01E10-76E7-4527-984F-B0EEF7E1AC64}.Release|x64.ActiveCfg = Release|x64 + {29C01E10-76E7-4527-984F-B0EEF7E1AC64}.Release|x64.Build.0 = Release|x64 + {29C01E10-76E7-4527-984F-B0EEF7E1AC64}.Release|x86.ActiveCfg = Release|x86 + {29C01E10-76E7-4527-984F-B0EEF7E1AC64}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/FoxTube/App.xaml b/FoxTube/App.xaml index 3f5f37b..4a4243f 100644 --- a/FoxTube/App.xaml +++ b/FoxTube/App.xaml @@ -6,9 +6,29 @@ - + + Red + + + diff --git a/FoxTube/App.xaml.cs b/FoxTube/App.xaml.cs index 060f634..87ddf64 100644 --- a/FoxTube/App.xaml.cs +++ b/FoxTube/App.xaml.cs @@ -1,17 +1,29 @@ -using FoxTube.Core.Controllers; +using System; +using FoxTube.Core.Helpers; +using Windows.ApplicationModel; using Windows.ApplicationModel.Activation; +using Windows.UI; +using Windows.UI.Popups; +using Windows.UI.ViewManagement; using Windows.UI.Xaml; namespace FoxTube { sealed partial class App : Application { - public App() => + public App() + { InitializeComponent(); + Suspending += OnSuspending; + UnhandledException += ErrorOccured; + Metrics.StartSession(); + } protected override async void OnLaunched(LaunchActivatedEventArgs e) { await StoreInterop.UpdateStoreState(); + if (Settings.LastReviewedVersion != Metrics.CurrentVersion) + Inbox.PushChangelog(); if (!e.PrelaunchActivated && Window.Current.Content == null) Window.Current.Content = new MainPage(); @@ -34,5 +46,30 @@ namespace FoxTube Window.Current.Content = new MainPage(); Window.Current.Activate(); } + + void OnSuspending(object sender, SuspendingEventArgs e) + { + Metrics.EndSession(); + } + + async void ErrorOccured(object sender, Windows.UI.Xaml.UnhandledExceptionEventArgs e) + { + Metrics.AddEvent("Application chrashed", + ("Exception", e.Exception.GetType().ToString()), + ("Message", e.Message), + ("StackTrace", e.Exception.StackTrace)); + e.Handled = true; + + MessageDialog alert = new MessageDialog($"Exception: {e.Exception.GetType().ToString()}\nMessage: {e.Message}\n\nIf this happens again try to reset your app settings or report the problem", + "Unhandled error occured"); + alert.Commands.Add(new UICommand("Reset application", (command) => Utils.InitializeFailsafeProtocol())); + if(Feedback.HasFeedbackHub) + alert.Commands.Add(new UICommand("Report the problem", (command) => Feedback.OpenFeedbackHub())); + alert.Commands.Add(new UICommand("Close")); + + alert.DefaultCommandIndex = 0; + alert.CancelCommandIndex = 2; + await alert.ShowAsync(); + } } } diff --git a/FoxTube/Controls/ItemsGrid.xaml.cs b/FoxTube/Controls/ItemsGrid.xaml.cs index 7534877..a62d8e5 100644 --- a/FoxTube/Controls/ItemsGrid.xaml.cs +++ b/FoxTube/Controls/ItemsGrid.xaml.cs @@ -1,5 +1,4 @@ using FoxTube.Controls.Cards; -using FoxTube.Core.Controllers; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; @@ -17,8 +16,8 @@ namespace FoxTube.Controls { empty.Opacity = 0; - if (!StoreInterop.AdsDisabled && ItemsCount % 5 == 0 && ItemsCount > 0) - Items.Add(new AdvertCard()); + //if (!StoreInterop.AdsDisabled && ItemsCount % 5 == 0 && ItemsCount > 0) + // Items.Add(new AdvertCard()); Items.Add(item); } diff --git a/FoxTube/FoxTube.csproj b/FoxTube/FoxTube.csproj index 0374fe1..f01fe09 100644 --- a/FoxTube/FoxTube.csproj +++ b/FoxTube/FoxTube.csproj @@ -123,7 +123,6 @@ ItemsGrid.xaml - MainPage.xaml @@ -131,6 +130,21 @@ Home.xaml + + Settings.xaml + + + About.xaml + + + General.xaml + + + Inbox.xaml + + + Translate.xaml + @@ -228,64 +242,44 @@ Designer MSBuild:Compile - + Designer MSBuild:Compile - + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + Designer MSBuild:Compile - - 0.13.0 - - - 1.40.3 - - - 1.40.3 - - - 1.40.3 - - - 1.40.3.1602 - - - 1.40.3.1663 - 10.1811.22001 - - 2.5.0 - 6.2.9 - - 10.1901.28001 - - - 5.1.1 - - 5.1.1 + 6.0.0 2.2.190917002 - - 4.3.2 - - - 4.3.0 - - - 4.7.10 - @@ -293,7 +287,7 @@ FoxTube.Background - {797951d8-bf28-4659-bdf4-c17a583e64cd} + {29c01e10-76e7-4527-984f-b0eef7e1ac64} FoxTube.Core @@ -301,9 +295,6 @@ Microsoft Advertising SDK for XAML - - Microsoft Engagement Framework - diff --git a/FoxTube/Helpers/Utils.cs b/FoxTube/Helpers/Utils.cs deleted file mode 100644 index cd6c1e5..0000000 --- a/FoxTube/Helpers/Utils.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Microsoft.Services.Store.Engagement; -using System; -using Windows.ApplicationModel.Core; - -namespace FoxTube.Helpers -{ - public static class Utils - { - public static bool HasFeedbackHub => StoreServicesFeedbackLauncher.IsSupported(); - - public static async void OpenFeedbackHub() - { - if(HasFeedbackHub) - await StoreServicesFeedbackLauncher.GetDefault().LaunchAsync(); - } - - public static void CloseApp() => - CoreApplication.Exit(); - - public static async void RestartApp(string args = "") => - await CoreApplication.RequestRestartAsync(args); - } -} diff --git a/FoxTube/MainPage.xaml b/FoxTube/MainPage.xaml index 0f47db8..768517d 100644 --- a/FoxTube/MainPage.xaml +++ b/FoxTube/MainPage.xaml @@ -9,7 +9,7 @@ xmlns:controls="using:FoxTube.Controls" xmlns:toolkit="using:Microsoft.Toolkit.Uwp.UI.Controls"> - + @@ -81,11 +81,16 @@ + + + + + - + diff --git a/FoxTube/MainPage.xaml.cs b/FoxTube/MainPage.xaml.cs index e4cfd45..c199e5b 100644 --- a/FoxTube/MainPage.xaml.cs +++ b/FoxTube/MainPage.xaml.cs @@ -1,5 +1,5 @@ -using FoxTube.Core.Controllers; -using FoxTube.Helpers; +using FoxTube.Core.Helpers; +using FoxTube.Core.Models; using FoxTube.Views; using System; using Windows.ApplicationModel.Core; @@ -9,19 +9,25 @@ using Windows.UI.Popups; using Windows.UI.ViewManagement; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Navigation; namespace FoxTube { public sealed partial class MainPage : Page { - static MainPage Current { get; set; } + public static MainPage Current { get; set; } public MainPage() { Current = this; InitializeComponent(); + if (Settings.Theme == 0) + RequestedTheme = ElementTheme.Light; + else if (Settings.Theme == 1) + RequestedTheme = ElementTheme.Dark; + // TODO: Remove this - content.Navigate(typeof(Home)); + content.Navigate(typeof(Views.Settings)); Window.Current.SetTitleBar(AppTitleBar); @@ -29,20 +35,27 @@ namespace FoxTube ApplicationViewTitleBar titleBar = ApplicationView.GetForCurrentView().TitleBar; titleBar.ButtonBackgroundColor = Colors.Transparent; - titleBar.ButtonHoverForegroundColor = Colors.White; - titleBar.ButtonPressedForegroundColor = Colors.White; titleBar.ButtonHoverBackgroundColor = Color.FromArgb(50, 255, 255, 255); titleBar.ButtonPressedBackgroundColor = Color.FromArgb(20, 255, 255, 255); - if (Application.Current.RequestedTheme == ApplicationTheme.Dark) - titleBar.ButtonForegroundColor = Colors.White; + if (RequestedTheme == ElementTheme.Default) + titleBar.ButtonForegroundColor = + titleBar.ButtonHoverForegroundColor = + titleBar.ButtonPressedForegroundColor = Application.Current.RequestedTheme == ApplicationTheme.Dark ? Colors.White : Colors.Black; else - titleBar.ForegroundColor = Colors.Black; + titleBar.ButtonForegroundColor = + titleBar.ButtonHoverForegroundColor = + titleBar.ButtonPressedForegroundColor = RequestedTheme == ElementTheme.Dark ? Colors.White : Colors.Black; - LeaveFeedback.Visibility = Utils.HasFeedbackHub ? Visibility.Visible : Visibility.Collapsed; + LeaveFeedback.Visibility = Feedback.HasFeedbackHub ? Visibility.Visible : Visibility.Collapsed; RemoveAds.Visibility = StoreInterop.AdsDisabled ? Visibility.Collapsed : Visibility.Visible; if (!StoreInterop.AdsDisabled) RemoveAds.Content += $" ({StoreInterop.Price})"; + + if (Settings.PromptReview) + Feedback.PromptReview(); + if (Settings.PromptFeedback) + Feedback.PromptFeedback(); } void NavigationView_DisplayModeChanged(Microsoft.UI.Xaml.Controls.NavigationView sender, Microsoft.UI.Xaml.Controls.NavigationViewDisplayModeChangedEventArgs args) @@ -87,7 +100,7 @@ namespace FoxTube } void LeaveFeedback_Click(object sender, RoutedEventArgs e) => - Utils.OpenFeedbackHub(); + Feedback.OpenFeedbackHub(); async void RemoveAds_Tapped(object sender, Windows.UI.Xaml.Input.TappedRoutedEventArgs e) { @@ -105,7 +118,18 @@ namespace FoxTube public static void Navigate(Type pageType) { + + } + void Content_Navigated(object sender, NavigationEventArgs e) => + refresh.Visibility = (e.Content is IRefreshable) ? Visibility.Visible : Visibility.Collapsed; + + void Refresh_Click(object sender, RoutedEventArgs e) + { + if (video.Content != null) + (video.Content as IRefreshable)?.RefreshPage(); + else + (content.Content as IRefreshable)?.RefreshPage(); } } } diff --git a/FoxTube/Themes/Resources.xaml b/FoxTube/Themes/Resources.xaml deleted file mode 100644 index c038322..0000000 --- a/FoxTube/Themes/Resources.xaml +++ /dev/null @@ -1,18 +0,0 @@ - - - Red - - - - - diff --git a/FoxTube/Views/Home.xaml b/FoxTube/Views/Home.xaml index 589a61a..566d7ce 100644 --- a/FoxTube/Views/Home.xaml +++ b/FoxTube/Views/Home.xaml @@ -10,7 +10,7 @@ mc:Ignorable="d"> - + @@ -25,7 +25,7 @@ - + @@ -40,7 +40,7 @@ - + diff --git a/FoxTube/Views/Home.xaml.cs b/FoxTube/Views/Home.xaml.cs index 59ebe6b..2bbaa15 100644 --- a/FoxTube/Views/Home.xaml.cs +++ b/FoxTube/Views/Home.xaml.cs @@ -1,4 +1,5 @@ using FoxTube.Controls.Cards; +using FoxTube.Core.Models; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Navigation; @@ -9,11 +10,16 @@ namespace FoxTube.Views /// /// An empty page that can be used on its own or navigated to within a Frame. /// - public sealed partial class Home : Page + public sealed partial class Home : Page, IRefreshable { public Home() => InitializeComponent(); + public void RefreshPage() + { + throw new System.NotImplementedException(); + } + protected override void OnNavigatedTo(NavigationEventArgs e) { base.OnNavigatedTo(e); diff --git a/FoxTube/Views/Settings.xaml b/FoxTube/Views/Settings.xaml new file mode 100644 index 0000000..51afdea --- /dev/null +++ b/FoxTube/Views/Settings.xaml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FoxTube/Views/Settings.xaml.cs b/FoxTube/Views/Settings.xaml.cs new file mode 100644 index 0000000..6631a7a --- /dev/null +++ b/FoxTube/Views/Settings.xaml.cs @@ -0,0 +1,35 @@ +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 Settings : Page + { + public Settings() + { + this.InitializeComponent(); + } + + void Pivot_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + + } + } +} diff --git a/FoxTube/Views/SettingsSections/About.xaml b/FoxTube/Views/SettingsSections/About.xaml new file mode 100644 index 0000000..cbb0c97 --- /dev/null +++ b/FoxTube/Views/SettingsSections/About.xaml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + @Tyrrrz for his awesome library + @msreviewnet for warm welcome and first feedback + You for using my app :) + + + + + + + Twitter: @xfox111 + Vkontakte: @XFox.Mike + + E-mail: michael.xfox@outlook.com + My website: https://xfox111.net + + + + + + + Our Privacy Policy + YouTube Privacy Policy + YouTube Terms of use + YouTube Community Guidelines + + + + + ©[year] Michael Gordeev + ©[year] YouTube, LLC + +