/// <summary>
 /// Конструктор.
 /// </summary>
 /// <param name="link">Ссылка.</param>
 /// <param name="visited">Посещённые.</param>
 /// <param name="favorites">Избранные.</param>
 public VisitedMainTileViewModel(BoardLinkBase link, ThreadLinkCollection visited, ThreadLinkCollection favorites)
 {
     if (link == null) throw new ArgumentNullException(nameof(link));
     this.link = link;
     TileData = new VisitedThreadTileViewModel(link);
     var upd = (IThreadTileUpdater)TileData;
     upd.UpdateData(visited);
     FavoritesChanged(favorites);
     hash = ServiceLocator.Current.GetServiceOrThrow<ILinkHashService>().GetLinkHash(link);
     if (visited?.ThreadInfo != null)
     {
         threadInfo = visited.ThreadInfo.ContainsKey(hash) ? visited.ThreadInfo[hash] : null;
     }
 }
 /// <summary>
 /// Конструктор.
 /// </summary>
 /// <param name="link">Ссылка.</param>
 /// <param name="favorites">Избранные треды.</param>
 public FavoriteMainTileViewModel(BoardLinkBase link, ThreadLinkCollection favorites)
 {
     if (link == null) throw new ArgumentNullException(nameof(link));
     this.link = link;
     TileData = new FavoriteThreadTileViewModel(link);
     var upd = (IThreadTileUpdater) TileData;
     var si = upd?.UpdateData(favorites);
     if (si != null)
     {
         UpdateId = new ThreadListUpdateId() { LinkHash = ServiceLocator.Current.GetServiceOrThrow<ILinkHashService>().GetLinkHash(link), SortDate = si.AddedDate, Link = link };
     }
     else
     {
         UpdateId = new ThreadListUpdateId() { LinkHash = ServiceLocator.Current.GetServiceOrThrow<ILinkHashService>().GetLinkHash(link), SortDate = DateTime.MinValue, Link = link };
     }
 }
 /// <summary>
 /// Изменились посещённые.
 /// </summary>
 /// <param name="visited">Посещённые.</param>
 public void VisitedChanged(ThreadLinkCollection visited)
 {
 }
 /// <summary>
 /// Избранные изменились.
 /// </summary>
 /// <param name="favorites">Избранные.</param>
 public void FavoritesChanged(ThreadLinkCollection favorites)
 {
     (TileData as IThreadTileUpdater)?.UpdateData(favorites);
 }
 /// <summary>
 /// Изменились посещённые.
 /// </summary>
 /// <param name="visited">Посещённые.</param>
 public void VisitedChanged(ThreadLinkCollection visited)
 {
     if (visited?.ThreadInfo != null)
     {
         threadInfo = visited.ThreadInfo.ContainsKey(hash) ? visited.ThreadInfo[hash] : null;
     }
 }
 /// <summary>
 /// Избранные изменились.
 /// </summary>
 /// <param name="favorites">Избранные.</param>
 public void FavoritesChanged(ThreadLinkCollection favorites)
 {
     if (favorites?.Links != null)
     {
         var linkHash = ServiceLocator.Current.GetServiceOrThrow<ILinkHashService>();
         var comparer = linkHash.GetComparer();
         IsFavorite = favorites.Links.Any(l => comparer.Equals(l, link));
         CanAddToFavorites = !IsFavorite;
         CanRemoveFromFavorites = IsFavorite;
     }
 }
 /// <summary>
 /// Добавить в избранные треды.
 /// </summary>
 /// <param name="link">Ссылка.</param>
 /// <param name="info">Информация о треде.</param>
 /// <param name="reportError">Показать ошибку на экране.</param>
 /// <returns>Треды.</returns>
 public static async Task AddToFavoriteThreads(this BoardLinkBase link, ShortThreadInfo info = null, bool reportError = true)
 {
     if (link != null)
     {
         try
         {
             var storage = ServiceLocator.Current.GetServiceOrThrow<IStorageService>();
             var linkHash = ServiceLocator.Current.GetServiceOrThrow<ILinkHashService>();
             var threadProcess = ServiceLocator.Current.GetServiceOrThrow<IThreadTreeProcessService>();
             var comparer = linkHash.GetComparer();
             var hash = linkHash.GetLinkHash(link);
             var favs = await storage.ThreadData.FavoriteThreads.LoadLinkCollection() as ThreadLinkCollection;
             if (favs == null)
             {
                 favs = new ThreadLinkCollection();
             }
             if (favs.Links == null)
             {
                 favs.Links = new List<BoardLinkBase>();
             }
             if (favs.ThreadInfo == null)
             {
                 favs.ThreadInfo = new Dictionary<string, ShortThreadInfo>();
             }
             if (favs.Links.Any(f => comparer.Equals(f, link)))
             {
                 return;
             }
             if (info == null)
             {
                 var visited = await storage.ThreadData.VisitedThreads.LoadLinkCollectionForReadOnly() as ThreadLinkCollection;
                 if (visited?.ThreadInfo != null)
                 {
                     if (visited.ThreadInfo.ContainsKey(hash))
                     {
                         info = visited.ThreadInfo[hash];
                     }
                 }
             }
             if (info == null)
             {
                 var data = await storage.ThreadData.LoadThread(link);
                 if (data != null)
                 {
                     info = threadProcess.GetShortInfo(data);
                 }
             }
             if (info == null)
             {
                 throw new InvalidOperationException("Информация о треде не найдена");
             }
             var pc = await storage.ThreadData.LoadPostCountInfo(link) ?? PostCountInfo.Create(link);
             favs.Links.Add(link);
             favs.Links = favs.Links.Deduplicate(f => f, comparer).ToList();
             var favInfo = new FavoriteThreadInfo()
             {
                 CountInfo = pc,
                 SmallImage = info.SmallImage,
                 Title = info.Title,
                 AddedDate = DateTime.Now,
                 CreatedDate = info.CreatedDate,
                 UpdatedDate = info.UpdatedDate,
                 ViewDate = info.ViewDate
             };
             favs.ThreadInfo[hash] = favInfo;
             await storage.ThreadData.FavoriteThreads.SaveLinkCollection(favs);
         }
         catch (Exception ex)
         {
             if (reportError)
             {
                 await AppHelpers.ShowError(ex);
             }
             else
             {
                 DebugHelper.BreakOnError(ex);
             }
         }
         finally
         {
             ViewModelEvents.FavoritesListRefreshed.RaiseEvent(link, null);
         }
     }
 }