From d3271a040585b65ef837074cdf3cb6884aa184d6 Mon Sep 17 00:00:00 2001 From: gramps Date: Mon, 31 Aug 2026 08:59:38 -0700 Subject: [PATCH] =?UTF-8?q?refactor:=20split=20SocialsDialogViewModel=20un?= =?UTF-8?q?der=20500=20lines=20=E2=80=94=20500-limit=20Phase=203,=20Commit?= =?UTF-8?q?=20D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SocialsDialogViewModel.cs 515 -> 334. Extracted the DialogEntry record + the row-level SocialSlotViewModel (service/logo/lock/edit/validate state, computed Show* flags) into a new SocialSlotViewModel.cs partial. The dialog VM keeps the sign-in gate, validation orchestration, and commit. DialogEntry stays public in the same namespace. Zero behavior change; build 0 warnings; 246 pass, only the 2 known failures. Docs: ViewModels/index.md Phase 3 tracker updated in same commit. --- ViewModels/SocialSlotViewModel.cs | 183 +++++++++++++++++++++++++++ ViewModels/SocialsDialogViewModel.cs | 181 -------------------------- ViewModels/index.md | 1 + 3 files changed, 184 insertions(+), 181 deletions(-) create mode 100644 ViewModels/SocialSlotViewModel.cs diff --git a/ViewModels/SocialSlotViewModel.cs b/ViewModels/SocialSlotViewModel.cs new file mode 100644 index 0000000..2b7aecf --- /dev/null +++ b/ViewModels/SocialSlotViewModel.cs @@ -0,0 +1,183 @@ +using System.ComponentModel; +using ytLive.Helpers; +using ytLive.Models; +using ytLive.ViewModels; + +namespace ytLive.ViewModels; +public sealed record DialogEntry(SocialService Service, string Handle, string ProfileUrl, string? FediverseSoftware = null); + +/// +/// One of the six fixed dialog rows. Row 0 is always YouTube (signed-in account +/// or a sign-in prompt); rows 1-5 hold validated entries, an empty slot, or — on +/// the free tier — a locked "Premium" slot. Rows are a positional projection of +/// the dialog's working list, so deleting an entry makes the ones above advance up. +/// +public sealed class SocialSlotViewModel : ViewModelBase +{ + public int Index { get; } + public bool IsYoutube => Index == 0; + + private SocialService _service = SocialService.Link; + public SocialService Service + { + get => _service; + set { if (SetProperty(ref _service, value)) OnPropertyChanged(nameof(LogoData)); } + } + + public string LogoData => Service == SocialService.Fediverse + ? SocialServiceIcons.LogoDataForFediverse(FediverseSoftware) + : SocialServiceIcons.LogoDataFor(Service); + public string LockedIconData => SocialServiceIcons.LockedIconData; + public string DoNotIconData => SocialServiceIcons.DoNotIconData; + + private bool _isLocked; + public bool IsLocked + { + get => _isLocked; + set + { + if (SetProperty(ref _isLocked, value)) + { + OnPropertyChanged(nameof(ShowAddButton)); + OnPropertyChanged(nameof(ShowDoNot)); + OnPropertyChanged(nameof(DisplayText)); + } + } + } + + private bool _isFilled; + public bool IsFilled + { + get => _isFilled; + set + { + if (SetProperty(ref _isFilled, value)) + { + OnPropertyChanged(nameof(ShowEditButton)); + OnPropertyChanged(nameof(ShowDeleteButton)); + OnPropertyChanged(nameof(ShowAddButton)); + OnPropertyChanged(nameof(ShowDoNot)); + OnPropertyChanged(nameof(DisplayText)); + } + } + } + + private bool _isSignIn; + public bool IsSignIn + { + get => _isSignIn; + set + { + if (SetProperty(ref _isSignIn, value)) + { + OnPropertyChanged(nameof(ShowSignInButton)); + OnPropertyChanged(nameof(ShowDeleteButton)); + OnPropertyChanged(nameof(ShowLogo)); + OnPropertyChanged(nameof(DisplayText)); + } + } + } + + private bool _isEditing; + public bool IsEditing + { + get => _isEditing; + set + { + if (SetProperty(ref _isEditing, value)) + { + OnPropertyChanged(nameof(ShowEditBox)); + OnPropertyChanged(nameof(ShowDisplay)); + OnPropertyChanged(nameof(ShowEditButton)); + OnPropertyChanged(nameof(ShowDeleteButton)); + OnPropertyChanged(nameof(ShowAddButton)); + OnPropertyChanged(nameof(ShowDoNot)); + } + } + } + + private bool _isValidating; + public bool IsValidating + { + get => _isValidating; + set + { + if (SetProperty(ref _isValidating, value)) + { + OnPropertyChanged(nameof(ShowBusy)); + OnPropertyChanged(nameof(ShowDoNot)); + } + } + } + + private string _handle = string.Empty; + public string Handle + { + get => _handle; + set + { + if (SetProperty(ref _handle, value)) + OnPropertyChanged(nameof(DisplayText)); + } + } + + private string? _fediverseSoftware; + public string? FediverseSoftware + { + get => _fediverseSoftware; + set + { + if (SetProperty(ref _fediverseSoftware, value)) + OnPropertyChanged(nameof(LogoData)); + } + } + + public string ProfileUrl { get; set; } = string.Empty; + + private string? _error; + public string? Error + { + get => _error; + set + { + if (SetProperty(ref _error, value)) + { + OnPropertyChanged(nameof(HasError)); + OnPropertyChanged(nameof(ShowError)); + OnPropertyChanged(nameof(ShowDoNot)); + } + } + } + + private string _editText = string.Empty; + public string EditText + { + get => _editText; + set => SetProperty(ref _editText, value); + } + + /// The last text submitted for validation (used to skip re-validating + /// identical input — e.g. a LostFocus firing as the user clicks Cancel). + public string? LastValidatedInput { get; set; } + + public string DisplayText => + IsYoutube + ? (IsSignIn ? "Sign in to YouTube" : Handle) + : IsLocked ? "Unlock with Premium" + : IsFilled ? Handle + : "No social yet"; + + public bool HasError => !string.IsNullOrEmpty(Error); + public bool ShowError => HasError; + public bool ShowLogo => IsYoutube ? !IsSignIn : IsFilled; + public bool ShowBusy => IsValidating; + public bool ShowEditBox => IsEditing; + public bool ShowDisplay => !IsEditing && !IsValidating; + public bool ShowSignInButton => IsYoutube && IsSignIn && !IsValidating; + public bool ShowAddButton => !IsYoutube && !IsLocked && !IsFilled && !IsEditing && !IsValidating; + public bool ShowEditButton => !IsYoutube && IsFilled && !IsEditing && !IsValidating; + public bool ShowDeleteButton => (IsFilled || IsYoutube) && !IsEditing && !IsValidating; + public bool ShowDoNot => !IsYoutube && !IsLocked && (!IsFilled || HasError || IsValidating); + + public SocialSlotViewModel(int index) => Index = index; +} diff --git a/ViewModels/SocialsDialogViewModel.cs b/ViewModels/SocialsDialogViewModel.cs index 08864f2..3903ec5 100644 --- a/ViewModels/SocialsDialogViewModel.cs +++ b/ViewModels/SocialsDialogViewModel.cs @@ -8,187 +8,6 @@ using ytLive.Services; namespace ytLive.ViewModels; -/// -/// A validated social entry in the dialog's working copy (non-YouTube slots). -/// -public sealed record DialogEntry(SocialService Service, string Handle, string ProfileUrl, string? FediverseSoftware = null); - -/// -/// One of the six fixed dialog rows. Row 0 is always YouTube (signed-in account -/// or a sign-in prompt); rows 1-5 hold validated entries, an empty slot, or — on -/// the free tier — a locked "Premium" slot. Rows are a positional projection of -/// the dialog's working list, so deleting an entry makes the ones above advance up. -/// -public sealed class SocialSlotViewModel : ViewModelBase -{ - public int Index { get; } - public bool IsYoutube => Index == 0; - - private SocialService _service = SocialService.Link; - public SocialService Service - { - get => _service; - set { if (SetProperty(ref _service, value)) OnPropertyChanged(nameof(LogoData)); } - } - - public string LogoData => Service == SocialService.Fediverse - ? SocialServiceIcons.LogoDataForFediverse(FediverseSoftware) - : SocialServiceIcons.LogoDataFor(Service); - public string LockedIconData => SocialServiceIcons.LockedIconData; - public string DoNotIconData => SocialServiceIcons.DoNotIconData; - - private bool _isLocked; - public bool IsLocked - { - get => _isLocked; - set - { - if (SetProperty(ref _isLocked, value)) - { - OnPropertyChanged(nameof(ShowAddButton)); - OnPropertyChanged(nameof(ShowDoNot)); - OnPropertyChanged(nameof(DisplayText)); - } - } - } - - private bool _isFilled; - public bool IsFilled - { - get => _isFilled; - set - { - if (SetProperty(ref _isFilled, value)) - { - OnPropertyChanged(nameof(ShowEditButton)); - OnPropertyChanged(nameof(ShowDeleteButton)); - OnPropertyChanged(nameof(ShowAddButton)); - OnPropertyChanged(nameof(ShowDoNot)); - OnPropertyChanged(nameof(DisplayText)); - } - } - } - - private bool _isSignIn; - public bool IsSignIn - { - get => _isSignIn; - set - { - if (SetProperty(ref _isSignIn, value)) - { - OnPropertyChanged(nameof(ShowSignInButton)); - OnPropertyChanged(nameof(ShowDeleteButton)); - OnPropertyChanged(nameof(ShowLogo)); - OnPropertyChanged(nameof(DisplayText)); - } - } - } - - private bool _isEditing; - public bool IsEditing - { - get => _isEditing; - set - { - if (SetProperty(ref _isEditing, value)) - { - OnPropertyChanged(nameof(ShowEditBox)); - OnPropertyChanged(nameof(ShowDisplay)); - OnPropertyChanged(nameof(ShowEditButton)); - OnPropertyChanged(nameof(ShowDeleteButton)); - OnPropertyChanged(nameof(ShowAddButton)); - OnPropertyChanged(nameof(ShowDoNot)); - } - } - } - - private bool _isValidating; - public bool IsValidating - { - get => _isValidating; - set - { - if (SetProperty(ref _isValidating, value)) - { - OnPropertyChanged(nameof(ShowBusy)); - OnPropertyChanged(nameof(ShowDoNot)); - } - } - } - - private string _handle = string.Empty; - public string Handle - { - get => _handle; - set - { - if (SetProperty(ref _handle, value)) - OnPropertyChanged(nameof(DisplayText)); - } - } - - private string? _fediverseSoftware; - public string? FediverseSoftware - { - get => _fediverseSoftware; - set - { - if (SetProperty(ref _fediverseSoftware, value)) - OnPropertyChanged(nameof(LogoData)); - } - } - - public string ProfileUrl { get; set; } = string.Empty; - - private string? _error; - public string? Error - { - get => _error; - set - { - if (SetProperty(ref _error, value)) - { - OnPropertyChanged(nameof(HasError)); - OnPropertyChanged(nameof(ShowError)); - OnPropertyChanged(nameof(ShowDoNot)); - } - } - } - - private string _editText = string.Empty; - public string EditText - { - get => _editText; - set => SetProperty(ref _editText, value); - } - - /// The last text submitted for validation (used to skip re-validating - /// identical input — e.g. a LostFocus firing as the user clicks Cancel). - public string? LastValidatedInput { get; set; } - - public string DisplayText => - IsYoutube - ? (IsSignIn ? "Sign in to YouTube" : Handle) - : IsLocked ? "Unlock with Premium" - : IsFilled ? Handle - : "No social yet"; - - public bool HasError => !string.IsNullOrEmpty(Error); - public bool ShowError => HasError; - public bool ShowLogo => IsYoutube ? !IsSignIn : IsFilled; - public bool ShowBusy => IsValidating; - public bool ShowEditBox => IsEditing; - public bool ShowDisplay => !IsEditing && !IsValidating; - public bool ShowSignInButton => IsYoutube && IsSignIn && !IsValidating; - public bool ShowAddButton => !IsYoutube && !IsLocked && !IsFilled && !IsEditing && !IsValidating; - public bool ShowEditButton => !IsYoutube && IsFilled && !IsEditing && !IsValidating; - public bool ShowDeleteButton => (IsFilled || IsYoutube) && !IsEditing && !IsValidating; - public bool ShowDoNot => !IsYoutube && !IsLocked && (!IsFilled || HasError || IsValidating); - - public SocialSlotViewModel(int index) => Index = index; -} - /// /// View model for the Social Media Site Promotion dialog. Owns the working copy /// of the social bar config: the six fixed slots, the sign-in gate, per-row diff --git a/ViewModels/index.md b/ViewModels/index.md index 4c69042..cce9911 100644 --- a/ViewModels/index.md +++ b/ViewModels/index.md @@ -69,5 +69,6 @@ commit, tag `refactor-commit-N`, no per-commit push). - [x] **Commit A · `refactor-commit-A`** — **core** → `MainViewModel.cs` 758 → **495**. Moved source add/remove/image block to new **`MainViewModel.Sources.cs`** (234 lines: `AddSource`, `NextSourceName`, `AddImage`, `BuildImageCandidates`, `PickImageBytes`, `AddAsset`, `AddImageSource`, `AddReusedImage`, `RemoveElement`) and WebView2 hosting (`RegisterLoadedWebSources`, `InitWebView2`, `OnWebView2PreviewBitmapChanged`) to new **`MainViewModel.Web.cs`**. Pruned now-dead usings (`Microsoft.Win32`, `NAudio.CoreAudioApi`, `System.Windows.Media.Imaging`, `Collections.ObjectModel/Specialized`). Pending: Streaming, Background, SocialsDialogViewModel, LayoutStore. - [x] **Commit B · `refactor-commit-B`** — **Streaming** → `MainViewModel.Streaming.cs` 789 → **330** + new **`MainViewModel.Streaming.Operations.cs`** (459 lines). Moved the go-live/record/health operation bodies (`StartSession`, `BeginRecordOnly`, `BeginGoLive`, `StartRecordFile`, `PrepareAndStartLiveAsync`, `PollHealthAsync`/`OnHealthPollTick`/`ApplyHealthIssue`, `StopStream`, `FinalizeRecordingAsync`, `UniquePath`, `ChooseRecordFolder`, `ResetRecordFolder`, `DefaultRecordFolder`, `OnFramePumpFailed`, `OnFramePumpHealthUpdated`, `ApplyHealth`, `ResetHealth`, `BuildEncoderOptions`) into the Operations partial; Streaming.cs keeps state + quality/resolution tiers + session timer + command declarations. Pruned dead usings both files. Pending: Background, SocialsDialogViewModel, LayoutStore. - [x] **Commit C · `refactor-commit-C`** — **Background** → `MainViewModel.Background.cs` 567 → **418** + new **`MainViewModel.Background.Model.cs`** (163 lines). Moved the static scene-model helpers (`LoadBackgroundImage`, `CreatePlaceholderSnapshot`, `EnsureBackground`, `CreateBackground`, `NormalizeBackgrounds`, `AllBackgrounds`, `ResolveAutoCaptureKey`, `MonitorKeyPrefix`) into the Model partial; Background.cs keeps capture/live state + operations (`UpdateActiveBackground`, `UpdateBackgroundImage`, `RefreshSnapshotsAsync`, `ReacquireScreenCaptures`, `OnScreenPreviewBitmapChanged`, `OnFullscreenMonitorChanged`, `RefreshBackgroundAutoCapture`, `BrowseBackground`, `ClearBackgroundCaptureAsync`, `RedesignateBackgroundAsync`, `ChangeBackgroundCaptureAsync`, `SetBackgroundCapture`, `DefaultBackgroundAsset`, `HealBackgrounds`, `StampDefaultBackgroundAsset`). Pending: SocialsDialogViewModel, LayoutStore. +- [x] **Commit D · `refactor-commit-D`** — **SocialsDialog** → `SocialsDialogViewModel.cs` 515 → **334** + new **`SocialSlotViewModel.cs`** (183 lines). Moved the `DialogEntry` record + the row-level `SocialSlotViewModel` (six-fixed-slot row VM: service/logo/lock/edit/validate state + computed `Show*` flags) into its own file; `SocialsDialogViewModel.cs` keeps the dialog VM (sign-in gate, validation orchestration, commit). `DialogEntry` stays `public` in the same namespace so both files see it. Pending: LayoutStore. The partial `.cs` files land next to `MainViewModel.cs` in this folder as the split proceeds; each partial carries its own `using`s and re-declares nothing from core. \ No newline at end of file