/// <summary> /// コンストラクタ /// </summary> /// <param name="settings"></param> /// <param name="logger"></param> public RecipeDetailViewModel(ISettings settings, ILogger logger) { // Property // 作成したレシピ this.DecidedRecipe = this.RecipeViewModel .CombineLatest( // ダウンロード完了後に値をセットする this.IsDownaloding, (recipe, isDownloading) => isDownloading ? null : recipe) .ToReactiveProperty() .AddTo(this.CompositeDisposable); this.TargetUrl = new ReactiveProperty <string>() .SetValidateNotifyError(x => x != null ? null : "必須") .SetValidateNotifyError(x => Creator.CanCreateFromUrl(x) ? null : "対応サイトのURLではありません。") .AddTo(this.CompositeDisposable); this.Sites.Value = Creator.RecipeSitePlugins.Select(x => new Site { Logo = x.LogoUrl, TargetUrlPattern = x.TargetUrlPattern, IsValid = this.TargetUrl.Select(url => url != null && (x.TargetUrlPattern?.IsMatch(url) ?? false)).ToReactiveProperty() }).ToArray(); this.RecipeView = this.RecipeViewModel .CombineLatest(this.IsEditing, (vm, isEditing) => { if (isEditing) { return(Creator.CreateRecipeEditorViewInstance(settings, logger, vm)); } else { return(Creator.CreateRecipeViewerViewInstance(settings, logger, vm)); } }) .ToReactiveProperty() .AddTo(this.CompositeDisposable); // Command // レシピダウンロードコマンド this.DownloadCommand = new[] { this.TargetUrl.ObserveHasErrors.Select(x => !x), this.IsDownaloding.Select(x => !x), this.RecipeViewModel.Select(x => x == null) }.CombineLatestValuesAreAllTrue() .ToReactiveCommand() .AddTo(this.CompositeDisposable); this.DownloadCommand.Subscribe(url => { this.IsDownaloding.Value = true; var vm = Creator.CreateRecipeViewModelInstanceFromUrl(settings, logger, this.TargetUrl.Value); this.RecipeViewModel.Value = vm; vm.Url.Value = new Uri(this.TargetUrl.Value); vm.Recipe.FailedNotification.Where(x => x.Behavior == Composition.Behavior.Download).Subscribe(x => { this.RecipeViewModel.Value = null; this.IsDownaloding.Value = false; }); vm.Recipe.CompletedNotification.Where(x => x.Behavior == Composition.Behavior.Download).Subscribe(x => { this.IsDownaloding.Value = false; }); vm.DownloadCommand.Execute(this.Messenger); }).AddTo(this.CompositeDisposable); // レシピ登録コマンド this.RegisterRecipeCommand = new[] { this.IsDownaloding.Select(x => !x), this.RecipeViewModel.Select(x => x != null), this.IsEditing.Select(x => !x) }.CombineLatestValuesAreAllTrue() .ToReactiveCommand() .AddTo(this.CompositeDisposable); this.RegisterRecipeCommand.ObserveOnDispatcher(DispatcherPriority.Background).Subscribe(_ => { this.IsBusy.Value = true; this.RecipeViewModel.Value.RegisterRecipeCommand.Execute(this.Messenger); this._registerCompleted.Next(); this.Messenger.Raise(new WindowActionMessage(WindowAction.Close, "Close")); }).AddTo(this.CompositeDisposable); // レシピ破棄コマンド this.RevertRecipeCommand.ObserveOnDispatcher(DispatcherPriority.Background).Subscribe(_ => { this.IsBusy.Value = true; // 変更前の状態を再読込 this.RecipeViewModel.Value.LoadRecipeCommand.Execute(this.Messenger); this.Messenger.Raise(new WindowActionMessage(WindowAction.Close, "Close")); }).AddTo(this.CompositeDisposable); // レシピ編集モード切り替えコマンド this.ChangeModeToEditorCommand = new[] { this.IsDownaloding.Select(x => !x), this.RecipeViewModel.Select(x => x != null), this.IsEditing.Select(x => !x) }.CombineLatestValuesAreAllTrue() .ToReactiveCommand() .AddTo(this.CompositeDisposable); this.ChangeModeToEditorCommand.Subscribe(() => { this.IsEditing.Value = true; }).AddTo(this.CompositeDisposable); // 編集終了コマンド this.CompleteEditCommand = new[] { this.IsDownaloding.Select(x => !x), this.RecipeViewModel.Select(x => x != null), this.IsEditing }.CombineLatestValuesAreAllTrue() .ToReactiveCommand() .AddTo(this.CompositeDisposable); this.CompleteEditCommand.Subscribe(() => { this.IsEditing.Value = false; }).AddTo(this.CompositeDisposable); }