Display File Transfer Progress
- 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_sectionTestFlight
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
- Share Plugin demands its Device to send network packages
- Send
share
for each of the new files to send - Send
shareRequestUpdate
when additional files are added the the send queue
- Send
- The Device asks each of its links to send the package
- 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
- progress update:
- Receive
- progress update:
- start:
LinkDelegate.willReceivePayload(_:totalNumOfFilesToReceive:)
- during:
LinkDelegate.onReceivingPayload(_:)
- start:
- completion:
LinkDelegate.onPackageReceived
- failure:
LinkDelegate.onReceivingPayload(_:failedWithError:)
- if the error is on our end, close the socket if it's currently active
- progress update:
- Send
- 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
- progress update:
- Receive
- progress update:
-
shareRequestUpdate
:Plugin.onDevicePackageReceived(np:)
- actual payload:
- start:
Plugin.willReceivePayload(_:totalNumOfFilesToReceive:)
- during:
Plugin.onReceivingPayload(_:)
- start:
- note that
onDevicePackageReceived
updatestotalNumOfFilesToReceive
when the other client adds additional file, andwillReceivePayload
updatestotalNumOfFilesToReceive
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.
- progress update:
- Send
Implementation Details
-
socket.userData
stores theFileTransferItem
that the currentsocket
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
, andKDEFileTransferItem
-
FileTransferItemInfo
is an Identifiable struct for keeping track of what needs to be transferred in Swift, whileFileTransferItem
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 forFileTransferItem
(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 iniOS14+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