PageRenderTime 40ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/wp-toolkit/Microsoft.Phone.Controls.Toolkit/HubTile/HubTileService.cs

https://bitbucket.org/jeremejevs/milk-manager
C# | 379 lines | 217 code | 37 blank | 125 comment | 39 complexity | bbeee01db9c95605e0fc7716f3c636d6 MD5 | raw file
  1. // (c) Copyright Microsoft Corporation.
  2. // This source is subject to the Microsoft Public License (Ms-PL).
  3. // Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
  4. // All other rights reserved.
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Diagnostics.CodeAnalysis;
  8. using System.Windows.Threading;
  9. namespace Microsoft.Phone.Controls
  10. {
  11. /// <summary>
  12. /// Provides organized animations for the hub tiles.
  13. /// </summary>
  14. /// <QualityBand>Preview</QualityBand>
  15. public static class HubTileService
  16. {
  17. /// <summary>
  18. /// Number of steps in the pipeline
  19. /// </summary>
  20. private const int WaitingPipelineSteps = 3;
  21. /// <summary>
  22. /// Number of hub tile that can be animated at exactly the same time.
  23. /// </summary>
  24. private const int NumberOfSimultaneousAnimations = 1;
  25. /// <summary>
  26. /// Track resurrection for weak references.
  27. /// </summary>
  28. private const bool TrackResurrection = false;
  29. /// <summary>
  30. /// Timer to trigger animations in timely.
  31. /// </summary>
  32. private static DispatcherTimer Timer = new DispatcherTimer();
  33. /// <summary>
  34. /// Random number generator to take certain random decisions.
  35. /// e.g. which hub tile is to be animated next.
  36. /// </summary>
  37. private static Random ProbabilisticBehaviorSelector = new Random();
  38. /// <summary>
  39. /// Pool that contains references to the hub tiles that are not frozen.
  40. /// i.e. hub tiles that can be animated at the moment.
  41. /// </summary>
  42. private static List<WeakReference> EnabledImagesPool = new List<WeakReference>();
  43. /// <summary>
  44. /// Pool that contains references to the hub tiles which are frozen.
  45. /// i.e. hub tiles that cannot be animated at the moment.
  46. /// </summary>
  47. private static List<WeakReference> FrozenImagesPool = new List<WeakReference>();
  48. /// <summary>
  49. /// Pipeline that contains references to the hub tiles that where animated previously.
  50. /// These are stalled briefly before they can be animated again.
  51. /// </summary>
  52. private static List<WeakReference> StalledImagesPipeline = new List<WeakReference>();
  53. /// <summary>
  54. /// Static constructor to add the tick event handler.
  55. /// </summary>
  56. [SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline", Justification = "Attaching event handlers cannot be done inline.")]
  57. static HubTileService()
  58. {
  59. Timer.Tick += OnTimerTick;
  60. }
  61. /// <summary>
  62. /// Restart the timer to trigger animations.
  63. /// </summary>
  64. private static void RestartTimer()
  65. {
  66. if (!Timer.IsEnabled)
  67. {
  68. Timer.Interval = TimeSpan.FromMilliseconds(2500);
  69. Timer.Start();
  70. }
  71. }
  72. /// <summary>
  73. /// Add a reference to a newly instantiated hub tile.
  74. /// </summary>
  75. /// <param name="tile">The newly instantiated hub tile.</param>
  76. internal static void InitializeReference(HubTile tile)
  77. {
  78. WeakReference wref = new WeakReference(tile, TrackResurrection);
  79. if (tile.IsFrozen)
  80. {
  81. AddReferenceToFrozenPool(wref);
  82. }
  83. else
  84. {
  85. AddReferenceToEnabledPool(wref);
  86. }
  87. RestartTimer();
  88. }
  89. /// <summary>
  90. /// Remove all references of a hub tile before finalizing it.
  91. /// </summary>
  92. /// <param name="tile">The hub tile that is to be finalized.</param>
  93. internal static void FinalizeReference(HubTile tile)
  94. {
  95. WeakReference wref = new WeakReference(tile, TrackResurrection);
  96. HubTileService.RemoveReferenceFromEnabledPool(wref);
  97. HubTileService.RemoveReferenceFromFrozenPool(wref);
  98. HubTileService.RemoveReferenceFromStalledPipeline(wref);
  99. }
  100. /// <summary>
  101. /// Add a reference of a hub tile to the enabled images pool.
  102. /// </summary>
  103. /// <param name="tile">The hub tile to be added.</param>
  104. private static void AddReferenceToEnabledPool(WeakReference tile)
  105. {
  106. if (!ContainsTarget(EnabledImagesPool, tile.Target))
  107. {
  108. EnabledImagesPool.Add(tile);
  109. }
  110. }
  111. /// <summary>
  112. /// Add a reference of a hub tile to the frozen images pool.
  113. /// </summary>
  114. /// <param name="tile">The hub tile to be added.</param>
  115. private static void AddReferenceToFrozenPool(WeakReference tile)
  116. {
  117. if (!ContainsTarget(FrozenImagesPool, tile.Target))
  118. {
  119. FrozenImagesPool.Add(tile);
  120. }
  121. }
  122. /// <summary>
  123. /// Add a reference of a hub tile to the stalled images pipeline.
  124. /// </summary>
  125. /// <param name="tile">The hub tile to be added.</param>
  126. private static void AddReferenceToStalledPipeline(WeakReference tile)
  127. {
  128. if (!ContainsTarget(StalledImagesPipeline, tile.Target))
  129. {
  130. StalledImagesPipeline.Add(tile);
  131. }
  132. }
  133. /// <summary>
  134. /// Remove the reference of a hub tile from the enabled images pool.
  135. /// </summary>
  136. /// <param name="tile">The hub tile to be removed.</param>
  137. private static void RemoveReferenceFromEnabledPool(WeakReference tile)
  138. {
  139. RemoveTarget(EnabledImagesPool, tile.Target);
  140. }
  141. /// <summary>
  142. /// Remove the reference of a hub tile from the frozen images pool.
  143. /// </summary>
  144. /// <param name="tile">The hub tile to be removed.</param>
  145. private static void RemoveReferenceFromFrozenPool(WeakReference tile)
  146. {
  147. RemoveTarget(FrozenImagesPool, tile.Target);
  148. }
  149. /// <summary>
  150. /// Remove the reference of a hub tile from the stalled images pipeline.
  151. /// </summary>
  152. /// <param name="tile">The hub tile to be removed.</param>
  153. private static void RemoveReferenceFromStalledPipeline(WeakReference tile)
  154. {
  155. RemoveTarget(StalledImagesPipeline, tile.Target);
  156. }
  157. /// <summary>
  158. /// Determine if there is a reference to a known target in a list.
  159. /// </summary>
  160. /// <param name="list">The list to be examined.</param>
  161. /// <param name="target">The known target.</param>
  162. /// <returns>True if a reference to the known target exists in the list. False otherwise.</returns>
  163. private static bool ContainsTarget(List<WeakReference> list, Object target)
  164. {
  165. for (int i = 0; i < list.Count; i++)
  166. {
  167. if (list[i].Target == target)
  168. {
  169. return true;
  170. }
  171. }
  172. return false;
  173. }
  174. /// <summary>
  175. /// Remove a reference to a known target in a list.
  176. /// </summary>
  177. /// <param name="list">The list to be examined.</param>
  178. /// <param name="target">The known target.</param>
  179. private static void RemoveTarget(List<WeakReference> list, Object target)
  180. {
  181. for (int i = 0; i < list.Count; i++)
  182. {
  183. if (list[i].Target == target)
  184. {
  185. list.RemoveAt(i);
  186. return;
  187. }
  188. }
  189. }
  190. /// <summary>
  191. /// Executes the code to process a visual transition:
  192. /// 1. Stop the timer.
  193. /// 2. Advances the stalled tiles to the next step in the pipeline.
  194. /// If there is at least one tile that can be currently animated ...
  195. /// 3. Animate as many tiles as indicated.
  196. /// 4. Select a tile andomly from the pool of enabled tiles.
  197. /// 5. Based on this tile's current visual state, move it onto
  198. /// the next one.
  199. /// 6. Set the stalling counter for the recently animated image.
  200. /// 7. Take it out from the pool and into the pipeline to prevent it
  201. /// from being animated continuously.
  202. /// 8. Restart the timer with a randomly generated time interval
  203. /// between 100 and 3000 ms.
  204. /// Notice that if there are no hub tiles that can be animated,
  205. /// the timer is not restarted.
  206. /// </summary>
  207. /// <param name="sender">The static timer.</param>
  208. /// <param name="e">The event information.</param>
  209. private static void OnTimerTick(object sender, EventArgs e)
  210. {
  211. Timer.Stop();
  212. for (int i = 0; i < StalledImagesPipeline.Count; i++)
  213. {
  214. if ((StalledImagesPipeline[i].Target as HubTile)._stallingCounter-- == 0)
  215. {
  216. AddReferenceToEnabledPool(StalledImagesPipeline[i]);
  217. RemoveReferenceFromStalledPipeline(StalledImagesPipeline[i]);
  218. i--;
  219. }
  220. }
  221. if (EnabledImagesPool.Count > 0)
  222. {
  223. for (int j = 0; j < NumberOfSimultaneousAnimations; j++)
  224. {
  225. int index = ProbabilisticBehaviorSelector.Next(EnabledImagesPool.Count);
  226. switch ((EnabledImagesPool[index].Target as HubTile).State)
  227. {
  228. case ImageState.Expanded:
  229. //If the tile can neither drop nor flip, or if its size is Small, do not change state.
  230. if ((!(EnabledImagesPool[index].Target as HubTile)._canDrop && !(EnabledImagesPool[index].Target as HubTile)._canFlip) || (EnabledImagesPool[index].Target as HubTile).Size == TileSize.Small)
  231. {
  232. break;
  233. }
  234. //If the tile can only flip, change to the Flipped state.
  235. if (!(EnabledImagesPool[index].Target as HubTile)._canDrop && (EnabledImagesPool[index].Target as HubTile)._canFlip)
  236. {
  237. (EnabledImagesPool[index].Target as HubTile).State = ImageState.Flipped;
  238. break;
  239. }
  240. //If the tile can only drop, change to the Semidropped state.
  241. if (!(EnabledImagesPool[index].Target as HubTile)._canFlip && (EnabledImagesPool[index].Target as HubTile)._canDrop)
  242. {
  243. (EnabledImagesPool[index].Target as HubTile).State = ImageState.Semiexpanded;
  244. break;
  245. }
  246. //If the tile can drop and flip, change randomly either to the Semidropped state or the Flipped state.
  247. if (ProbabilisticBehaviorSelector.Next(2) == 0)
  248. {
  249. (EnabledImagesPool[index].Target as HubTile).State = ImageState.Semiexpanded;
  250. }
  251. else
  252. {
  253. (EnabledImagesPool[index].Target as HubTile).State = ImageState.Flipped;
  254. }
  255. break;
  256. case ImageState.Semiexpanded:
  257. (EnabledImagesPool[index].Target as HubTile).State = ImageState.Collapsed;
  258. break;
  259. case ImageState.Collapsed:
  260. (EnabledImagesPool[index].Target as HubTile).State = ImageState.Expanded;
  261. break;
  262. case ImageState.Flipped:
  263. (EnabledImagesPool[index].Target as HubTile).State = ImageState.Expanded;
  264. break;
  265. }
  266. (EnabledImagesPool[index].Target as HubTile)._stallingCounter = WaitingPipelineSteps;
  267. AddReferenceToStalledPipeline(EnabledImagesPool[index]);
  268. RemoveReferenceFromEnabledPool(EnabledImagesPool[index]);
  269. }
  270. }
  271. else if (StalledImagesPipeline.Count == 0)
  272. {
  273. return;
  274. }
  275. Timer.Interval = TimeSpan.FromMilliseconds(ProbabilisticBehaviorSelector.Next(1, 31) * 100);
  276. Timer.Start();
  277. }
  278. /// <summary>
  279. /// Freeze a hub tile.
  280. /// </summary>
  281. /// <param name="tile">The hub tile to be frozen.</param>
  282. public static void FreezeHubTile(HubTile tile)
  283. {
  284. WeakReference wref = new WeakReference(tile, TrackResurrection);
  285. AddReferenceToFrozenPool(wref);
  286. RemoveReferenceFromEnabledPool(wref);
  287. RemoveReferenceFromStalledPipeline(wref);
  288. }
  289. /// <summary>
  290. /// Unfreezes a hub tile and restarts the timer if needed.
  291. /// </summary>
  292. /// <param name="tile">The hub tile to be unfrozen.</param>
  293. public static void UnfreezeHubTile(HubTile tile)
  294. {
  295. WeakReference wref = new WeakReference(tile, TrackResurrection);
  296. AddReferenceToEnabledPool(wref);
  297. RemoveReferenceFromFrozenPool(wref);
  298. RemoveReferenceFromStalledPipeline(wref);
  299. RestartTimer();
  300. }
  301. /// <summary>
  302. /// Freezes all the hub tiles with the specified group tag that are not already frozen.
  303. /// </summary>
  304. /// <param name="group">The group tag representing the hub tiles that should be frozen.</param>
  305. public static void FreezeGroup(string group)
  306. {
  307. for (int i = 0; i < EnabledImagesPool.Count; i++)
  308. {
  309. if ((EnabledImagesPool[i].Target as HubTile).GroupTag == group)
  310. {
  311. (EnabledImagesPool[i].Target as HubTile).IsFrozen = true;
  312. i--;
  313. }
  314. }
  315. for (int j = 0; j < StalledImagesPipeline.Count; j++)
  316. {
  317. if ((StalledImagesPipeline[j].Target as HubTile).GroupTag == group)
  318. {
  319. (StalledImagesPipeline[j].Target as HubTile).IsFrozen = true;
  320. j--;
  321. }
  322. }
  323. }
  324. /// <summary>
  325. /// Unfreezes all the hub tiles with the specified group tag
  326. /// that are currently frozen and restarts the timer if needed.
  327. /// </summary>
  328. /// <param name="group">The group tag representing the hub tiles that should be unfrozen.</param>
  329. public static void UnfreezeGroup(string group)
  330. {
  331. for (int i = 0; i < FrozenImagesPool.Count; i++)
  332. {
  333. if ((FrozenImagesPool[i].Target as HubTile).GroupTag == group)
  334. {
  335. (FrozenImagesPool[i].Target as HubTile).IsFrozen = false;
  336. i--;
  337. }
  338. }
  339. RestartTimer();
  340. }
  341. }
  342. }