-
Notifications
You must be signed in to change notification settings - Fork 150
Download Progress #38
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Good question! This is super-tricky, we're trying to clean it up in #17 . It's kind of messy, but you can get around this by emitting the progress things from within in Action's block before it is mapped to void. Pseudocode: let action = Action { [weak self] _ in
return download.onNext { progress in
self?.progressSignal.update(progress)
}.map(void)
} Like I said, it's not totally clean but it should work. Let me know 👍 |
thanks @ashfurrow, that's a solution I considered but I don't feel comfortable doing sideeffects this way. Makes that What I ended up doing is a workaround where I use
controlEvent.subscribeNext { _ -> Void in
action.execute()
}.addDisposableTo(self.actionDisposeBag) So in my view(table cell) where I subscribe to signals from my download action I do the following: // somewhere else in the cell file
// @IBOutlet weak var downloadButton: UIButton!
// @IBOutlet weak var downloadProgressView: UIView!
// @IBOutlet weak var downloadProgressViewWidth: NSLayoutConstraint!
// var viewModel: JRItineraryViewModel!
// var disposeBag = DisposeBag()
let downloadOfflineItineraryAction = viewModel.downloadOfflineItineraryAction
// step 1. bind enabled state
downloadOfflineItineraryAction.enabled.bindTo(downloadButton.rx_enabled).addDisposableTo(disposeBag)
// step 2. listen for progress events from the action
downloadOfflineItineraryAction.elements.observeOn(MainScheduler.instance).subscribeNext({ [weak self] (progress) in
if let strongSelf = self {
strongSelf.downloadProgressView.hidden = false
strongSelf.downloadButton.setTitle("Saving \(progress)%", forState: UIControlState.Normal)
strongSelf.downloadProgressViewWidth.constant = CGFloat(progress) / 100 * strongSelf.downloadButton.frame.size.width
strongSelf.setNeedsLayout()
}
}).addDisposableTo(disposeBag)
// step 3. listen for error events from the action
downloadOfflineItineraryAction.errors.subscribeNext({ [weak self] (error) in
self?.downloadProgressView.hidden = true
self?.downloadProgressViewWidth.constant = 0
self?.downloadButton.setTitle("There was an error", forState: UIControlState.Normal)
self?.setNeedsLayout()
}).addDisposableTo(disposeBag)
// step 4. bind tap event to execute the action
downloadButton.rx_tap.subscribeNext({ [weak self] (_) in
if let strongSelf = self {
// omitted analytics code here.
downloadOfflineItineraryAction.execute().subscribe(onCompleted: { [weak self] in
self?.downloadProgressView.hidden = true
self?.downloadProgressViewWidth.constant = 0
self?.setNeedsLayout()
}, onDisposed: { [weak self] in
self?.downloadProgressView.hidden = true
self?.downloadProgressViewWidth.constant = 0
self?.setNeedsLayout()
}).addDisposableTo(strongSelf.disposeBag)
}
}).addDisposableTo(disposeBag) And my action that's created in viewmodel looks like this: func downloadOfflineItineraryAction(itinerary: JRItinerary) -> Action<Void, Int> {
return Action(workFactory: { [unowned self] (input) -> Observable<Int> in
return Observable.combineLatest(self.HTMLFilesDownloadSignal(itinerary).startWith(0), self.mapDownloadSignal(itinerary).startWith(0)) { (progress1, progress2) -> Int in
return (progress1 + progress2) / 2
}.observeOn(ConcurrentDispatchQueueScheduler(globalConcurrentQueueQOS: .Background))
})
} Notice that @ashfurrow let me know what you think about this solution and I hope it will be helpful for others who want to show download progress in their apps too |
Yeah, it's pretty much a choice of where the side effects make sense to put – that's all FRP really is, isolating side effects. Subscribing to the Where do you think makes sense to document this? |
I'm working on a blog post to describe it in details. I think I can send a
|
I think a blog post is the perfect spot, adding a link to the readme is a great idea, I'd happily accept that pull request. |
@ashfurrow awesome. was working on it today. unfortunately can't finish tonight. my work in progress is here https://www.softcover.io/read/41bc8669/rx_action I'll post here and create a PR for README when I'm done. Thx. |
Cool, looking forward to the PR! No rush though – don't stress about it! |
@ashfurrow just published it http://www.sm-cloud.com/rxswift-action/ a PR is coming in soon |
related to this conversation RxSwiftCommunity#38
closed with this PR #39 |
Hi @ashfurrow, thanks for doing all this great work! Trying to use
Action
in my current project and have gotten into a bit of a jam - I have a download button that will pull several files from our backend and I am creating aCocoaAction
for it. But I don't know how I can pull progress from the underlyingObservable
that actually does the work (I have aObservable<Int>
that emits progress events, each event is one percent of overall progress upto 100% when it sendsonComplete
). Seems likeCocoaAction
's signature isAction<Void, Void>
which means it takes no argument (makes sense because a button calls it) and it emits no values in itselements
Observable
(I've used your trick from here to map toVoid
).I'm sure I'm missing something trivial but how can I observe my download progress and get a notification when the whole process/action is done (onComplete)?
Thanks in advance!
The text was updated successfully, but these errors were encountered: