public IObservable <IRxn> Process(StartStopRecording @event) { return(RxObservable.Create <IRxn>(() => { if (_tape != null) { OnVerbose("Tape {0} goes for {1}".FormatWith(_tape.Name, _tape.Source.Duration)); _recording.Dispose(); _recording.Clear(); _tape.Source.Dispose(); _tape = null; return; } _tape = _tapeRepository.GetOrCreate(@event.TapeName); _appNav.CurrentView.Select(view => _automator.AutomateUserActions(view.Page, view.Model, Input, Input.OnNext)) .Switch() .Until(OnError) .DisposedBy(_recording); _recorder.Record(_tape, Input.Where(e => !e.GetType().ImplementsInterface <INotRecorded>())).DisposedBy(_recording); OnVerbose("Recording {0} has started".FormatWith(@event.TapeName)); })); }
public IObservable <Unit> ShowRootPage(Page page, bool hasNavbar = false) { return(RxObservable.Create(() => { OnInformation("Swapping>> {0}", page.GetType()); PushRoot(page, (IRxnPageModel)page.BindingContext, hasNavbar); })); }
public IObservable <IRxn> Process(UserLoggingOut @event) { return(RxObservable.Create(() => { var loginPage = _defaultPages.LoginPage(); PushRoot(loginPage, (IRxnPageModel)loginPage.BindingContext); }) .Select(_ => (IRxn)null)); }
public IObservable <IRxn> Process(UserLoggedIn @event) { return(RxObservable.Create(() => { var mainPage = _defaultPages.MainPage(); PushRoot(mainPage, (IRxnPageModel)mainPage.BindingContext, _defaultPages.MainPageHasNav); }) .Select(_ => (IRxn)null)); }
public IObservable <IRxn> Process(Question @event) { return(RxObservable.Create(() => { _inFlight.Set(@event.Ask.Id, @event); return @event.Ask; })); }
/// <summary> /// page life-cycle -> Currently the system doesnt dispose/hide the previous page until its "hidden" or popped /// </summary> /// <param name="navTo"></param> /// <returns></returns> public IObservable <IRxn> Process(NavigationAction navTo) { return(RxObservable.Create <IRxn>(o => { if (navTo.IsPushing || navTo.IsSwapping) { OnVerbose("Resolving next page: {0}", navTo.PageModelType.Name); var page = ResolvePageFor(navTo.PageType, navTo.PageModelType, navTo.Cfg); var nextPageModel = GetPageModel(page); if (!navTo.IsSwapping) { Push(page, nextPageModel); return navTo.IsModal ? ShowPageModal(page).FinallyR(() => o.OnCompleted()).Subscribe() : ShowPage(page).FinallyR(() => o.OnCompleted()).Subscribe(); } else { return ShowRootPage(page, navTo.ShowNav).FinallyR(() => o.OnCompleted()).Subscribe(); } } else if (navTo.IsPoppingTo) { OnVerbose("Disposing from: {0} to {1}", _appNav.Current, navTo.PageModelType); var pagesToPop = PopTo(navTo.PageModelType); return navTo.IsModal ? HideManyPagesModal(pagesToPop).FinallyR(() => o.OnCompleted()).Subscribe() : HideManyPages(pagesToPop).FinallyR(() => o.OnCompleted()).Subscribe(); } else //popping { OnVerbose("Disposing: {0}", _appNav.Current); return navTo.IsModal ? HideCurrentPageModal().FinallyR(() => o.OnCompleted()).Subscribe() : HideCurrentPage().FinallyR(() => o.OnCompleted()).Subscribe(); //pages are implicitly pop()'d when OnPopped event is called as it is removed from the nav stack /*return (navTo.IsModal ? HideCurrentPageModal() : HideCurrentPage()) * .DoWhile(() => navTo.PageModelType != null && _appNav.Current.Model.GetType() != navTo.PageModelType) * .FinallyR(() => o.OnCompleted()) * .Subscribe();*/ } }) .Finally(() => OnVerbose("Finished navigation")) .Catch <IRxn, Exception>(e => { OnError(e); return Observable.Empty <IRxn>(); })); }
public IObservable <IRxn> Process(EventPublishingOsBridge.AppResumed @event) { return(RxObservable.Create <IRxn>(() => { if (_appNav.Current != null && _appNav.Current.Model != null) { OnInformation("Resuming app @ {0}", _appNav.Current); RxnApp.BackgroundScheduler.Run(() => this.TryCatch(() => _appNav.Current.Model.BackgroundShow())); } else { OnWarning("No current page set, cannot resume page, this is probably means an error has occoured!"); } })); }
public IObservable <IRxn> Process(CommandResult @event) { return(RxObservable.Create(() => { if (!_inFlight.Contains(@event.InResponseTo)) { return null; } var answer = _inFlight.Get(@event.InResponseTo); _inFlight.Remove(@event.InResponseTo); return @event.Result == CmdResult.Success ? answer.OnSuccess : answer.OnFailure; })); }
public IObservable <IRxn> Process(PlayRecording @event) { return(RxObservable.Create <IRxn>(o => { //todo: fix way inital page of recording is shown so playback is consistant o.OnCompleted(); return Disposable.Empty; }) .Do(__ => { CurrentThreadScheduler.Instance.Run(() => { var tape = _tapeRepository.GetOrCreate("{0}".FormatWith(@event.Name)); var player = _recorder.Play(tape, new PlaybackSettings() { Speed = 1, TickSpeed = 1 }); OnVerbose("Playing {0} @ {1}", tape.Name, tape.Source.Duration); var stopPositionDebug = player.Position.Do(p => OnVerbose("Current: {0}", p)).Until(OnError); //generate the UI automation events only while playing var automator = _appNav.CurrentView .Do(_ => OnWarning("New Page {0}", _.Model.GetType().Name)) .Select(view => _automator.AutomateUserActions(view.Page, view.Model, Input, _publish).Do(isReady => player.IsPaused.OnNext(!isReady))) .Switch() .Until(OnError); var pageTransition = this.OnReactionTo <NavigationAction>() .Do(_ => OnWarning("Pausing")) .Do(_ => player.IsPaused.OnNext(true)) .Until(OnError); var recording = player.Stream.Select(e => FilterPlayback(e)) .Where(e => e != null) .FinallyR(() => { automator.Dispose(); pageTransition.Dispose(); }) .Do(_ => OnWarning("PLAYING>> {0}-{1}", _.GetType().Name, _.ToJson())) .Subscribe(p => _publish(p), error => OnError(error)); }); })); }
public IObservable <bool> AutomateUserActions(Page page, RxnPageModel model, IObservable <IRxn> actions, Action <IRxn> publish) { return(RxObservable.DfrCreate <bool>(o => { var state = new InterceptState(model, actions, publish); var resources = new CompositeDisposable(new DisposableAction(() => { Debug.WriteLine("<<<<Disposing of {0}>>>>>", model.GetType().Name); })); if (page is ContentPage) { Observable.FromEventPattern(e => page.LayoutChanged += e, e => page.LayoutChanged -= e) .Select(_ => new Unit()) .StartWith(new Unit()) .BufferFirstLast(TimeSpan.FromMilliseconds(70), false) .Do(_ => o.OnNext(false)) .Do(_ => _dialog.ShowLoading("Loading...")) .Do(_ => Debug.WriteLine("Intercepting>>> {0}", model.GetType().Name)) .Select(_ => { return Observable.Defer(() => RxObservable.Create(() => { var timer = Stopwatch.StartNew(); var r = FindAllCommandHolder(((ContentPage)page).Content as IViewContainer <View>, state); timer.Stop(); Debug.WriteLine("Interception took: {0}", timer.Elapsed); if (r != null) { resources.Add(r); } })); }) .Switch() .Do(_ => _dialog.HideLoading()) .FinallyR(() => _dialog.HideLoading()) .Subscribe(_ => o.OnNext(true)) .DisposedBy(resources); return resources; } ; return Disposable.Empty; })); }
/// <summary> /// Transforms a chatty sequence into a smooth one by ignoring the values /// that occour during bursts of chattyness, only propergating the first /// and last values during this time, ignoring the rest. The timer is only activated when values /// are produced /// </summary> /// <typeparam name="T"></typeparam> /// <param name="source"></param> /// <param name="ignorePeriod"></param> /// <returns></returns> public static IObservable <T> BufferFirstLast <T>(this IObservable <T> source, TimeSpan ignorePeriod, bool notifyFirst = true, bool notifyLast = true, IScheduler ignoreScheduler = null) { return(Observable.Defer <T>(() => RxObservable.Create <T>(o => { T last = default(T); IDisposable timer = null; Action startTimer = () => timer = Observable.Timer(ignorePeriod, ignoreScheduler ?? Scheduler.Default) .Subscribe(_ => { if (notifyLast) { o.OnNext(last); } timer = null; }); var sub = source.Subscribe(t => { last = t; if (timer != null) { timer.Dispose(); startTimer(); return; } if (notifyFirst) { o.OnNext(last); } startTimer(); }, o.OnError, o.OnCompleted); return sub; }))); }
public IObservable <Unit> Handle(TMessage message) { return(RxObservable.Create(() => HandleCore(message).Wait())); }
public IObservable <IRxn> Process(DeleteRecording @event) { return(RxObservable.Create <IRxn>(() => _tapeRepository.Delete(@event.Name))); }
public static BufferedObservable <T> BufferFirstLastDistinct <T>(this IObservable <T> source, Func <T, object> distinctSelector, TimeSpan ignorePeriod, bool notifyFirst = true, bool notifyLast = true, IScheduler ignoreScheduler = null) { Action doFlush = null; Action flushBuffer = () => { if (doFlush != null) { doFlush(); } }; //omg what a hack but meh, it works! return(new BufferedObservable <T>(Observable.Defer <T>(() => RxObservable.Create <T>(o => { T last = default(T); object distinct = null; IDisposable timer = null; Action <T> lastAction = (t) => { if (timer == null) { return; } timer = null; if (notifyLast) { o.OnNext(t); } }; var singleThread = new object(); //set out flush operation now. doFlush = () => lastAction(last); Action <T> startBufferTimer = (t) => { timer = Observable.Timer(ignorePeriod, ignoreScheduler ?? Scheduler.Default) .Subscribe(_ => { lock (singleThread) { lastAction(t); } }); }; return source.Subscribe(t => { lock (singleThread) { var latestDistinct = distinctSelector(t); if (timer != null) { if (distinct != null && !distinct.Equals(latestDistinct)) { timer.Dispose(); lastAction(last); } else { timer.Dispose(); startBufferTimer(t); return; } } distinct = latestDistinct; last = t; if (notifyFirst) { o.OnNext(t); } startBufferTimer(t); } }, o.OnError, o.OnCompleted); })), flushBuffer)); }