/// <summary> /// Data binding method. /// </summary> /// <typeparam name="TView">View type</typeparam> /// <typeparam name="TProperty">Property type</typeparam> /// <param name="self">View</param> /// <param name="propertySelector">Target property selector</param> /// <param name="source">Source property</param> /// <param name="updateSourceTrigger">Update source trigger</param> /// <returns>Data binding token</returns> public static IDisposable SetBinding <TView, TProperty>( this TView self, Expression <Func <TView, TProperty> > propertySelector, IReactiveProperty <TProperty> source, Func <TView, IObservable <Unit> > updateSourceTrigger = null) where TView : View { var d = new CompositeDisposable(); var isUpdating = false; var setter = AccessorCache <TView> .LookupSet(propertySelector, out var propertyName); source .Where(_ => !isUpdating) .Subscribe(x => setter(self, x)) .AddTo(d); if (updateSourceTrigger != null) { var getter = AccessorCache <TView> .LookupGet(propertySelector, out propertyName); updateSourceTrigger(self).Subscribe(_ => { isUpdating = true; try { source.Value = getter(self); } finally { isUpdating = false; } }).AddTo(d); } return(d); }
public static IDisposable BindTwoWayTo <TSource, TTarget>(this IReactiveProperty <TSource> This, IReactiveProperty <TTarget> target) { if (This == null || target == null) { return(Disposable.Empty); } bool isUpdating = false; return(new CompositeDisposable( This .Where(_ => !isUpdating) .Subscribe(x => { isUpdating = true; target.Value = (TTarget)(object)x; isUpdating = false; }), target .Where(_ => !isUpdating) .Subscribe(x => { isUpdating = true; This.Value = (TSource)(object)x; isUpdating = false; }))); }
protected override void Awake() { base.Awake(); Debug.Log($"DialogueConversationController: Loaded {m_Sprites.Length} sprite(s)."); // When a text phase event is processed from the dialogue system and it didn't have choices, this will post // a delayed dialogue continuation to make it look like the other person was typing. Posts the length // of the output for the purposes of making an appropriate delay. var lastChoice = -1; CompositeDisposable subscriptions = null; m_ChatBoxController.choices .Subscribe(choice => { lastChoice = choice.index; }) .AddTo(this); profile .Where(item => item != null) .Subscribe(item => { m_DatingProfileView.data = item; m_ConversationController.conversantName = profile.Value.name; }) .AddTo(this); selectedDialogue .StartWith((DialogueItem)null) .Pairwise() .Subscribe(dialogues => { var oldDialogue = dialogues.Previous; var newDialogue = dialogues.Current; if (oldDialogue == newDialogue || newDialogue == null) { return; } subscriptions?.Dispose(); subscriptions = ResumeStory(newDialogue, oldDialogue); AnalyticsEvent.Custom("chat_with", new Dictionary <string, object>() { { "on_profile", profile.Value?.name } }); var eventHitBuilder1 = new EventHitBuilder() .SetEventCategory("conversation") .SetEventAction("chat_with") .SetEventLabel(profile.Value?.name); GoogleAnalyticsV4.getInstance().LogEvent(eventHitBuilder1); }) .AddTo(this); }
public FFmpegDownloadViewModel(FFmpegSettings FFmpegSettings, FFmpegDownloadModel DownloadModel, IFFmpegViewsProvider FFmpegViewsProvider, IMessageProvider MessageProvider) { this.FFmpegSettings = FFmpegSettings; _downloadModel = DownloadModel; _messageProvider = MessageProvider; StartCommand = _downloaderProgress .Select(M => M.State) .Select(M => M == FFmpegDownloaderState.Ready) .ToReactiveCommand() .WithSubscribe(async() => { var progress = new Progress <FFmpegDownloaderProgress>(M => _downloaderProgress.Value = M); _downloadTask = DownloadModel.Start(progress, _cancellationTokenSource.Token); var result = await _downloadTask; AfterDownload?.Invoke(result); }); CanCancel = _downloaderProgress .Select(M => M.State) .Select(M => M == FFmpegDownloaderState.Downloading) .ToReadOnlyReactivePropertySlim(); SelectFolderCommand = _downloaderProgress .Select(M => M.State) .Select(M => M == FFmpegDownloaderState.Ready) .ToReactiveCommand() .WithSubscribe(FFmpegViewsProvider.PickFolder); OpenFolderCommand = new ReactiveCommand() .WithSubscribe(() => { var path = FFmpegSettings.GetFolderPath(); if (Directory.Exists(path)) { Process.Start(path); } }); Status = _downloaderProgress .Select(M => { switch (M.State) { case FFmpegDownloaderState.Error: return(M.ErrorMessage); case FFmpegDownloaderState.Downloading: return($"{FFmpegDownloaderState.Downloading} ({M.DownloadProgress}%)"); default: return(M.State.ToString()); } }) .ToReadOnlyReactivePropertySlim(); Progress = _downloaderProgress .Where(M => M.State == FFmpegDownloaderState.Downloading) .Select(M => M.DownloadProgress) .ToReadOnlyReactivePropertySlim(); Progress.Subscribe(M => ProgressChanged?.Invoke(M)); InProgress = _downloaderProgress .Select(M => M.State) .Select(M => M == FFmpegDownloaderState.Downloading || M == FFmpegDownloaderState.Extracting) .ToReadOnlyReactivePropertySlim(); IsDone = _downloaderProgress .Select(M => M.State) .Select(M => M == FFmpegDownloaderState.Done || M == FFmpegDownloaderState.Cancelled || M == FFmpegDownloaderState.Error) .ToReadOnlyReactivePropertySlim(); }