Explorar o código

add cms collection

姜青儀 %!s(int64=2) %!d(string=hai) anos
pai
achega
9257a70d2b

+ 233 - 0
CMSCollection/CMSCollection.cs

@@ -0,0 +1,233 @@
+using KdanCommon.CMSCollection.Data;
+using KdanCommon.Helpers;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Windows.Globalization;
+using Windows.Web.Http;
+using Windows.Web.Http.Filters;
+
+namespace KdanCommon.CMSCollection
+{
+    public class CMSCollection
+    {
+        public static string CMSDomain = "https://cms.kdanmobile.com";
+
+        private List<ISetting> settingList = null;
+        private HttpClient httpClient = null;
+        private Uri windowsCardsUri = null;
+        private Uri pdfViewerEventBarSettingUri = null;
+        private Uri pdfOtherSettingUri = null;
+        private string appType = null;
+        private bool loadCardsOnly = false;
+        private SemaphoreSlim loadSettingSS = new SemaphoreSlim(1);
+        private bool isLoaded = false;
+
+        public CMSCollection(string appType, bool loadCardOnly = true)
+        {
+            var filter = new HttpBaseProtocolFilter();
+            filter.CacheControl.ReadBehavior = HttpCacheReadBehavior.MostRecent;
+            httpClient = new HttpClient(filter);
+            windowsCardsUri = new Uri($"{CMSDomain}/items/windows_cards");
+            pdfViewerEventBarSettingUri = new Uri($"{CMSDomain}/items/pdf_remote_config");
+            pdfOtherSettingUri = new Uri($"{CMSDomain}/items/PDF_UWP_RemoteConfig");
+            this.appType = appType;
+            this.loadCardsOnly = loadCardOnly;
+            settingList = new List<ISetting>();
+        }
+
+        #region Public Method
+        public async Task<ISetting> GetSetting(string settingId)
+        {
+            await LoadSettings();
+            return settingList.FirstOrDefault(s => s.SettingName == settingId);
+        }
+
+        public async Task<List<WindowsCardSetting>> GetCardSettings()
+        {
+            await LoadSettings();
+            return settingList.Where(s => s is WindowsCardSetting).Select(s => s as WindowsCardSetting).OrderByDescending(w => w.Weight).ToList();
+        }
+        #endregion
+
+        #region Private Method
+        private async Task LoadSettings()
+        {
+            try
+            {
+                await loadSettingSS.WaitAsync();
+                if (!isLoaded)
+                {
+                    settingList.Clear();
+
+                    // check internet
+
+                    var allTask = new List<Task>();
+                    allTask.Add(GetWindowsCards());
+                    if (!loadCardsOnly)
+                    {
+                        allTask.Add(GetViewerEventBarSetting());
+                        allTask.Add(GetOtherSetting());
+                    }
+                    await Task.WhenAll(allTask);
+                    isLoaded = true;
+                }
+            }
+            catch
+            {
+
+            }
+            finally
+            {
+                loadSettingSS.Release();
+            }
+        }
+
+        private async Task GetViewerEventBarSetting()
+        {
+            var region = GetSystemRegion();
+            var appLang = GetAppLanguage();
+            var querys = new List<KeyValuePair<string, string>>();
+            querys.Add(new KeyValuePair<string, string>("deep[evnet_bar_text_translations][_filter][languages_code][_eq]", appLang));
+            querys.Add(new KeyValuePair<string, string>("deep[dialog_text_translations][_filter][languages_code][_eq]", appLang));
+            querys.Add(new KeyValuePair<string, string>("deep[dialog_button][dialog_button_translations][_filter][languages_code][_eq]", appLang));
+            querys.Add(new KeyValuePair<string, string>("deep[do_not_show_translations][_filter][languages_code][_eq]", appLang));
+            querys.Add(new KeyValuePair<string, string>("filter[platform][_eq]", "windows"));
+            querys.Add(new KeyValuePair<string, string>("filter[regions][_contains]", region));
+            querys.Add(new KeyValuePair<string, string>("fields", "*,do_not_show_translations.*,evnet_bar_text_translations.*,dialog_text_translations.*,dialog_button.*,dialog_button.dialog_button_translations.*"));
+            var result = await httpClient.GetRequest(pdfViewerEventBarSettingUri, querys);
+            if (result.StatusCode == HttpStatusCode.Ok)
+            {
+                var jsonString = await result.Content.ReadAsStringAsync();
+                var response = JsonTool.DeserializeJSON<ViewerEventBarSettingResponse>(jsonString);
+                if (response != null && response.Data != null && response.Data.Length > 0)
+                    settingList.Add(response.Data[0]);
+            }
+        }
+        private async Task GetOtherSetting()
+        {
+            var querys = new List<KeyValuePair<string, string>>();
+            querys.Add(new KeyValuePair<string, string>("filter[status][_eq]", "published"));
+            querys.Add(new KeyValuePair<string, string>("filter[platform][_in]", appType));
+            querys.Add(new KeyValuePair<string, string>("fields", "*"));
+            var result = await httpClient.GetRequest(pdfViewerEventBarSettingUri, querys);
+            if (result.StatusCode == HttpStatusCode.Ok)
+            {
+                var jsonString = await result.Content.ReadAsStringAsync();
+                dynamic dyna = DynamicJsonHelper.ToDynamicJson(jsonString);
+                if (dyna == null)
+                    return;
+                List<dynamic> settings = DynamicJsonHelper.GetArraySafety(dyna.data);
+                if (settings == null)
+                    return;
+                foreach (var setting in settings)
+                {
+                    string configName = DynamicJsonHelper.GetValueSafety<string>(setting.config_name, null);
+                    if (!string.IsNullOrEmpty(configName) && setting.json_data != null)
+                        settingList.Add(new JsonSetting(configName, setting.json_data));
+                }
+            }
+        }
+        private async Task GetWindowsCards()
+        {
+            string region = GetSystemRegion();
+            string lang = GetAppLanguage();
+            var querys = new List<KeyValuePair<string, string>>();
+            querys.Add(new KeyValuePair<string, string>("deep[Information][_filter][languages_code][_eq]", lang));
+            querys.Add(new KeyValuePair<string, string>("filter[_or][0][include_regions][_eq]", "true"));
+            querys.Add(new KeyValuePair<string, string>("filter[_or][0][regions][_contains]", region));
+            querys.Add(new KeyValuePair<string, string>("filter[_or][1][include_regions][_eq]", "false"));
+            querys.Add(new KeyValuePair<string, string>("filter[_or][1][regions][_ncontains]", region));
+            querys.Add(new KeyValuePair<string, string>("filter[appTypes][_contains]", appType));
+            querys.Add(new KeyValuePair<string, string>("filter[status][_eq]", "published"));
+            querys.Add(new KeyValuePair<string, string>("fields", "*,Information.*"));
+            var result = await httpClient.GetRequest(windowsCardsUri, querys);
+            if (result.StatusCode == HttpStatusCode.Ok)
+            {
+                var jsonString = await result.Content.ReadAsStringAsync();
+                var response = JsonTool.DeserializeJSON<WindowsCardsResponse>(jsonString);
+                if (response != null && response.Data != null && response.Data.Length > 0)
+                {
+                    foreach (var card in response.Data)
+                        settingList.Add(card);
+                }
+            }
+        }
+
+        private string GetSystemRegion()
+        {
+            var geographyCountryCode = new GeographicRegion().CodeTwoLetter;
+            switch (geographyCountryCode)
+            {
+                case "GB":
+                case "US":
+                case "TW":
+                case "CN":
+                case "JP":
+                case "ES":
+                case "IT":
+                case "FR":
+                case "DE":
+                case "RU":
+                case "PT":
+                case "KR":
+                    return geographyCountryCode;
+                default:
+                    return "OTHER";
+            }
+        }
+
+        private string GetAppLanguage()
+        {
+            try
+            {
+                var currentLang = Windows.ApplicationModel.Resources.Core.ResourceContext.GetForCurrentView().Languages[0];
+                switch (currentLang)
+                {
+                    case "de-DE":
+                    case "de":
+                        return "de";
+                    case "es-ES":
+                    case "es":
+                        return "es";
+                    case "fr-FR":
+                    case "fr":
+                        return "fr";
+                    case "it-IT":
+                    case "it":
+                        return "it";
+                    case "ja-JP":
+                    case "ja":
+                        return "ja";
+                    case "zh-Hans-CN":
+                    case "zh-Hans":
+                    case "zh-CN":
+                        return "zh-cn";
+                    case "zh-Hant-TW":
+                    case "zh-Hant":
+                    case "zh-TW":
+                        return "zh-tw";
+                    case "ru-RU":
+                    case "ru":
+                        return "ru";
+                    case "ko-KR":
+                    case "ko":
+                        return "ko";
+                    case "pt-PT":
+                    case "pt":
+                        return "pt";
+                    default:
+                        return "en";
+                }
+            }
+            catch
+            {
+                return "en";
+            }
+        }
+        #endregion
+    }
+}

+ 13 - 0
CMSCollection/Data/ISetting.cs

@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace KdanCommon.CMSCollection.Data
+{
+    public interface ISetting
+    {
+        string SettingName { get; }
+    }
+}

+ 26 - 0
CMSCollection/Data/JsonSetting.cs

@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace KdanCommon.CMSCollection.Data
+{
+    public class JsonSetting : ISetting
+    {
+        public string SettingName
+        {
+            get
+            {
+                return Key;
+            }
+        }
+        public string Key { get; private set; }
+        public dynamic JsonData { get; private set; }
+        public JsonSetting(string key, dynamic jsonData)
+        {
+            Key = key;
+            JsonData = jsonData;
+        }
+    }
+}

+ 149 - 0
CMSCollection/Data/ViewerEventBarSettingResponse.cs

@@ -0,0 +1,149 @@
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace KdanCommon.CMSCollection.Data
+{
+    public partial class ViewerEventBarSettingResponse
+    {
+        [JsonProperty("data")]
+        public ViewerEventBarSetting[] Data { get; set; }
+    }
+
+    public partial class ViewerEventBarSetting : ISetting
+    {
+        public string SettingName
+        {
+            get
+            {
+                return "ViewerEventBarSetting";
+            }
+        }
+
+        [JsonProperty("id")]
+        public long Id { get; set; }
+
+        [JsonProperty("event_name")]
+        public string EventName { get; set; }
+
+        [JsonProperty("target_user")]
+        public string TargetUser { get; set; }
+
+        [JsonProperty("start_time")]
+        public long StartTime { get; set; }
+
+        [JsonProperty("end_time")]
+        public long EndTime { get; set; }
+
+        [JsonProperty("event_bar_text_color")]
+        public string EventBarTextColor { get; set; }
+
+        [JsonProperty("event_bar_background_color")]
+        public string EventBarBackgroundColor { get; set; }
+
+        [JsonProperty("event_bar_link_url")]
+        public Uri EventBarLinkUrl { get; set; }
+
+        [JsonProperty("event_bar_icon_image")]
+        public string EventBarIconImage { get; set; }
+
+        [JsonProperty("event_bar_close_button_image")]
+        public string EventBarCloseButtonImage { get; set; }
+
+        [JsonProperty("event_bar_icon_visible")]
+        public bool EventBarIconVisible { get; set; }
+
+        [JsonProperty("event_bar_close_button_visible")]
+        public bool EventBarCloseButtonVisible { get; set; }
+
+        [JsonProperty("dialog_text_color")]
+        public string DialogTextColor { get; set; }
+
+        [JsonProperty("dialog_background_color")]
+        public string DialogBackgroundColor { get; set; }
+
+        [JsonProperty("dialog_image")]
+        public string DialogImage { get; set; }
+
+        [JsonProperty("dialog_close_icon_image")]
+        public string DialogCloseIconImage { get; set; }
+
+        [JsonProperty("dialog_close_button_visible")]
+        public bool DialogCloseButtonVisible { get; set; }
+
+        [JsonProperty("do_not_show_checkbox_checked_color")]
+        public string DoNotShowCheckboxCheckedColor { get; set; }
+
+        [JsonProperty("do_not_show_checkbox_unchecked_color")]
+        public string DoNotShowCheckboxUncheckedColor { get; set; }
+
+        [JsonProperty("do_not_show_visible")]
+        public bool DoNotShowVisible { get; set; }
+
+        [JsonProperty("event_visible")]
+        public bool EventVisible { get; set; }
+
+        [JsonProperty("platform")]
+        public string Platform { get; set; }
+
+        [JsonProperty("do_not_show_checkbox_text_color")]
+        public string DoNotShowCheckboxTextColor { get; set; }
+
+        [JsonProperty("evnet_bar_text_translations")]
+        public Translation[] EvnetBarTextTranslations { get; set; }
+
+        [JsonProperty("dialog_text_translations")]
+        public Translation[] DialogTextTranslations { get; set; }
+
+        [JsonProperty("dialog_button")]
+        public DialogButton[] DialogButton { get; set; }
+
+        [JsonProperty("do_not_show_translations")]
+        public Translation[] DoNotShowTranslations { get; set; }
+
+        [JsonProperty("do_not_show_dialog")]
+        public bool DoNotShowDialog { get; set; }
+
+        [JsonProperty("regions")]
+        public string[] Regions { get; set; }
+    }
+
+    public partial class DialogButton
+    {
+        [JsonProperty("id")]
+        public long Id { get; set; }
+
+        [JsonProperty("dialog_button_text_color")]
+        public string DialogButtonTextColor { get; set; }
+
+        [JsonProperty("dialog_button_background_color")]
+        public string DialogButtonBackgroundColor { get; set; }
+
+        [JsonProperty("dialog_button_url")]
+        public Uri DialogButtonUrl { get; set; }
+
+        [JsonProperty("dialog_button_border_color")]
+        public string DialogButtonBorderColor { get; set; }
+
+        [JsonProperty("dialog_button_sort")]
+        public long DialogButtonSort { get; set; }
+
+        [JsonProperty("dialog_button_translations")]
+        public Translation[] DialogButtonTranslations { get; set; }
+    }
+
+    public partial class Translation
+    {
+        [JsonProperty("id")]
+        public long Id { get; set; }
+
+        [JsonProperty("languages_code")]
+        public string LanguagesCode { get; set; }
+
+        [JsonProperty("content")]
+        public string Content { get; set; }
+    }
+}

+ 105 - 0
CMSCollection/Data/WindowsCardsResponse.cs

@@ -0,0 +1,105 @@
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace KdanCommon.CMSCollection.Data
+{
+    public partial class WindowsCardsResponse
+    {
+        [JsonProperty("data")]
+        public WindowsCardSetting[] Data { get; set; }
+    }
+
+    public partial class WindowsCardSetting : ISetting
+    {
+        public string SettingName
+        {
+            get
+            {
+                return Id;
+            }
+        }
+
+        [JsonProperty("id")]
+        public string Id { get; set; }
+
+        [JsonProperty("status")]
+        public string Status { get; set; }
+
+        [JsonProperty("sort")]
+        public object Sort { get; set; }
+
+        [JsonProperty("user_created")]
+        public string UserCreated { get; set; }
+
+        [JsonProperty("date_created")]
+        public DateTimeOffset DateCreated { get; set; }
+
+        [JsonProperty("user_updated")]
+        public string UserUpdated { get; set; }
+
+        [JsonProperty("date_updated")]
+        public DateTimeOffset DateUpdated { get; set; }
+
+        [JsonProperty("Permission")]
+        public string Permission { get; set; }
+
+        [JsonProperty("Weight")]
+        public long Weight { get; set; }
+
+        [JsonProperty("appTypes")]
+        public string[] AppTypes { get; set; }
+
+        [JsonProperty("Start")]
+        public DateTimeOffset Start { get; set; }
+
+        [JsonProperty("End")]
+        public DateTimeOffset End { get; set; }
+
+        [JsonProperty("include_regions")]
+        public bool IncludeRegions { get; set; }
+
+        [JsonProperty("regions")]
+        public string[] Regions { get; set; }
+
+        [JsonProperty("Information")]
+        public Information[] Information { get; set; }
+    }
+
+    public partial class Information
+    {
+        [JsonProperty("id")]
+        public long Id { get; set; }
+
+        [JsonProperty("windows_cards_id")]
+        public string WindowsCardsId { get; set; }
+
+        [JsonProperty("languages_code")]
+        public string LanguagesCode { get; set; }
+
+        [JsonProperty("Title")]
+        public string Title { get; set; }
+
+        [JsonProperty("Description")]
+        public string Description { get; set; }
+
+        [JsonProperty("Link")]
+        public string Link { get; set; }
+
+        [JsonProperty("Image")]
+        public string Image { get; set; }
+
+        public string ImageUrlStr
+        {
+            get
+            {
+                if (string.IsNullOrEmpty(Image))
+                    return null;
+                return $"{CMSCollection.CMSDomain}/assets/{Image}";
+            }
+        }
+    }
+}

+ 53 - 0
Helpers/DynamicJsonHelper.cs

@@ -0,0 +1,53 @@
+using Newtonsoft.Json.Linq;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Xml.Linq;
+
+namespace KdanCommon.Helpers
+{
+    public static class DynamicJsonHelper
+    {
+        public static dynamic ToDynamicJson(string jsonString)
+        {
+            try
+            {
+                JObject jo = JObject.Parse(jsonString);
+                return jo as dynamic;
+            }
+            catch
+            {
+                return null;
+            }
+        }
+
+        public static T GetValueSafety<T>(dynamic value, T defaultValue)
+        {
+            try
+            {
+                var val = (T)value;
+                if (val == null)
+                    return defaultValue;
+                else
+                    return (T)value;
+            }
+            catch
+            {
+                return defaultValue;
+            }
+        }
+
+        public static List<dynamic> GetArraySafety(dynamic value)
+        {
+            try
+            {
+                if (value is JArray)
+                    return ((JArray)value).Cast<dynamic>().ToList();
+            }
+            catch { }
+            return null;
+        }
+    }
+}

+ 78 - 0
Helpers/HttpClientHelper.cs

@@ -0,0 +1,78 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Windows.Web.Http;
+
+namespace KdanCommon.Helpers
+{
+    public static class HttpClientHelper
+    {
+        public static KeyValuePair<string, string> CreateQuery(string param, string value)
+        {
+            return new KeyValuePair<string, string>(param, value);
+        }
+        public static async Task<HttpResponseMessage> GetRequest(this HttpClient httpClient, Uri requestUri, List<KeyValuePair<string, string>> querys)
+        {
+            requestUri = new Uri(requestUri.AbsoluteUri + querys.HttpQueryString());
+
+            var result = new HttpResponseMessage();
+            try
+            {
+                result = await httpClient.GetAsync(requestUri);
+
+            }
+            catch (Exception ex)
+            {
+                var ii = ex.Data;
+                result.StatusCode = HttpStatusCode.RequestTimeout;
+
+            }
+            return result;
+        }
+
+        public static async Task<HttpResponseMessage> PostRequest(this HttpClient httpClient, Uri requestUri, List<KeyValuePair<string, string>> querys)
+        {
+            var content = new HttpFormUrlEncodedContent(querys);
+            var result = new HttpResponseMessage();
+            try
+            {
+                result = await httpClient.PostAsync(requestUri, content);
+            }
+            catch (Exception ex)
+            {
+                var ii = ex.Data;
+                result.StatusCode = HttpStatusCode.RequestTimeout;
+            }
+            return result;
+        }
+
+        public static async Task<HttpResponseMessage> PutRequest(this HttpClient httpClient, Uri requestUri, List<KeyValuePair<string, string>> querys)
+        {
+            var content = new HttpFormUrlEncodedContent(querys);
+            var result = await httpClient.PutAsync(requestUri, content);
+            return result;
+        }
+
+        public static async Task<HttpResponseMessage> DeleteRequest(this HttpClient httpClient, Uri requestUri, List<KeyValuePair<string, string>> querys)
+        {
+            //  requestUri = new Uri(requestUri.AbsoluteUri + HttpQueryString(querys));
+            HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Delete, requestUri);
+
+            request.Content = new HttpFormUrlEncodedContent(querys);
+            var result = await httpClient.SendRequestAsync(request);
+            return result;
+        }
+        public static string HttpQueryString(this List<KeyValuePair<string, string>> querys)
+        {
+            var queryString = "?";
+            foreach (var q in querys)
+            {
+                queryString += q.Key + "=" + q.Value + "&";
+            }
+            queryString = queryString.Remove(queryString.Length - 1);
+            return queryString;
+        }
+    }
+}

+ 30 - 0
Helpers/JsonTool.cs

@@ -0,0 +1,30 @@
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace KdanCommon.Helpers
+{
+    public static class JsonTool
+    {
+        /// <summary>
+        /// Deserialize json to target class
+        /// when jsonStr deserializes failed, put default value in there
+        /// </summary>
+        public static T DeserializeJSON<T>(string jsonStr)
+        {
+            T response = default(T);
+            response = JsonConvert.DeserializeObject<T>(jsonStr, new JsonSerializerSettings()
+            {
+                Error = (sender, errorEventArgs) =>
+                {
+                    System.Diagnostics.Debug.WriteLine(String.Format("error happen in {0} : {1}", errorEventArgs.CurrentObject.GetType().Name, errorEventArgs.ErrorContext.Error.Message));
+                    errorEventArgs.ErrorContext.Handled = true;
+                }
+            });
+            return response;
+        }
+    }
+}

+ 153 - 0
KdanCommon.csproj

@@ -0,0 +1,153 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{7B8ABCA1-8DA7-42AE-8AEA-C92053014AC0}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>KdanCommon</RootNamespace>
+    <AssemblyName>KdanCommon</AssemblyName>
+    <DefaultLanguage>zh-TW</DefaultLanguage>
+    <TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
+    <TargetPlatformVersion Condition=" '$(TargetPlatformVersion)' == '' ">10.0.18362.0</TargetPlatformVersion>
+    <TargetPlatformMinVersion>10.0.16299.0</TargetPlatformMinVersion>
+    <MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
+    <FileAlignment>512</FileAlignment>
+    <ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
+    <PlatformTarget>x86</PlatformTarget>
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>bin\x86\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
+    <NoWarn>;2008</NoWarn>
+    <DebugType>full</DebugType>
+    <UseVSHostingProcess>false</UseVSHostingProcess>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
+    <PlatformTarget>x86</PlatformTarget>
+    <OutputPath>bin\x86\Release\</OutputPath>
+    <DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
+    <Optimize>true</Optimize>
+    <NoWarn>;2008</NoWarn>
+    <DebugType>pdbonly</DebugType>
+    <UseVSHostingProcess>false</UseVSHostingProcess>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM'">
+    <PlatformTarget>ARM</PlatformTarget>
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>bin\ARM\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
+    <NoWarn>;2008</NoWarn>
+    <DebugType>full</DebugType>
+    <UseVSHostingProcess>false</UseVSHostingProcess>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|ARM'">
+    <PlatformTarget>ARM</PlatformTarget>
+    <OutputPath>bin\ARM\Release\</OutputPath>
+    <DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
+    <Optimize>true</Optimize>
+    <NoWarn>;2008</NoWarn>
+    <DebugType>pdbonly</DebugType>
+    <UseVSHostingProcess>false</UseVSHostingProcess>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM64'">
+    <PlatformTarget>ARM64</PlatformTarget>
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>bin\ARM64\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
+    <NoWarn>;2008</NoWarn>
+    <DebugType>full</DebugType>
+    <UseVSHostingProcess>false</UseVSHostingProcess>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|ARM64'">
+    <PlatformTarget>ARM64</PlatformTarget>
+    <OutputPath>bin\ARM64\Release\</OutputPath>
+    <DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
+    <Optimize>true</Optimize>
+    <NoWarn>;2008</NoWarn>
+    <DebugType>pdbonly</DebugType>
+    <UseVSHostingProcess>false</UseVSHostingProcess>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+    <PlatformTarget>x64</PlatformTarget>
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>bin\x64\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
+    <NoWarn>;2008</NoWarn>
+    <DebugType>full</DebugType>
+    <UseVSHostingProcess>false</UseVSHostingProcess>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+    <PlatformTarget>x64</PlatformTarget>
+    <OutputPath>bin\x64\Release\</OutputPath>
+    <DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
+    <Optimize>true</Optimize>
+    <NoWarn>;2008</NoWarn>
+    <DebugType>pdbonly</DebugType>
+    <UseVSHostingProcess>false</UseVSHostingProcess>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <PropertyGroup>
+    <RestoreProjectStyle>PackageReference</RestoreProjectStyle>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="CMSCollection\CMSCollection.cs" />
+    <Compile Include="CMSCollection\Data\ISetting.cs" />
+    <Compile Include="CMSCollection\Data\JsonSetting.cs" />
+    <Compile Include="CMSCollection\Data\ViewerEventBarSettingResponse.cs" />
+    <Compile Include="CMSCollection\Data\WindowsCardsResponse.cs" />
+    <Compile Include="Helpers\DynamicJsonHelper.cs" />
+    <Compile Include="Helpers\HttpClientHelper.cs" />
+    <Compile Include="Helpers\JsonTool.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <EmbeddedResource Include="Properties\KdanCommon.rd.xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform">
+      <Version>6.2.14</Version>
+    </PackageReference>
+    <PackageReference Include="Newtonsoft.Json">
+      <Version>12.0.3</Version>
+    </PackageReference>
+  </ItemGroup>
+  <PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '14.0' ">
+    <VisualStudioVersion>14.0</VisualStudioVersion>
+  </PropertyGroup>
+  <Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>

+ 29 - 0
Properties/AssemblyInfo.cs

@@ -0,0 +1,29 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// 組件的一般資訊是由下列的屬性集控制。
+// 變更這些屬性的值即可修改組件的相關
+// 資訊。
+[assembly: AssemblyTitle("KdanCommon")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("KdanCommon")]
+[assembly: AssemblyCopyright("Copyright ©  2023")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// 組件的版本資訊由下列四個值所組成:
+//
+//      主要版本
+//      次要版本 
+//      組建編號
+//      修訂
+//
+// 您可以指定所有的值,也可以使用 '*' 將組建和修訂編號 
+// 設為預設,如下所示:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
+[assembly: ComVisible(false)]

+ 33 - 0
Properties/KdanCommon.rd.xml

@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    這個檔案包含執行階段指示詞、應用程式透過反射和其他動態程式碼模式所存取的類型相關規格。
+    執行階段指示詞的用途是控制
+    .NET Native 最佳化程式,以及確認未移除程式庫所存取的程式碼。如果您的程式庫
+    未執行任何反射,您通常就不需要編輯這個檔案。不過,
+    如果您的程式庫透過類型 (尤其是傳遞給它或衍生自其類型的類型) 進行反射,
+    您就應該撰寫執行階段指示詞。
+
+    程式庫中的最常用反射是探索傳遞給程式庫的類型相關資訊。
+    執行階段指示詞能用三種方式表達傳遞給程式庫的類型
+    需求。
+
+    1.  Parameter、GenericParameter、TypeParameter、TypeEnumerableParameter
+        使用這些指示詞透過傳遞為參數的類型進行反射。
+
+    2.  SubTypes
+        使用 SubTypes 指示詞透過衍生自另一種類型的類型進行反射。
+
+    3.  AttributeImplies
+        使用 AttributeImplies 指示詞指出程式庫需要透過
+        利用屬性所裝飾的類型或方法進行反射。
+
+    如需為程式庫撰寫執行階段指示詞的詳細資訊,請前往
+    https://go.microsoft.com/fwlink/?LinkID=391919
+-->
+<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
+  <Library Name="KdanCommon">
+
+  	<!-- 請在這裡新增程式庫的指示詞 -->
+
+  </Library>
+</Directives>