/// <summary> /// Loads image data from a local file and set it to current image data. /// </summary> /// <param name="item">Target item</param> internal async Task LoadSetAsync(FileItemViewModel item) { _tokenSourceLoading?.TryCancel(); // Canceling already canceled source will be simply ignored. try { _tokenSourceLoading = new CancellationTokenSourcePlus(); byte[] data = null; if (item.IsAvailableLocal && item.CanLoadDataLocal) { data = await FileAddition.ReadAllBytesAsync(ComposeLocalPath(item), _tokenSourceLoading.Token); } CurrentItem = item; CurrentImageData = data; } catch (OperationCanceledException) { // None. } catch (FileNotFoundException) { item.Status = FileStatus.NotCopied; item.IsAliveLocal = false; } catch (IOException) { item.IsAvailableLocal = false; } catch (Exception ex) { Debug.WriteLine($"Failed to load image data from local file.\r\n{ex}"); throw new UnexpectedException("Failed to load image data from local file.", ex); } finally { _tokenSourceLoading?.Dispose(); } }
/// <summary> /// Checks files in FlashAir card. /// </summary> private async Task CheckFileBaseAsync() { OperationStatus = Resources.OperationStatus_Checking; try { using (var manager = new FileManager()) { _tokenSourceWorking = new CancellationTokenSourcePlus(); // Check firmware version. _card.FirmwareVersion = await manager.GetFirmwareVersionAsync(_tokenSourceWorking.Token); // Check CID. if (_card.CanGetCid) { _card.Cid = await manager.GetCidAsync(_tokenSourceWorking.Token); } // Check SSID and check if PC is connected to FlashAir card by a wireless connection. _card.Ssid = await manager.GetSsidAsync(_tokenSourceWorking.Token); _card.IsWirelessConnected = NetworkChecker.IsWirelessNetworkConnected(_card.Ssid); // Get all items. var fileListNew = (await manager.GetFileListRootAsync(_card, _tokenSourceWorking.Token)) .Select(fileItem => new FileItemViewModel(fileItem)) .ToList(); fileListNew.Sort(); // Record time stamp of write event. if (_card.CanGetWriteTimeStamp) { _card.WriteTimeStamp = await manager.GetWriteTimeStampAsync(_tokenSourceWorking.Token); } await Task.Run(() => { // Check if any sample is in old items. var isSample = FileListCore.Any(x => x.Size == 0); // Check if FlashAir card is changed. bool isChanged; if (_card.IsChanged.HasValue) { isChanged = _card.IsChanged.Value; } else { var signaturesOld = new HashSet <string>(FileListCore.Select(x => x.Signature)); isChanged = !fileListNew.Select(x => x.Signature).Any(x => signaturesOld.Contains(x)); } if (isSample || isChanged) { FileListCore.Clear(); } // Check old items. foreach (var itemOld in FileListCore) { var itemSameIndex = fileListNew.IndexOf(x => x.FilePath.Equals(itemOld.FilePath, StringComparison.OrdinalIgnoreCase) && (x.Size == itemOld.Size)); if (itemSameIndex >= 0) { itemOld.IsAliveRemote = true; itemOld.FileItem = fileListNew[itemSameIndex].FileItem; fileListNew.RemoveAt(itemSameIndex); continue; } itemOld.IsAliveRemote = false; } // Add new items (This operation may be heavy). var isLeadOff = true; foreach (var itemNew in fileListNew) { if (isLeadOff) { InvokeSafely(() => FileListCoreViewIndex = FileListCoreView.IndexOf(itemNew)); isLeadOff = false; } itemNew.IsAliveRemote = true; FileListCore.Insert(itemNew); // Customized Insert method } // Check all local files. foreach (var item in FileListCore) { var info = GetFileInfoLocal(item); item.IsAliveLocal = IsAliveLocal(info, item.Size); item.IsAvailableLocal = IsAvailableLocal(info); item.Status = item.IsAliveLocal ? FileStatus.Copied : FileStatus.NotCopied; } // Manage deleted items. var itemDeletedPairs = FileListCore .Select((x, Index) => !x.IsAliveRemote ? new { Item = x, Index } : null) .Where(x => x != null) .OrderByDescending(x => x.Index) .ToArray(); foreach (var itemDeletedPair in itemDeletedPairs) { var item = itemDeletedPair.Item; if (Settings.Current.MovesFileToRecycle && item.IsDescendant && (item.Status == FileStatus.Copied)) { try { Recycle.MoveToRecycle(ComposeLocalPath(item)); item.Status = FileStatus.Recycled; } catch (Exception ex) { Debug.WriteLine($"Failed to move a file to Recycle.\r\n{ex}"); item.Status = FileStatus.NotCopied; } } if (!item.IsDescendant || ((item.Status != FileStatus.Copied) && (item.Status != FileStatus.Recycled))) { FileListCore.RemoveAt(itemDeletedPair.Index); } } }); // Get thumbnails (from local). foreach (var item in FileListCore.Where(x => x.IsTarget && !x.HasThumbnail)) { if (!item.IsAliveLocal || !item.IsAvailableLocal || !item.CanLoadDataLocal) { continue; } _tokenSourceWorking.Token.ThrowIfCancellationRequested(); try { if (item.CanReadExif) { item.Thumbnail = await ImageManager.ReadThumbnailAsync(ComposeLocalPath(item)); } else if (item.CanLoadDataLocal) { item.Thumbnail = await ImageManager.CreateThumbnailAsync(ComposeLocalPath(item)); } } catch (FileNotFoundException) { item.Status = FileStatus.NotCopied; item.IsAliveLocal = false; } catch (IOException) { item.IsAvailableLocal = false; } catch (ImageNotSupportedException) { item.CanLoadDataLocal = false; } } // Get thumbnails (from remote). foreach (var item in FileListCore.Where(x => x.IsTarget && !x.HasThumbnail)) { if (!item.IsAliveRemote || !item.CanGetThumbnailRemote) { continue; } _tokenSourceWorking.Token.ThrowIfCancellationRequested(); try { item.Thumbnail = await manager.GetThumbnailAsync(item.FilePath, _card, _tokenSourceWorking.Token); } catch (RemoteFileThumbnailFailedException) { item.CanGetThumbnailRemote = false; } } } OperationStatus = Resources.OperationStatus_CheckCompleted; } finally { FileListCoreViewIndex = -1; // No selection _tokenSourceWorking?.Dispose(); } }
/// <summary> /// Copies files from FlashAir card. /// </summary> /// <param name="progress">Progress</param> private async Task CopyFileBaseAsync(IProgress <ProgressInfo> progress) { CopyStartTime = DateTime.Now; _copyFileCount = 0; if (!FileListCore.Any(x => x.IsTarget && (x.Status == FileStatus.ToBeCopied))) { OperationStatus = Resources.OperationStatus_NoFileToBeCopied; return; } OperationStatus = Resources.OperationStatus_Copying; try { using (var manager = new FileManager()) { _tokenSourceWorking = new CancellationTokenSourcePlus(); // Check CID. if (_card.CanGetCid) { if (await manager.GetCidAsync(_tokenSourceWorking.Token) != _card.Cid) { throw new CardChangedException(); } } // Check if upload.cgi is disabled. if (Settings.Current.DeleteOnCopy && _card.CanGetUpload) { _card.Upload = await manager.GetUploadAsync(_tokenSourceWorking.Token); if (_card.IsUploadDisabled) { throw new CardUploadDisabledException(); } } while (true) { var item = FileListCore.FirstOrDefault(x => x.IsTarget && (x.Status == FileStatus.ToBeCopied)); if (item == null) { break; // Copy completed. } _tokenSourceWorking.Token.ThrowIfCancellationRequested(); try { item.Status = FileStatus.Copying; FileListCoreViewIndex = FileListCoreView.IndexOf(item); var localPath = ComposeLocalPath(item); var localDirectory = Path.GetDirectoryName(localPath); if (!string.IsNullOrEmpty(localDirectory) && !Directory.Exists(localDirectory)) { Directory.CreateDirectory(localDirectory); } var data = await manager.GetSaveFileAsync(item.FilePath, localPath, item.Size, item.Date, item.CanReadExif, progress, _card, _tokenSourceWorking.Token); CurrentItem = item; CurrentImageData = data; if (!item.HasThumbnail) { try { if (item.CanReadExif) { item.Thumbnail = await ImageManager.ReadThumbnailAsync(CurrentImageData); } else if (item.CanLoadDataLocal) { item.Thumbnail = await ImageManager.CreateThumbnailAsync(CurrentImageData); } } catch (ImageNotSupportedException) { item.CanLoadDataLocal = false; } } item.CopiedTime = DateTime.Now; item.IsAliveLocal = true; item.IsAvailableLocal = true; item.Status = FileStatus.Copied; _copyFileCount++; } catch (RemoteFileNotFoundException) { item.IsAliveRemote = false; } catch (RemoteFileInvalidException) { item.Status = FileStatus.Weird; } catch { item.Status = FileStatus.ToBeCopied; // Revert to status before copying. throw; } if (Settings.Current.DeleteOnCopy && !item.IsReadOnly && IsAliveLocal(item)) { await manager.DeleteFileAsync(item.FilePath, _tokenSourceWorking.Token); } } } OperationStatus = string.Format(Resources.OperationStatus_CopyCompleted, _copyFileCount, (int)(DateTime.Now - CopyStartTime).TotalSeconds); } finally { FileListCoreViewIndex = -1; // No selection _tokenSourceWorking?.Dispose(); } }