From 7d0938b5691c15a77826a7c3b8b2ba665600ef2c Mon Sep 17 00:00:00 2001 From: Valeriy Mironov Date: Sat, 9 Jun 2018 12:29:59 +0300 Subject: [PATCH] Animated preview generation code now read states from a PreviewStates.json file, preview generated using Mono runtime will have separate .png files instead of 1 .gif, added support for drawing correct weather icon depending on weather condition in state --- Resources/ImageLoader.cs | 2 +- Resources/Resources.csproj | 5 +- Resources/packages.config | 2 +- .../AirPollution/AirPollutionImageElement.cs | 4 +- .../Elements/Weather/WeatherIconsElement.cs | 5 +- WatchFace.Parser/Models/WatchState.cs | 9 +- WatchFace.Parser/Models/WeatherCondition.cs | 28 +++- WatchFace.Parser/PreviewGenerator.cs | 59 ++------ WatchFace.Parser/WatchFace.Parser.csproj | 43 ++++-- .../WeatherIcons/{279.png => 0.png} | Bin .../WeatherIcons/{247.png => 1.png} | Bin WatchFace.Parser/WeatherIcons/10.png | Bin 0 -> 334 bytes WatchFace.Parser/WeatherIcons/11.png | Bin 0 -> 325 bytes WatchFace.Parser/WeatherIcons/12.png | Bin 0 -> 288 bytes WatchFace.Parser/WeatherIcons/13.png | Bin 0 -> 334 bytes WatchFace.Parser/WeatherIcons/14.png | Bin 0 -> 236 bytes WatchFace.Parser/WeatherIcons/15.png | Bin 0 -> 302 bytes WatchFace.Parser/WeatherIcons/16.png | Bin 0 -> 365 bytes WatchFace.Parser/WeatherIcons/17.png | Bin 0 -> 340 bytes WatchFace.Parser/WeatherIcons/18.png | Bin 0 -> 229 bytes WatchFace.Parser/WeatherIcons/19.png | Bin 0 -> 319 bytes WatchFace.Parser/WeatherIcons/2.png | Bin 0 -> 372 bytes WatchFace.Parser/WeatherIcons/20.png | Bin 0 -> 335 bytes WatchFace.Parser/WeatherIcons/21.png | Bin 0 -> 367 bytes WatchFace.Parser/WeatherIcons/22.png | Bin 0 -> 316 bytes WatchFace.Parser/WeatherIcons/23.png | Bin 0 -> 270 bytes WatchFace.Parser/WeatherIcons/24.png | Bin 0 -> 278 bytes WatchFace.Parser/WeatherIcons/25.png | Bin 0 -> 305 bytes WatchFace.Parser/WeatherIcons/3.png | Bin 0 -> 374 bytes WatchFace.Parser/WeatherIcons/4.png | Bin 0 -> 326 bytes WatchFace.Parser/WeatherIcons/5.png | Bin 0 -> 297 bytes WatchFace.Parser/WeatherIcons/6.png | Bin 0 -> 314 bytes WatchFace.Parser/WeatherIcons/7.png | Bin 0 -> 316 bytes WatchFace.Parser/WeatherIcons/8.png | Bin 0 -> 324 bytes WatchFace.Parser/WeatherIcons/9.png | Bin 0 -> 319 bytes WatchFace.Parser/packages.config | 5 +- WatchFace/Program.cs | 133 +++++++++++++++--- WatchFace/WatchFace.csproj | 14 +- WatchFace/packages.config | 6 +- 39 files changed, 219 insertions(+), 96 deletions(-) rename WatchFace.Parser/WeatherIcons/{279.png => 0.png} (100%) rename WatchFace.Parser/WeatherIcons/{247.png => 1.png} (100%) create mode 100644 WatchFace.Parser/WeatherIcons/10.png create mode 100644 WatchFace.Parser/WeatherIcons/11.png create mode 100644 WatchFace.Parser/WeatherIcons/12.png create mode 100644 WatchFace.Parser/WeatherIcons/13.png create mode 100644 WatchFace.Parser/WeatherIcons/14.png create mode 100644 WatchFace.Parser/WeatherIcons/15.png create mode 100644 WatchFace.Parser/WeatherIcons/16.png create mode 100644 WatchFace.Parser/WeatherIcons/17.png create mode 100644 WatchFace.Parser/WeatherIcons/18.png create mode 100644 WatchFace.Parser/WeatherIcons/19.png create mode 100644 WatchFace.Parser/WeatherIcons/2.png create mode 100644 WatchFace.Parser/WeatherIcons/20.png create mode 100644 WatchFace.Parser/WeatherIcons/21.png create mode 100644 WatchFace.Parser/WeatherIcons/22.png create mode 100644 WatchFace.Parser/WeatherIcons/23.png create mode 100644 WatchFace.Parser/WeatherIcons/24.png create mode 100644 WatchFace.Parser/WeatherIcons/25.png create mode 100644 WatchFace.Parser/WeatherIcons/3.png create mode 100644 WatchFace.Parser/WeatherIcons/4.png create mode 100644 WatchFace.Parser/WeatherIcons/5.png create mode 100644 WatchFace.Parser/WeatherIcons/6.png create mode 100644 WatchFace.Parser/WeatherIcons/7.png create mode 100644 WatchFace.Parser/WeatherIcons/8.png create mode 100644 WatchFace.Parser/WeatherIcons/9.png diff --git a/Resources/ImageLoader.cs b/Resources/ImageLoader.cs index 6e1a981..89beaf3 100644 --- a/Resources/ImageLoader.cs +++ b/Resources/ImageLoader.cs @@ -9,7 +9,7 @@ namespace Resources { public class ImageLoader { - public static readonly int NumericPartLength = 3; + public static readonly int NumericPartLength = 4; private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); public static Bitmap LoadImageForNumber(string directory, long index) diff --git a/Resources/Resources.csproj b/Resources/Resources.csproj index 79d0b28..cd27aa1 100644 --- a/Resources/Resources.csproj +++ b/Resources/Resources.csproj @@ -35,12 +35,15 @@ ..\packages\Bumpkit.1.0.2\lib\BumpKit.dll - ..\packages\NLog.4.4.12\lib\net40\NLog.dll + ..\packages\NLog.4.5.6\lib\net40-client\NLog.dll + + + diff --git a/Resources/packages.config b/Resources/packages.config index e7a2a3e..7e4a313 100644 --- a/Resources/packages.config +++ b/Resources/packages.config @@ -1,5 +1,5 @@  - + \ No newline at end of file diff --git a/WatchFace.Parser/Models/Elements/Weather/AirPollution/AirPollutionImageElement.cs b/WatchFace.Parser/Models/Elements/Weather/AirPollution/AirPollutionImageElement.cs index 3b33df6..542e4e9 100644 --- a/WatchFace.Parser/Models/Elements/Weather/AirPollution/AirPollutionImageElement.cs +++ b/WatchFace.Parser/Models/Elements/Weather/AirPollution/AirPollutionImageElement.cs @@ -9,9 +9,9 @@ namespace WatchFace.Parser.Models.Elements public override void Draw(Graphics drawer, Bitmap[] resources, WatchState state) { - if (state.Air == AirCondition.Unknown) return; + if (state.AirQuality == AirCondition.Unknown) return; - var imageIndex = (int) state.Air; + var imageIndex = (int) state.AirQuality; Draw(drawer, resources, imageIndex); } } diff --git a/WatchFace.Parser/Models/Elements/Weather/WeatherIconsElement.cs b/WatchFace.Parser/Models/Elements/Weather/WeatherIconsElement.cs index 697c1a3..e609420 100644 --- a/WatchFace.Parser/Models/Elements/Weather/WeatherIconsElement.cs +++ b/WatchFace.Parser/Models/Elements/Weather/WeatherIconsElement.cs @@ -19,11 +19,14 @@ namespace WatchFace.Parser.Models.Elements var useAltCoordinates = CurrentAlt != null && state.CurrentTemperature == null; var iconCoordinates = useAltCoordinates ? CurrentAlt : Current; + if (state.CurrentWeather > WeatherCondition.VeryHeavyDownpour || + state.CurrentWeather < WeatherCondition.Unknown) return; + if (iconCoordinates != null) drawer.DrawImage(LoadWeatherImage(state.CurrentWeather), iconCoordinates.X, iconCoordinates.Y); if (CustomIcon != null) - drawer.DrawImage(resources[CustomIcon.ImageIndex + 1], CustomIcon.X, CustomIcon.Y); + drawer.DrawImage(resources[CustomIcon.ImageIndex + (int)state.CurrentWeather], CustomIcon.X, CustomIcon.Y); } private static Bitmap LoadWeatherImage(WeatherCondition weather) diff --git a/WatchFace.Parser/Models/WatchState.cs b/WatchFace.Parser/Models/WatchState.cs index 53e13c2..b004d0a 100644 --- a/WatchFace.Parser/Models/WatchState.cs +++ b/WatchFace.Parser/Models/WatchState.cs @@ -1,4 +1,6 @@ using System; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; namespace WatchFace.Parser.Models { @@ -12,15 +14,18 @@ namespace WatchFace.Parser.Models public int Distance { get; set; } = 2367; public int? Pulse { get; set; } = 62; + + [JsonConverter(typeof(StringEnumConverter))] + public WeatherCondition CurrentWeather { get; set; } = WeatherCondition.PartlyCloudy; public int? CurrentTemperature { get; set; } = -10; public int? DayTemperature { get; set; } = -15; public int? NightTemperature { get; set; } = -24; public int? TomorrowDayTemperature { get; set; } public int? TomorrowNightTemperature { get; set; } - public WeatherCondition CurrentWeather { get; set; } = WeatherCondition.Cloudy; // https://en.wikipedia.org/wiki/Air_quality_index#Mainland_China - public AirCondition Air { get; set; } = AirCondition.Excellent; + [JsonConverter(typeof(StringEnumConverter))] + public AirCondition AirQuality { get; set; } = AirCondition.Excellent; public int? AirQualityIndex { get; set; } = 15; public int BatteryLevel { get; set; } = 67; diff --git a/WatchFace.Parser/Models/WeatherCondition.cs b/WatchFace.Parser/Models/WeatherCondition.cs index ccee295..2ca60b9 100644 --- a/WatchFace.Parser/Models/WeatherCondition.cs +++ b/WatchFace.Parser/Models/WeatherCondition.cs @@ -2,7 +2,31 @@ { public enum WeatherCondition { - Unknown = 279, - Cloudy = 247 + Unknown, + PartlyCloudy, + CloudyAndRain, + CloudyAndSnow, + Sunny, + Cloudy, + LightRain, + LightSnow, + Rain, + Snow, + HeavySnow, + HeavyRain, + SandStorm, + SnowAndRain, + Fog, + Haze, + Storm, + VeryHeavySnow, + FloatingDust, + Downpour, + Hail, + HailStorm, + HeavyDownpour, + BlowingDust, + Tornado, + VeryHeavyDownpour } } \ No newline at end of file diff --git a/WatchFace.Parser/PreviewGenerator.cs b/WatchFace.Parser/PreviewGenerator.cs index d25bc9b..62deb7c 100644 --- a/WatchFace.Parser/PreviewGenerator.cs +++ b/WatchFace.Parser/PreviewGenerator.cs @@ -1,8 +1,5 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Drawing; -using System.IO; -using BumpKit; using WatchFace.Parser.Interfaces; using WatchFace.Parser.Models; @@ -10,63 +7,23 @@ namespace WatchFace.Parser { public class PreviewGenerator { - public static void CreateGif(List descriptor, Bitmap[] images, Stream outputStream) + public static IEnumerable CreateAnimation(List descriptor, Bitmap[] images, + IEnumerable states) { var previewWatchFace = new Models.Elements.WatchFace(descriptor); - var watchState = new WatchState(); - var time = watchState.Time; - - using (var encoder = new GifEncoder(outputStream)) + foreach (var watchState in states) { - for (var i = 0; i < 10; i++) + using (var image = CreateFrame(previewWatchFace, images, watchState)) { - var num = i + 1; - watchState.BatteryLevel = 100 - (num * 10); - - watchState.Pulse = 60 + num * 2; - watchState.Steps = num * 1000; - watchState.Calories = num * 75; - watchState.Distance = num * 700; - - watchState.Bluetooth = num > 1 && num < 6; - watchState.Unlocked = num > 2 && num < 7; - watchState.Alarm = num > 3 && num < 8; - watchState.DoNotDisturb = num > 4 && num < 9; - - watchState.DayTemperature += 2; - watchState.NightTemperature += 4; - - if (num < 3) - { - watchState.Air = AirCondition.Unknown; - watchState.AirQualityIndex = null; - } - else - { - watchState.Air = (AirCondition) (num - 3); - watchState.AirQualityIndex = (num - 2) * 50 - 25; - } - - if (num < 3) - watchState.CurrentTemperature = null; - else if (num == 3) - watchState.CurrentTemperature = -10; - else - watchState.CurrentTemperature += 6; - - watchState.Time = new DateTime(time.Year, num, num * 2 + 5, i * 2, i * 6, i); - using (var image = CreateFrame(previewWatchFace, images, watchState)) - { - encoder.AddFrame(image, frameDelay: TimeSpan.FromSeconds(1)); - } + yield return image; } } } - public static Image CreateImage(IEnumerable descriptor, Bitmap[] resources) + public static Image CreateImage(IEnumerable descriptor, Bitmap[] images, WatchState state) { var previewWatchFace = new Models.Elements.WatchFace(descriptor); - return CreateFrame(previewWatchFace, resources, new WatchState()); + return CreateFrame(previewWatchFace, images, state); } private static Image CreateFrame(IDrawable watchFace, Bitmap[] resources, WatchState state) diff --git a/WatchFace.Parser/WatchFace.Parser.csproj b/WatchFace.Parser/WatchFace.Parser.csproj index fc360f4..14008da 100644 --- a/WatchFace.Parser/WatchFace.Parser.csproj +++ b/WatchFace.Parser/WatchFace.Parser.csproj @@ -31,19 +31,19 @@ 4 - - ..\packages\Bumpkit.1.0.2\lib\BumpKit.dll - - - ..\packages\Newtonsoft.Json.10.0.3\lib\net40\Newtonsoft.Json.dll + + ..\packages\Newtonsoft.Json.11.0.2\lib\net40\Newtonsoft.Json.dll - ..\packages\NLog.4.4.12\lib\net40\NLog.dll + ..\packages\NLog.4.5.6\lib\net40-client\NLog.dll + + + @@ -173,9 +173,34 @@ - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - \ No newline at end of file diff --git a/WatchFace.Parser/WeatherIcons/279.png b/WatchFace.Parser/WeatherIcons/0.png similarity index 100% rename from WatchFace.Parser/WeatherIcons/279.png rename to WatchFace.Parser/WeatherIcons/0.png diff --git a/WatchFace.Parser/WeatherIcons/247.png b/WatchFace.Parser/WeatherIcons/1.png similarity index 100% rename from WatchFace.Parser/WeatherIcons/247.png rename to WatchFace.Parser/WeatherIcons/1.png diff --git a/WatchFace.Parser/WeatherIcons/10.png b/WatchFace.Parser/WeatherIcons/10.png new file mode 100644 index 0000000000000000000000000000000000000000..9199265b7bcbff5c7dcfe117c0de51bfdb8daefa GIT binary patch literal 334 zcmeAS@N?(olHy`uVBq!ia0vp^av;pX1|+Qw)-3{3jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1quc!N;C1jv*f2NBbH1niT|Ce*gE6UaDic?r>$o z*2z8%cbOk&r~jTTVW-&U-|naT-eznor3rhWSrAH|xw=$Xx)M>nMx&3V1= z0ek)0rE@br@E!fqZuPD7H(uG+ zl>fB1(6Z-=^VerI{?mSOMRkALZwDT0UG2XPJhKnI2f1kOw5fFpZN9e8uII>iJUqK^ ao4L2(+?9R&ubYA1W$<+Mb6Mw<&;$TxX^Kz) literal 0 HcmV?d00001 diff --git a/WatchFace.Parser/WeatherIcons/11.png b/WatchFace.Parser/WeatherIcons/11.png new file mode 100644 index 0000000000000000000000000000000000000000..8b7492fb9dfd64174bcc27beb0eceba7e92d8f1d GIT binary patch literal 325 zcmeAS@N?(olHy`uVBq!ia0vp^av;pX1|+Qw)-3{3jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1quc!CRg#jv*f2Px~M8H7oG2)&8Ge)-?y^+y@j?}c=^Ay@wuV%`h26?iM-kq zT3eT=+p^ET^yaPHp};D`TfdU#C>~q<_`m6~Yb7)H8vyw^OHVIatAA{I>^1)Ri(Q!S T9timX^d*C*tDnm{r-UW|l--aD literal 0 HcmV?d00001 diff --git a/WatchFace.Parser/WeatherIcons/12.png b/WatchFace.Parser/WeatherIcons/12.png new file mode 100644 index 0000000000000000000000000000000000000000..73b22662f00c33c23d8e4f52bc5756752f183205 GIT binary patch literal 288 zcmeAS@N?(olHy`uVBq!ia0vp^av;pX1|+Qw)-3{3jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1quc!L6Pyjv*f2S0^xX9X8-${{7!SUG|{D&Z6lh z5y`F1Kc+-nc>L#B|Ab48Q}~vY81N_iC@4sMGE$H#lA7c3(&5yn>#gfQB|MxrMJV#>aqZF6sQ zFEjuf{LJz1yyXWzSwC~s{lTWOV!|iG|G|G=I!<7QW^%|NVFW7p_w+Pi_8mE|y(1 z@9j<@_Vm{`{Y@&`AN9w_EI2r`YTM@DT?Q7>iO;`zb4krfJyN8{{i;m!wa1QsH9KCO zvP_xPxqqLyojE__>FM{Qd0$y4%?LX3e2K)S4L5{$H%iFqb{{Uzopr01O?4$N&HU literal 0 HcmV?d00001 diff --git a/WatchFace.Parser/WeatherIcons/14.png b/WatchFace.Parser/WeatherIcons/14.png new file mode 100644 index 0000000000000000000000000000000000000000..0e53f025601ae1ff09bfe01fc60b82adcb4a8cdf GIT binary patch literal 236 zcmeAS@N?(olHy`uVBq!ia0vp^av;pX1|+Qw)-3{3jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1quc!A4IP#}E(iqrHw?42nEQzWtwHR-HXnp)0RU zq1|)gXO~<43rrj`8!j;{W%Od6!WQYb>C@soRwxx~=m?c+)|qlM*Su8wgwxEsWx?B< z*3E!vbDVZt^8dB93a8)p)V~h9ASyhCO@lW;3M~C8dEPgsR(WolmP39IfsSGDboFyt I=akR{09A@nY>n-tB4F#>;qof~R$d4p8t@)x7)_ra-v1XA+-= z|8Fn-J@OgudFkbs+FXCQNw-EF&YX6zVOx3i$G<^hdW?Td9tvIX7l$&wch60}b?@y_ z{bs&gku2WjFI$Bl_1!u5E@jFu=8s#}FF3-?wiN_Lr${b1vw&Cne6iq#ZHf;hj566L hvVz_8>A1{O*0P`16HEV9iUPgE;OXk;vd$@?2>?ElcCP>c literal 0 HcmV?d00001 diff --git a/WatchFace.Parser/WeatherIcons/16.png b/WatchFace.Parser/WeatherIcons/16.png new file mode 100644 index 0000000000000000000000000000000000000000..876ee2dcbb3d0414d1d663a48c98c81c16b4708c GIT binary patch literal 365 zcmeAS@N?(olHy`uVBq!ia0vp^av;pX1|+Qw)-3{3jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1quc4NRUcjv*f2SNpm7nhkiI%l~^DXJo%>yB_o{ zan@3G({0X2lCOSJzOaYcCEM`K@51w}s_S2ewR+Nzko>D}-8mmW_%k3RpTJ*U>$ ztGH7A=%eL@Z-qtoH-52i|9ndDl~7Ra+C@o6`Z-?-t}9*FHl4%%S-|uOr($?Lk9Nol zU+H!c{V#FK`^K8&MK3MS`f0y@+wUTrmp}V-%a`&^-}V$4Xzkgslh^m&O~wl{mu#ze zO|&2KFY9ZY%a@T>a%j)W#fi(AXG#7z@ZrU=I~RFP_Mb_vWMX!%J((4oQ4b6v22WQ% Jmvv4FO#s(^mFoZi literal 0 HcmV?d00001 diff --git a/WatchFace.Parser/WeatherIcons/17.png b/WatchFace.Parser/WeatherIcons/17.png new file mode 100644 index 0000000000000000000000000000000000000000..433ec9d5dc42707eb5b8a0ece4a57ade22798ad5 GIT binary patch literal 340 zcmeAS@N?(olHy`uVBq!ia0vp^av;pX1|+Qw)-3{3jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1quc!Iz#cjv*f2NBbH1niT|C{{COScB@Y0I%W2# zw<^L3-w*7_SyL}`SpCQcPQw}}o{P#EWez;j?hALz8m@6m``st;&g#l;zOM>xyPK?n z0@#xx=KXN6eHkEsWJ8Sn{}m!vSZ^x`{XV0dQ1;8|I?wFA|E8~7;4@`T`}rAr6~7hV ze1GI%{Oc>iy!RGL{M(TBXjW-pV7ZA%X_{5IiFrmq*N*d6*KeNtn|OWZ%Ox7mzg?2% z-F52mtWqm$)%Vk;_eLCVHnd;e@J>79%F-QacN-+ktc+uo+Cl}tN17|N^`7&Y-jNu} kf6VkX+mR1x)4#ILS$Vwvl*X!AKuxx%m{{wGD>adCy2bctf+b8ayKVP?D4s|s;l=NuK4rt>b*ph1R(4= x{BmwCvXaG#GWSle|2AJfzTqMqZj9(=mtA82^Rc`CQlKjsJYD@<);T3K0RTJyRKoxO literal 0 HcmV?d00001 diff --git a/WatchFace.Parser/WeatherIcons/19.png b/WatchFace.Parser/WeatherIcons/19.png new file mode 100644 index 0000000000000000000000000000000000000000..6610b426f865a13bf694c2ea1ab057b8bfd36acc GIT binary patch literal 319 zcmeAS@N?(olHy`uVBq!ia0vp^av;pX1|+Qw)-3{3jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1quc!7H9Fjv*f2Py3^VS`>I#_WoZQ>#C$^(*H*3 zcVc+y)R~+sZXf)oZWyE3rhTNKRbr88M!5rzvHQZ!yoP(WR{U<0U^BgvZF;3yf{pc+ zN28U%;fkZIUzfC1DYt$6@x$A-(JEOkBIo{Qwl}-@P2MgntN-u4)?ubVaooRS_hg-B zJT5+Bsnl#c`F-yX!R>#UxkW7ar426T1O3O~ M>FVdQ&MBb@0GO|P+W-In literal 0 HcmV?d00001 diff --git a/WatchFace.Parser/WeatherIcons/2.png b/WatchFace.Parser/WeatherIcons/2.png new file mode 100644 index 0000000000000000000000000000000000000000..7388f00492163cdfbb8767d655ce46feef288a9f GIT binary patch literal 372 zcmV-)0gL{LP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0SQS&K~zXf-H!oo z#4rd1@Bg2^0>L>P#@NXl^6rAAVTM?r}p3?ImM~lyoF| zk!r_DMv0WJub`a(np31KLAwr`B~rGa8v>dgDD^jhyJ+4_r85h_Z8VLjDidRh?ey>d zU?YlhrIWr3Y`%Z@$CN0_Be%3KfZc31QAXU-egN!!9#6%r0;Rq~JHpkF!ca*ins@re zN4Ny-MLjdaGZPMcK~&1!&%q&@Qs#aR4$+h{_j7QFrj)s#gF`f>%zaY|za$Fs=|E;- zE{byDYDNl!7wUmO(sM5Gd5~gmkSCC6E`a85fM(77Z&pBajDGabK1}`=ulEnr_hsSa S6o!`o0000Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0OUzTK~zXf<&n`6 zf-npO{r{gvS`)m4EiDT5!JXNG+@*lyV`ce~7|syG8Dcm?4AB;}J0OO^QRwV}7;a|H z_6K5ERj5}L>Ol;v4t1nM9f+Yl;sy1jLVXfLJ3jtW*P$*MgG}ywwt(H!2M+BayWjsx z)uGI>oR>eb_Y9}bc3;VhSF3CjE#9H?$1g6>;*~1vEMJipuhy|Seo4U>cS5J+&dpfP zWx=~@nRB-4dw$iNke&B(Q3+k1O{J9=v@>_XEHRuRhCzk;*5A+(!=S&=ufdX0-WS85 hvg;`u6T_Q*EKkQpS?vxUli>gW002ovPDHLkV1m-UjDi3F literal 0 HcmV?d00001 diff --git a/WatchFace.Parser/WeatherIcons/21.png b/WatchFace.Parser/WeatherIcons/21.png new file mode 100644 index 0000000000000000000000000000000000000000..661c0578726c12808baec717b19e2b20ce64796f GIT binary patch literal 367 zcmV-#0g(QQP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0R%}zK~zXf)sKsg zgD?yP`~N@P;v`EpW(f2})saS5uQynCTe$y746hKwE5z^$F+}&E?g=p*JPW;@h~aAH z+5JQeiw^BwhxQE847Ma_Fs{N}h#v`=fAJ#&4V3g!WElZ#FkUmmfqrNSza6 zIQ0WZLkzp|d7F=pI7?k+nty)tmqT N002ovPDHLkV1j9xo4f!3 literal 0 HcmV?d00001 diff --git a/WatchFace.Parser/WeatherIcons/22.png b/WatchFace.Parser/WeatherIcons/22.png new file mode 100644 index 0000000000000000000000000000000000000000..83f35c5f9792822b4726db18a3364e1118169d36 GIT binary patch literal 316 zcmeAS@N?(olHy`uVBq!ia0vp^av;pX1|+Qw)-3{3jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1quc!Hb?Qjv*f2Py3^VS`>I#_WoZQTgl>-6Totl zfA^}@XM7y)@_n=Ke8^=Oqu8c>L}0DsZu27>KIoNfQ*86}&c83)0>(?;uzRNx`oqBCI-|zh)y8SQvr{C`XH9L=F0zJpz>FVdQ I&MBb@0J|4`UH||9 literal 0 HcmV?d00001 diff --git a/WatchFace.Parser/WeatherIcons/23.png b/WatchFace.Parser/WeatherIcons/23.png new file mode 100644 index 0000000000000000000000000000000000000000..afabb22513273f15c05e643c4abd5d7ac87708bc GIT binary patch literal 270 zcmeAS@N?(olHy`uVBq!ia0vp^av;pX1|+Qw)-3{3jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1quc!Nr~~jv*f2M<+0H9Z=vo^5_3@>voYS@tJ;m zc$u>OsuNbu|I6aVsv)`{q#=mW%Q!orZ1e2!fIR)W)7l`x3w34l-#Ody2(f=M(QsVJ z@btsWJN-rJk7T^|2#C9;owInDBQ>odHNt7#q&8JGZnvAp5linsEcTzCzO(CozxAT- zl1e`Rhf6OdY3!|RQ=cf_?!>;7X$n_>mcvR0Fhg$H4b~IJM~gY8-;)G7m%-E3&t;uc GLK6TEXk5_% literal 0 HcmV?d00001 diff --git a/WatchFace.Parser/WeatherIcons/24.png b/WatchFace.Parser/WeatherIcons/24.png new file mode 100644 index 0000000000000000000000000000000000000000..6494b91b74e342080c250a1e9162711a722fd15d GIT binary patch literal 278 zcmeAS@N?(olHy`uVBq!ia0vp^av;pX1|+Qw)-3{3jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1quc!PTBFjv*f2M=v;X9X8-`3B3RRQl7Y{g#W&n zq*;Xzb$@lH1pNN@OHD%9KyAyt-@DHpfAjyxMd?%R<_BjOw7s%fU9w%Wng7Kk(OtI_ zd=AWL5WJ|VZMV3ZPhz6pzoY3T=NXfkj>k~J z-N$sSTW|iy_oeO-g~3&ixXw!U1b>;Z*s|FWBzEbLr?!OmZMlE_*X$cB*d30X5|#ow Oo59o7&t;ucLK6Tl;A%Di literal 0 HcmV?d00001 diff --git a/WatchFace.Parser/WeatherIcons/25.png b/WatchFace.Parser/WeatherIcons/25.png new file mode 100644 index 0000000000000000000000000000000000000000..135f5b44ad4d50cc03078b3e619f4862aa11505b GIT binary patch literal 305 zcmeAS@N?(olHy`uVBq!ia0vp^av;pX1|+Qw)-3{3jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1quc!DF5-jv*f2Py3_!S`~O$@BUx5w@X(um1U33 zpMpuAZ!BF)tZ&2%9TrX6;lvZ(p;*QK)~q8jNxNj5LR;YZ%lj1C9J#-SaeoEUtyVz` z`Hlp{6*}5xF1**dP$qwWNa%{!79(6*00&?%(>Zy z{m-Ke-NHpjCAH-D{b&($&$3MWESguirR&Vi={^^gBBNf&$XIAE>*wG3GU@-Eu7^*x w#pk!bIe5=f{P3TE_j9@*itEpNwe3H{swyj9e(M>HKp!!9y85}Sb4q9e0LO!Nvj6}9 literal 0 HcmV?d00001 diff --git a/WatchFace.Parser/WeatherIcons/3.png b/WatchFace.Parser/WeatherIcons/3.png new file mode 100644 index 0000000000000000000000000000000000000000..9fa024c382f335cdb8c657034e80c5269e836746 GIT binary patch literal 374 zcmeAS@N?(olHy`uVBq!ia0vp^av;pX1|+Qw)-3{3jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1quc4cwkCjv*f2cY6cN4jXW=6#w^L?%{Zj>)4G| zSLeU0Zoa7ZVEW6w%-XW2{2YoUwf}!O9v0SLzUD%lk>AEieJhrSSo;}yt?{X4ean#% zm-JL@%j*S^NvWK>5*JuDX8mI-5I@`Oy>+Jafm{>oRa(Z6C+#!d|Gb%5^l7i>+t>@w zpMS4evv5(2<&|GdH_kp2NIkOf+I)uU`|eZHL{~hs-jZA+HHl|x$fC;hIG%^P8UCW1 z`_f}AJ}`uyx_kbhT3gVwIzBVQDMsImH*_wXvU7g3FVE65f7glFxv>6xdSHD(U>-=n z?E4>A=PWU9e6Q@ac}DonfH|BCW=eGZWxn7NGDW{BE$NR=oqWSH`Oj7V84SRvxx>DRDl1=8>+_ z=G9NzGN$#fOEXSY-xA_7{cTCcO@*MG?`_k>j|l8m++rgb{3guxw6NjPywG{^9I-mP z1uw>aVLz4UQX)QGo;RuM?y8JRrDZqPc0o1d2xxArcJ_8Hx#`zFO?r`KMTzNbP3whE z-(KWV+I)MOOWMZnj=T&>JFg{aYwiObcBq{>s;$Gm`UmTln$4-T3@0SxZ}!|=2?`$u MPgg&ebxsLQ0Py*LQvd(} literal 0 HcmV?d00001 diff --git a/WatchFace.Parser/WeatherIcons/5.png b/WatchFace.Parser/WeatherIcons/5.png new file mode 100644 index 0000000000000000000000000000000000000000..861ef6e9ae669be82e8d9ba3f879a10e67a15567 GIT binary patch literal 297 zcmeAS@N?(olHy`uVBq!ia0vp^av;pX1|+Qw)-3{3jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1quc!F`@Cjv*f2Px~+OH7f|P{QW#m_&Np)N@;d*zCrK!_2||dDILFP*NfkvRyKV~{UiCchzQEx%tyQaAtAO-^K9MVp z64S!>ES$F`;Qf&eG4ksFaP@nEpE2`{ z>k76_t6FqWw97uO#-Z7G>yphsxy&u11J6Czx4iH`$5!=uk?5^(@zbF{Y)|$pc=0G7 iF>nGB1siYwW13f6d|7$!^-DmXFnGH9xvXSS)HH=Yg(>_wrDzV5kW1BON|2L;o=f=MS~FoeTIB zwa>V&VB54!iw>%X{QL2Uh4xv6jhr7p>B7OtDwXF!7v*?=Nu{aXd+H8(mW)(IT8d;iz8E%)-$^|3yc`z7q&Y^!HT2{jNu`|__k&}$5yu6{1- HoD!MEGKX)``j&?a$CzCAJe!-W zf&$o+BH})_RT(+$?M$@1SHDu^%FN>jKK?r+Wl;Uo;j;0eH{a_eMW=L5`usum{5{1_ z`_>rSS=>6YZ}CBOk@}j#CN_7eo8KO4=M-#N^rk<4(uD^ab0-zg3=j`}=fB-;#!C4Q zer_xLtqeX3nuzY(r`YDJe5JfAF*NqsdFdnzXP)$qhlllEbDucj`S+Sm^FpBK7(8A5 KT-G@yGywn#_OnJA0S zYLs}|rEa3GYf_#x<@oXVRaz#+*A6~@ZmXP7{;P4B?U{Gq|6f`a5WM8`C-rad0zO67 zrT=-9rTf&SyL`o;kKMvsb_AU+HH&{J7QXt#&VQ3y^wwQcp4;AauKUUY_Zf4q7hMWI zd->+}1=VkSYPdJnINrIPbVu>njne;8%Cq&Bi@WUAbu-&l^KYqVk9qYRejjfK_8-%# R^nspa@O1TaS?83{1OUx5hTH%E literal 0 HcmV?d00001 diff --git a/WatchFace.Parser/WeatherIcons/9.png b/WatchFace.Parser/WeatherIcons/9.png new file mode 100644 index 0000000000000000000000000000000000000000..aa6c0e4527cd2324d710c6b3d53d5e0c64b28103 GIT binary patch literal 319 zcmeAS@N?(olHy`uVBq!ia0vp^av;pX1|+Qw)-3{3jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1quc!7H9Fjv*f2Px~(lH7oG2{QWLh$c7aG>$R>lONhz7 z@@TgbaNhlh_v;d;S^;P4d;f#3FVu@*pLioZj&bvLev`8kZodB?RH{*|^ZcRznRf-J z?pNl+N`|uQYtCprTDS*YpO{W&OGTI4-f0T=H4@-_;P@IlseFV N44$rjF6*2UngBRPgZTge literal 0 HcmV?d00001 diff --git a/WatchFace.Parser/packages.config b/WatchFace.Parser/packages.config index 8df43ff..773939d 100644 --- a/WatchFace.Parser/packages.config +++ b/WatchFace.Parser/packages.config @@ -1,6 +1,5 @@  - - - + + \ No newline at end of file diff --git a/WatchFace/Program.cs b/WatchFace/Program.cs index cdcbd97..301c5bc 100644 --- a/WatchFace/Program.cs +++ b/WatchFace/Program.cs @@ -3,6 +3,8 @@ using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; using System.IO; +using System.Reflection; +using BumpKit; using Newtonsoft.Json; using NLog; using NLog.Config; @@ -10,6 +12,7 @@ using NLog.Targets; using Resources; using Resources.Models; using WatchFace.Parser; +using WatchFace.Parser.Models; using WatchFace.Parser.Utils; using Reader = WatchFace.Parser.Reader; using Writer = WatchFace.Parser.Writer; @@ -20,6 +23,7 @@ namespace WatchFace { private const string AppName = "WatchFace"; + private static readonly bool IsRunningOnMono = Type.GetType("Mono.Runtime") != null; private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); private static void Main(string[] args) @@ -107,7 +111,7 @@ namespace WatchFace var imagesDirectory = Path.GetDirectoryName(inputFileName); try { - WriteWatchFace(outputFileName, imagesDirectory, watchFace); + WriteWatchFace(outputDirectory, outputFileName, imagesDirectory, watchFace); } catch (Exception) { @@ -128,13 +132,8 @@ namespace WatchFace var watchFace = ParseResources(reader); if (watchFace == null) return; - Logger.Debug("Generating previews..."); - var preview = PreviewGenerator.CreateImage(reader.Parameters, reader.Images.ToArray()); - preview.Save(Path.Combine(outputDirectory, $"{baseName}_preview.png"), ImageFormat.Png); - using (var gifOutput = File.OpenWrite(Path.Combine(outputDirectory, $"{baseName}_preview.gif"))) - { - PreviewGenerator.CreateGif(reader.Parameters, reader.Images.ToArray(), gifOutput); - } + + GeneratePreviews(reader.Parameters, reader.Images.ToArray(), outputDirectory, baseName); Logger.Debug("Exporting resources to '{0}'", outputDirectory); var reDescriptor = new FileDescriptor {Images = reader.Images}; @@ -192,7 +191,8 @@ namespace WatchFace } if (resDescriptor.ResourcesCount != null && resDescriptor.ResourcesCount.Value != images.Count) - throw new ArgumentException($"The .res-file should contain {resDescriptor.ResourcesCount.Value} images but was loaded {images.Count} images."); + throw new ArgumentException( + $"The .res-file should contain {resDescriptor.ResourcesCount.Value} images but was loaded {images.Count} images."); resDescriptor.Images = images; @@ -218,7 +218,7 @@ namespace WatchFace new Extractor(resDescriptor).Extract(outputDirectory); } - private static void WriteWatchFace(string outputFileName, string imagesDirectory, Parser.WatchFace watchFace) + private static void WriteWatchFace(string outputDirectory, string outputFileName, string imagesDirectory, Parser.WatchFace watchFace) { try { @@ -229,13 +229,8 @@ namespace WatchFace Logger.Trace("Building parameters for watch face..."); var descriptor = ParametersConverter.Build(watchFace); - Logger.Debug("Generating preview..."); - var preview = PreviewGenerator.CreateImage(descriptor, imagesReader.Images.ToArray()); - preview.Save(Path.ChangeExtension(outputFileName, ".png")); - using (var gifOutput = File.OpenWrite(Path.ChangeExtension(outputFileName, ".gif"))) - { - PreviewGenerator.CreateGif(descriptor, imagesReader.Images.ToArray(), gifOutput); - } + var baseFilename = Path.GetFileNameWithoutExtension(outputFileName); + GeneratePreviews(descriptor, imagesReader.Images.ToArray(), outputDirectory, baseFilename); Logger.Debug("Writing watch face to '{0}'", outputFileName); using (var fileStream = File.OpenWrite(outputFileName)) @@ -400,5 +395,109 @@ namespace WatchFace LogManager.Configuration = config; } + + private static void GeneratePreviews(List parameters, Bitmap[] images, string outputDirectory, string baseName) + { + Logger.Debug("Generating previews..."); + + var states = GetPreviewStates(); + var staticPreview = PreviewGenerator.CreateImage(parameters, images, new WatchState()); + staticPreview.Save(Path.Combine(outputDirectory, $"{baseName}_static.png"), ImageFormat.Png); + + var previewImages = PreviewGenerator.CreateAnimation(parameters, images, states); + + if (IsRunningOnMono) + { + var i = 0; + foreach (var previewImage in previewImages) + { + previewImage.Save(Path.Combine(outputDirectory, $"{baseName}_animated_{i}.png"), ImageFormat.Png); + i++; + } + } + else + { + using (var gifOutput = File.OpenWrite(Path.Combine(outputDirectory, $"{baseName}_animated.gif"))) + using (var encoder = new GifEncoder(gifOutput)) + { + foreach (var previewImage in previewImages) + encoder.AddFrame(previewImage, frameDelay: TimeSpan.FromSeconds(1)); + } + } + } + + private static IEnumerable GetPreviewStates() + { + var appPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + var previewStatesPath = Path.Combine(appPath, "PreviewStates.json"); + + if (File.Exists(previewStatesPath)) + using (var stream = File.OpenRead(previewStatesPath)) + using (var reader = new StreamReader(stream)) + { + var json = reader.ReadToEnd(); + return JsonConvert.DeserializeObject>(json); + } + + var previewStates = GenerateSampleStates(); + using (var stream = File.OpenWrite(previewStatesPath)) + using (var writer = new StreamWriter(stream)) + { + var json = JsonConvert.SerializeObject(previewStates, Formatting.Indented); + writer.Write(json); + writer.Flush(); + } + + return previewStates; + } + + private static IEnumerable GenerateSampleStates() + { + var time = DateTime.Now; + var states = new List(); + + for (var i = 0; i < 10; i++) + { + var num = i + 1; + var watchState = new WatchState + { + BatteryLevel = 100 - i * 10, + Pulse = 60 + num * 2, + Steps = num * 1000, + Calories = num * 75, + Distance = num * 700, + Bluetooth = num > 1 && num < 6, + Unlocked = num > 2 && num < 7, + Alarm = num > 3 && num < 8, + DoNotDisturb = num > 4 && num < 9, + + DayTemperature = -15 + 2 * i, + NightTemperature = -24 + i * 4, + }; + + if (num < 3) + { + watchState.AirQuality = AirCondition.Unknown; + watchState.AirQualityIndex = null; + + watchState.CurrentWeather = WeatherCondition.Unknown; + watchState.CurrentTemperature = null; + } + else + { + var index = num - 2; + watchState.AirQuality = (AirCondition) index; + watchState.CurrentWeather = (WeatherCondition) index; + + watchState.AirQualityIndex = index * 50 - 25; + watchState.CurrentTemperature = -10 + i * 6; + } + + watchState.Time = new DateTime(time.Year, num, num * 2 + 5, i * 2, i * 6, i); + states.Add(watchState); + } + + return states; + } } } \ No newline at end of file diff --git a/WatchFace/WatchFace.csproj b/WatchFace/WatchFace.csproj index 652baca..ec6d17b 100644 --- a/WatchFace/WatchFace.csproj +++ b/WatchFace/WatchFace.csproj @@ -35,16 +35,24 @@ 4 - - ..\packages\Newtonsoft.Json.10.0.3\lib\net40\Newtonsoft.Json.dll + + ..\packages\Bumpkit.1.0.2\lib\BumpKit.dll + + + + ..\packages\Newtonsoft.Json.11.0.2\lib\net40\Newtonsoft.Json.dll - ..\packages\NLog.4.4.12\lib\net40\NLog.dll + ..\packages\NLog.4.5.6\lib\net40-client\NLog.dll + + + + diff --git a/WatchFace/packages.config b/WatchFace/packages.config index ec8ab8b..e79e7bc 100644 --- a/WatchFace/packages.config +++ b/WatchFace/packages.config @@ -1,6 +1,6 @@  - - - + + + \ No newline at end of file