loginButton.publishPermissions = ["publish_actions"]
func addFeed(feedMessage: String) -> Observable<Any> { return Observable.create { observer in let parameters = ["message": feedMessage] let addFeedRequest = FBSDKGraphRequest.init(graphPath: "me/feed", parameters: parameters, HTTPMethod: "POST") addFeedRequest.startWithCompletionHandler { (connection, result, error) -> Void in if error != nil { observer.on(.Error(error!)) } else { observer.on(.Next(result)) observer.on(.Completed) } } return AnonymousDisposable { } } }
class AddPostViewModel { let validatedText: Observable<Bool> let sendEnabled: Observable<Bool> // If some process in progress let indicator: Observable<Bool> // Has feed send in let sendedIn: Observable<Any> init(input: ( feedText: Observable<String>, sendButton: Observable<Void> ), dependency: ( API: APIManager, wireframe: Wireframe ) ) { let API = dependency.API let wireframe = dependency.wireframe let indicator = ViewIndicator() self.indicator = indicator.asObservable() validatedText = input.feedText .map { text in return text.characters.count > 0 } .shareReplay(1) sendedIn = input.sendButton.withLatestFrom(input.feedText) .flatMap { feedText -> Observable<Any> in return API.addFeed(feedText).trackView(indicator) } .catchError { error in return wireframe.promptFor((error as NSError).localizedDescription, cancelAction: "OK", actions: []) .map { _ in return error } .flatMap { error -> Observable<Any> in return Observable.error(error) } } .retry() .shareReplay(1) sendEnabled = Observable.combineLatest( validatedText, indicator.asObservable() ) { text, sendingIn in text && !sendingIn } .distinctUntilChanged() .shareReplay(1) } }
validatedText = input.feedText .map { text in return text.characters.count > 0 } .shareReplay(1)
sendEnabled = Observable.combineLatest( validatedText, indicator.asObservable() ) { text, sendingIn in text && !sendingIn } .distinctUntilChanged() .shareReplay(1)
sendedIn = input.sendButton.withLatestFrom(input.feedText) .flatMap { feedText -> Observable<Any> in return API.addFeed(feedText).trackView(indicator) } .catchError { error in return wireframe.promptFor((error as NSError).localizedDescription, cancelAction: "OK", actions: []) .map { _ in return error } .flatMap { error -> Observable<Any> in return Observable.error(error) } } .retry() .shareReplay(1)
let viewModel = AddPostViewModel( input: ( feedText: feedTextView.rx_text.asObservable(), sendButton: sendFeed.rx_tap.asObservable() ), dependency: ( API: APIManager.sharedAPI, wireframe: DefaultWireframe.sharedInstance ) ) let progress = MBProgressHUD() progress.mode = MBProgressHUDMode.Indeterminate progress.labelText = " ..." progress.dimBackground = true viewModel.indicator.asObservable() .bindTo(progress.rx_mbprogresshud_animating) .addDisposableTo(disposeBag) viewModel.sendEnabled .subscribeNext { [weak self] valid in self!.sendFeed.enabled = valid self!.sendFeed.alpha = valid ? 1.0 : 0.5 } .addDisposableTo(self.disposeBag) viewModel.sendedIn .flatMap { _ -> Observable<String> in return DefaultWireframe.sharedInstance.promptFor(" !", cancelAction: "OK", actions: []) .flatMap { action -> Observable<Any> in return Observable.just(action) } } .subscribeNext { action in self.navigationController?.popToRootViewControllerAnimated(true) } .addDisposableTo(self.disposeBag)
let booleans = ["f": false, "t": true]
--f-----t---
[shedule onNext(false) @ 0.4s, shedule onNext(true) @ 1.6s]
target 'ReactiveAppTests' do pod 'RxTests', '~> 2.0' pod 'FBSDKLoginKit' pod 'RxCocoa', '~> 2.0' end
class MockAPI : API { let _getFeeds: () -> Observable<GetFeedsResponse> let _getFeedInfo: (String) -> Observable<GetFeedInfoResponse> let _addFeed: (String) -> Observable<AnyObject> init( getFeeds: () -> Observable<GetFeedsResponse> = notImplemented(), getFeedInfo: (String) -> Observable<GetFeedInfoResponse> = notImplemented(), addFeed: (String) -> Observable<Any> = notImplemented() ) { _getFeeds = getFeeds _getFeedInfo = getFeedInfo _addFeed = addFeed } func getFeeds() -> Observable<GetFeedsResponse> { return _getFeeds() } func getFeedInfo(feedId: String) -> Observable<GetFeedInfoResponse> { return _getFeedInfo(feedId) } func addFeed(feedMessage: String) -> Observable<AnyObject> { return _addFeed(feedMessage) } }
extension ReactiveAppTests { func mockAPI(scheduler: TestScheduler) -> API { return MockAPI( getFeeds: scheduler.mock(feeds, errors: errors) { _ -> String in return "--fs" }, getFeedInfo: scheduler.mock(feedInfo, errors: errors) { _ -> String in return "--fi" }, addFeed: scheduler.mock(textValues, errors: errors) { _ -> String in return "--ft" } ) } }
let booleans = ["t" : true, "f" : false]
// let events = ["x" : ()] // let errors = [ "#1" : NSError(domain: "Some unknown error maybe", code: -1, userInfo: nil), ] // let textValues = [ "ft" : "feed", "e" : "" ] // // , , :-) let feeds = [ "fs" : GetFeedsResponse() ] let feedInfo = [ "fi" : GetFeedInfoResponse() ] let feedArray = [ "fa" : [Feed]() ] let feed = [ "f" : Feed(createdTime: "1", feedId: "1") ]
let ( feedTextEvents, buttonTapEvents, expectedValidatedTextEvents, expectedSendFeedEnabledEvents ) = ( scheduler.parseEventsAndTimes("e----------ft------", values: textValues).first!, scheduler.parseEventsAndTimes("-----------------x-", values: events).first!, scheduler.parseEventsAndTimes("f----------t-------", values: booleans).first!, scheduler.parseEventsAndTimes("f----------t-------", values: booleans).first! )
let wireframe = MockWireframe() let viewModel = AddPostViewModel( input: ( feedText: scheduler.createHotObservable(feedTextEvents).asObservable(), sendButton: scheduler.createHotObservable(buttonTapEvents).asObservable() ), dependency: ( API: mock, wireframe: wireframe ) ) // run experiment let recordedSendFeedEnabled = scheduler.record(viewModel.sendEnabled) let recordedValidatedTextEvents = scheduler.record(viewModel.validatedText) scheduler.start() // validate XCTAssertEqual(recordedValidatedTextEvents.events, expectedValidatedTextEvents) XCTAssertEqual(recordedSendFeedEnabled.events, expectedSendFeedEnabledEvents)
Source: https://habr.com/ru/post/304866/
All Articles