Archived
1
0

Anyway, I am the only one who reads this, right?

This commit is contained in:
Michael Gordeev
2019-12-02 16:52:49 +03:00
parent acd63a948e
commit bfc8689136
40 changed files with 8722 additions and 178 deletions
+46 -7
View File
@@ -4,8 +4,8 @@
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{797951D8-BF28-4659-BDF4-C17A583E64CD}</ProjectGuid>
<OutputType>winmdobj</OutputType>
<ProjectGuid>{29C01E10-76E7-4527-984F-B0EEF7E1AC64}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>FoxTube.Core</RootNamespace>
<AssemblyName>FoxTube.Core</AssemblyName>
@@ -16,7 +16,6 @@
<MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<AllowCrossPlatformRetargeting>false</AllowCrossPlatformRetargeting>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
@@ -27,6 +26,7 @@
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<LangVersion>8.0</LangVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
@@ -36,6 +36,7 @@
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<LangVersion>8.0</LangVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<PlatformTarget>x86</PlatformTarget>
@@ -46,6 +47,7 @@
<DebugType>full</DebugType>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<LangVersion>8.0</LangVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<PlatformTarget>x86</PlatformTarget>
@@ -56,6 +58,7 @@
<DebugType>pdbonly</DebugType>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<LangVersion>8.0</LangVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM'">
<PlatformTarget>ARM</PlatformTarget>
@@ -66,6 +69,7 @@
<DebugType>full</DebugType>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<LangVersion>8.0</LangVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|ARM'">
<PlatformTarget>ARM</PlatformTarget>
@@ -76,6 +80,7 @@
<DebugType>pdbonly</DebugType>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<LangVersion>8.0</LangVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM64'">
<PlatformTarget>ARM64</PlatformTarget>
@@ -86,6 +91,7 @@
<DebugType>full</DebugType>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<LangVersion>8.0</LangVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|ARM64'">
<PlatformTarget>ARM64</PlatformTarget>
@@ -96,6 +102,7 @@
<DebugType>pdbonly</DebugType>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<LangVersion>8.0</LangVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<PlatformTarget>x64</PlatformTarget>
@@ -106,6 +113,7 @@
<DebugType>full</DebugType>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<LangVersion>8.0</LangVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<PlatformTarget>x64</PlatformTarget>
@@ -116,23 +124,54 @@
<DebugType>pdbonly</DebugType>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<LangVersion>8.0</LangVersion>
</PropertyGroup>
<PropertyGroup>
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
</PropertyGroup>
<ItemGroup>
<Compile Include="Class1.cs" />
<Compile Include="Controllers\StoreInterop.cs" />
<Compile Include="Helpers.cs" />
<Compile Include="Helpers\Extensions.cs" />
<Compile Include="Helpers\Feedback.cs" />
<Compile Include="Helpers\Inbox.cs" />
<Compile Include="Helpers\Metrics.cs" />
<Compile Include="Helpers\Settings.cs" />
<Compile Include="Helpers\StoreInterop.cs" />
<Compile Include="Helpers\Utils.cs" />
<Compile Include="Models\Inbox\Changelog.cs" />
<Compile Include="Models\Inbox\DeveloperMessage.cs" />
<Compile Include="Models\Inbox\InboxItem.cs" />
<Compile Include="Models\IRefreshable.cs" />
<Compile Include="Models\Notifications.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<EmbeddedResource Include="Properties\FoxTube.Core.rd.xml" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="AngleSharp">
<Version>0.13.0</Version>
</PackageReference>
<PackageReference Include="Microsoft.AppCenter.Analytics">
<Version>2.6.1</Version>
</PackageReference>
<PackageReference Include="Microsoft.AppCenter.Crashes">
<Version>2.6.1</Version>
</PackageReference>
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform">
<Version>6.2.9</Version>
</PackageReference>
<PackageReference Include="Microsoft.Services.Store.Engagement">
<Version>10.1901.28001</Version>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Folder Include="Models\" />
<WCFMetadata Include="Connected Services\" />
</ItemGroup>
<ItemGroup>
<SDKReference Include="Microsoft.Services.Store.Engagement, Version=10.0">
<Name>Microsoft Engagement Framework</Name>
</SDKReference>
<SDKReference Include="Microsoft.VCLibs, Version=14.0">
<Name>Visual C++ 2015 Runtime for Universal Windows Platform Apps</Name>
</SDKReference>
</ItemGroup>
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '14.0' ">
<VisualStudioVersion>14.0</VisualStudioVersion>
-14
View File
@@ -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);
}
}
+49
View File
@@ -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<T>(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<byte> values = new List<byte>();
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
};
}
}
}
+52
View File
@@ -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();
}
}
}
+137
View File
@@ -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<List<InboxItem>>GetInbox()
{
List<InboxItem> list = new List<InboxItem>();
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<List<Changelog>>GetChangelogs()
{
List<Changelog> list = new List<Changelog>();
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<List<DeveloperMessage>>GetMessages()
{
List<DeveloperMessage> list = new List<DeveloperMessage>();
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;
}
/// <summary>
/// Fires toast notification with the last changelog content
/// </summary>
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));
}
}
}
}
+76
View File
@@ -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<string, string> parameters = new Dictionary<string, string>();
foreach (var (key, value) in details)
parameters.Add(key, value);
Analytics.TrackEvent(eventName, parameters.Count > 0 ? parameters : null);
}
public static async Task<string> 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<string, string> body = new Dictionary<string, string>
{
{ "Title", packageTitle },
{ "Content", content },
{ "Version", CurrentVersion }
};
request.Content = new FormUrlEncodedContent(body);
HttpResponseMessage response = await client.SendAsync(request);
return await response.Content.ReadAsStringAsync();
}
}
}
}
+118
View File
@@ -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();
}
}
@@ -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));
}
}
}
+36
View File
@@ -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
{
/// <summary>
/// Terminates current application session
/// </summary>
public static void CloseApp() =>
CoreApplication.Exit();
/// <summary>
/// Restarts application
/// </summary>
public static void RestartApp() =>
RestartApp(null);
/// <summary>
/// Restarts application with specified parameters
/// </summary>
/// <param name="args">Parameters which will be provided to new application instance</param>
public static async void RestartApp(string args) =>
await CoreApplication.RequestRestartAsync(args);
public static void InitializeFailsafeProtocol()
{
Metrics.AddEvent("Failsafe protocol initiated");
Settings.ResetSettings();
RestartApp();
}
}
}
@@ -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();
}
}
+19
View File
@@ -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;
}
}
}
@@ -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;
}
}
}
+17
View File
@@ -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; }
}
}
+27
View File
@@ -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($@"<toast activationType='foreground' launch='changelog|{version}'>
<visual>
<binding template='ToastGeneric'>
<image placement='hero' src='https://xfox111.net/FoxTube/Thumbnails/Changelog?ver={version}'/>
<image placement='appLogoOverride' hint-crop='circle' src='https://xfox111.net/FoxTube/Avatars/Changelog'/>
<text>Changelog</text>
<text>See what's new in {version}</text>
</binding>
</visual>
</toast>");
return new ToastNotification(template);
}
}
}
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
This file contains Runtime Directives, specifications about types your application accesses
through reflection and other dynamic code patterns. Runtime Directives are used to control the
.NET Native optimizer and ensure that it does not remove code accessed by your library. If your
library does not do any reflection, then you generally do not need to edit this file. However,
if your library reflects over types, especially types passed to it or derived from its types,
then you should write Runtime Directives.
The most common use of reflection in libraries is to discover information about types passed
to the library. Runtime Directives have three ways to express requirements on types passed to
your library.
1. Parameter, GenericParameter, TypeParameter, TypeEnumerableParameter
Use these directives to reflect over types passed as a parameter.
2. SubTypes
Use a SubTypes directive to reflect over types derived from another type.
3. AttributeImplies
Use an AttributeImplies directive to indicate that your library needs to reflect over
types or methods decorated with an attribute.
For more information on writing Runtime Directives for libraries, please visit
https://go.microsoft.com/fwlink/?LinkID=391919
-->
<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
<Library Name="FoxTube.Core">
<!-- add directives for your library here -->
</Library>
</Directives>