Skip to content

Display File Transfer Progress

Apollo Zhu requested to merge work/apollozhu/share/progress-display into master
  • Show the sending and receiving progress of files in each device's detail view
  • Fix receiving file with unknown/-1 length
  • Fixed incorrect attempt to send a file when sending and receiving files at the same time
  • Add https://github.com/apple/swift-collections from Apple under Apache License 2.0 as a dependency for OrderedDictionary
UI Preview full_file_transfer_section

TestFlight

Try out changes in this merge request by joining https://testflight.apple.com/join/gbsSOFZn. Limited to 100 external testers, will become unavailable once this merge request is merged.

Technical Design and Architecture

Components

  • Device: owns lan link and the share plugin.
  • Share Plugin: keep track of what needs to be transferred and moving the files to appropriate places
  • LanLink: handles socket, transferring metadata network packages, and actually transfer of files
  • FileTransferStatusSection: displays the status of current device's share plugin

Dataflow

  1. Share Plugin demands its Device to send network packages
    1. Send share for each of the new files to send
    2. Send shareRequestUpdate when additional files are added the the send queue
  2. The Device asks each of its links to send the package
  3. LanLink informs update to its LinkDelegate, i.e. the Device
    • Send
      • progress update: LinkDelegate.onSendingPayload(_:)
      • completion: LinkDelegate.onPackage(_:sentWithPackageTag:)
      • failure: LinkDelegate.onPackage(_:sendWithPackageTag:failedWithError:)
        • if the error is on our end, close the socket if it's currently active
    • Receive
      • progress update:
        • start: LinkDelegate.willReceivePayload(_:totalNumOfFilesToReceive:)
        • during: LinkDelegate.onReceivingPayload(_:)
      • completion: LinkDelegate.onPackageReceived
      • failure: LinkDelegate.onReceivingPayload(_:failedWithError:)
        • if the error is on our end, close the socket if it's currently active
  4. The Device informs each of its Plugins of the update, if they can respond to it.
    • Send
      • progress update: Plugin.onSendingPayload(_:)
      • completion: Plugin.onPackage(_:sentWithPackageTag:)
      • failure: Plugin.onPackage(_:sendWithPackageTag:failedWithError:)
        • cancel sending any remaining files
    • Receive
      • progress update:
        • shareRequestUpdate: Plugin.onDevicePackageReceived(np:)
        • actual payload:
          • start: Plugin.willReceivePayload(_:totalNumOfFilesToReceive:)
          • during: Plugin.onReceivingPayload(_:)
        • note that onDevicePackageReceived updates totalNumOfFilesToReceive when the other client adds additional file, and willReceivePayload updates totalNumOfFilesToReceive also in case if the other client doesn't send an update package.
      • completion: Plugin.onDevicePackageReceived(np:)
      • failure: Plugin.onReceivingPayload(_:failedWithError:)
        • cancel receiving any remaining files -- except for Soduto implementation where multiple files are sent in parallel.

Implementation Details

  • socket.userData stores the FileTransferItem that the current socket is responsible for. This allows us to add additional information to keep track of without the need to add yet another NSMutableArray to LanLink (as seen in !82 (merged)).
  • FileTransferItemInfo, FileTransferItem, and KDEFileTransferItem
    • FileTransferItemInfo is an Identifiable struct for keeping track of what needs to be transferred in Swift, while FileTransferItem is an Objective-C compatible class for use in LanLink/Objective-C backend
    • From our style guide, "Prefixes are commonly required in Objective-C to avoid naming collisions in a global namespace.", so KDEFileTransferItem is the Objective-C name for FileTransferItem (prefix "KDE-"), hence why "the class name is different" when using Objective-C vs. Swift.
  • For files with unknown length, we don't really know if it actually finished transferring, so socket disconnect is the best finish indicator. This means that even if the other client cancelled transfer instead of finished transferring we won't know for sure if the entire file has been received, but I don't think we would be able to tell anyways...
  • To support using file size formatter, the formatter based Text initialization API has been back ported to iOS 14 with some compiler @_semantics. See comments in iOS14+TextFormat.swift for details.

Additional Notes

  • The Qt client sends share update packets/network package but does not update its UI upon receiving one. Android client does.
  • Soduto sends multiple files in parallel all at once and doesn't provide a numOfFiles field.
  • Maybe we should allow cancelling sending/receiving from the UI in the future
  • The animation is not very great... the numbers jumps too fast, might want to throttle the updates
Edited by Apollo Zhu

Merge request reports