Files
Exterrata 9bb4f85802 CVR Manager 1.0.0
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 02:46:35 -04:00

628 lines
57 KiB
XML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:CVRManager.ViewModels"
xmlns:m="using:CVRManager.Models"
xmlns:v="using:CVRManager.Views"
x:Class="CVRManager.Views.MainWindow"
Icon="/Assets/app.ico" Title="CVR Manager" Width="1240" Height="820" MinWidth="1000" MinHeight="620">
<Grid>
<DockPanel>
<Border DockPanel.Dock="Top" Background="{DynamicResource SidebarBg}" BorderBrush="{DynamicResource CardBorder}" BorderThickness="0,0,0,1" Padding="24,0">
<StackPanel Orientation="Horizontal" Spacing="4">
<Path Data="{StaticResource CvrMark}" Fill="{DynamicResource AccentBrush}" Stretch="Uniform" Height="17" VerticalAlignment="Center" Margin="0,0,12,0"/>
<TextBlock Text="CVR Manager" FontSize="16" FontWeight="Bold" VerticalAlignment="Center" Margin="0,0,28,0"/>
<RadioButton Classes="tab" GroupName="top" Content="Installs" IsChecked="{Binding IsInstallsPage}"/>
<RadioButton Classes="tab" GroupName="top" Content="Sources" IsChecked="{Binding IsModsPage}"/>
<RadioButton Classes="tab" GroupName="top" Content="Gallery" IsChecked="{Binding IsGalleryPage}"/>
<RadioButton Classes="tab" GroupName="top" Content="Settings" IsChecked="{Binding IsSettingsPage}"/>
</StackPanel>
</Border>
<Panel>
<Grid ColumnDefinitions="300,*" Margin="24,20,24,20" IsVisible="{Binding IsInstallsPage}">
<DockPanel Margin="0,0,20,0">
<StackPanel DockPanel.Dock="Bottom" Spacing="8" Margin="0,8,0,0">
<Button Content="+ New install" Command="{Binding ShowNewCommand}" Classes="accent" HorizontalAlignment="Stretch" HorizontalContentAlignment="Center"/>
<Button Content="Refresh branches" Command="{Binding RefreshBranchesCommand}" Classes="ghost" HorizontalAlignment="Stretch" HorizontalContentAlignment="Center"/>
</StackPanel>
<ListBox x:Name="InstallList" Classes="cards" ItemsSource="{Binding Installs}" SelectedItem="{Binding SelectedInstall}">
<ListBox.ItemTemplate>
<DataTemplate DataType="vm:InstallVM">
<Grid ColumnDefinitions="*,Auto" Margin="16,12,12,12" ColumnSpacing="8">
<StackPanel Spacing="3">
<TextBlock Text="{Binding Name}" FontWeight="SemiBold" FontSize="15" TextTrimming="CharacterEllipsis"/>
<TextBlock Text="{Binding Branch}" Classes="dim" FontSize="12" TextTrimming="CharacterEllipsis"/>
<TextBlock Text="{Binding CardStatus}" Classes="dim" FontSize="12" IsVisible="{Binding !UpdateAvailable}"/>
<TextBlock Text="{Binding CardStatus}" Foreground="{DynamicResource WarnFg}" FontWeight="SemiBold" FontSize="12" IsVisible="{Binding UpdateAvailable}"/>
</StackPanel>
<StackPanel Grid.Column="1" Orientation="Horizontal" Spacing="6" VerticalAlignment="Stretch">
<StackPanel Spacing="4" VerticalAlignment="Center">
<Button Content="▶ Desktop" Command="{Binding LaunchDesktopCommand}" IsEnabled="{Binding HasGame}" Classes="accent" Padding="10,6" FontSize="12" HorizontalAlignment="Stretch" ToolTip.Tip="Launch in desktop mode (again, if it is already running)"/>
<Button Content="▶ VR" Command="{Binding LaunchVrCommand}" IsEnabled="{Binding HasGame}" Padding="10,6" FontSize="12" HorizontalAlignment="Stretch" ToolTip.Tip="Launch in VR mode (again, if it is already running)"/>
</StackPanel>
<Button Content="{Binding StopShortText}" Command="{Binding StopCommand}" IsVisible="{Binding IsRunning}" Classes="stop" Padding="9,6" FontSize="12" VerticalAlignment="Stretch" VerticalContentAlignment="Center" ToolTip.Tip="{Binding StopTip}"/>
</StackPanel>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DockPanel>
<Panel Grid.Column="1">
<StackPanel IsVisible="{Binding NoInstalls}" HorizontalAlignment="Center" VerticalAlignment="Center" Spacing="10">
<TextBlock Text="No installs yet" Classes="h1" HorizontalAlignment="Center"/>
</StackPanel>
<ContentControl Content="{Binding SelectedInstall}">
<ContentControl.ContentTemplate>
<DataTemplate DataType="vm:InstallVM">
<DockPanel>
<StackPanel DockPanel.Dock="Top" Spacing="12" Margin="0,0,0,12">
<Grid ColumnDefinitions="*,Auto">
<StackPanel Spacing="8">
<TextBlock Text="{Binding Name}" Classes="h1"/>
<StackPanel Orientation="Horizontal" Spacing="8">
<Border Classes="chip"><TextBlock Text="{Binding Branch}"/></Border>
<Border Classes="chip"><TextBlock Text="{Binding BuildText}"/></Border>
<Border Classes="chip good" IsVisible="{Binding UpToDate}"><TextBlock Text="Up to date"/></Border>
<Border Classes="chip warn" IsVisible="{Binding UpdateAvailable}"><TextBlock Text="{Binding UpdateChipText}"/></Border>
<Border Classes="chip" IsVisible="{Binding UpdateUnknown}"><TextBlock Text="Latest build unknown"/></Border>
<Border Classes="chip good" IsVisible="{Binding IsRunning}"><TextBlock Text="{Binding RunningText}"/></Border>
</StackPanel>
</StackPanel>
<StackPanel Grid.Column="1" Orientation="Horizontal" Spacing="8" VerticalAlignment="Top">
<ComboBox ItemsSource="{Binding Main.AccountChoices}" SelectedItem="{Binding AccountChoice}" IsVisible="{Binding Main.HasAccounts}" MinWidth="150" MinHeight="40" Padding="12,8" ToolTip.Tip="Account">
<ComboBox.ItemTemplate>
<DataTemplate DataType="m:AccountChoice"><TextBlock Text="{Binding Name}"/></DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<ComboBox ItemsSource="{Binding LaunchModes}" SelectedItem="{Binding LaunchModeChoice}" MinWidth="130" MinHeight="40" Padding="12,8">
<ComboBox.ItemTemplate>
<DataTemplate DataType="m:LaunchModeOption"><TextBlock Text="{Binding Label}"/></DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<Button Content="▶ Launch" Command="{Binding LaunchCommand}" IsEnabled="{Binding HasGame}" Classes="accent" MinWidth="132" HorizontalContentAlignment="Center" ToolTip.Tip="{Binding LaunchTip}"/>
<Button Content="{Binding StopText}" Command="{Binding StopCommand}" IsVisible="{Binding IsRunning}" Classes="stop" HorizontalContentAlignment="Center" ToolTip.Tip="{Binding StopTip}"/>
</StackPanel>
</Grid>
<StackPanel Orientation="Horizontal" Spacing="6">
<Button Content="Update" Command="{Binding UpdateCommand}"/>
<Button Content="Verify files" Command="{Binding VerifyCommand}"/>
<Button Content="Open folder" Command="{Binding OpenFolderCommand}"/>
<Button Content="Duplicate" Command="{Binding DuplicateCommand}"/>
<Button Content="Delete install" Command="{Binding DeleteCommand}" Classes="ghost danger"/>
</StackPanel>
<Border BorderBrush="{DynamicResource CardBorder}" BorderThickness="0,0,0,1">
<StackPanel Orientation="Horizontal">
<RadioButton Classes="tab" GroupName="sub" Content="Overview" IsChecked="{Binding ShowOverview}"/>
<RadioButton Classes="tab" GroupName="sub" Content="Mods" IsChecked="{Binding ShowModsTab}"/>
<RadioButton Classes="tab" GroupName="sub" Content="Logs" IsChecked="{Binding ShowLogs}"/>
</StackPanel>
</Border>
</StackPanel>
<Panel>
<ScrollViewer IsVisible="{Binding ShowOverview}">
<StackPanel Spacing="14" Margin="0,0,10,16" MaxWidth="900" HorizontalAlignment="Stretch">
<Border Classes="card">
<StackPanel Spacing="8">
<TextBlock Text="Branch and launch" Classes="h2"/>
<TextBlock Text="Name" Classes="label"/>
<TextBox Text="{Binding Name}"/>
<TextBlock Text="Branch" Classes="label"/>
<Grid ColumnDefinitions="*,Auto" ColumnSpacing="8">
<ComboBox ItemsSource="{Binding Main.BranchChoices}" SelectedItem="{Binding BranchHint}" HorizontalAlignment="Stretch">
<ComboBox.ItemTemplate>
<DataTemplate DataType="m:BranchChoice"><TextBlock Text="{Binding Display}"/></DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<Button Grid.Column="1" Content="+ Beta code" Command="{Binding EnterCodeCommand}" VerticalAlignment="Stretch"/>
</Grid>
<TextBlock Text="Launch arguments" Classes="label"/>
<Grid ColumnDefinitions="*,260" ColumnSpacing="8">
<TextBox Text="{Binding LaunchArgs}" PlaceholderText="Extra arguments"/>
<ComboBox Grid.Column="1" ItemsSource="{x:Static m:LaunchArgOption.All}" SelectedItem="{Binding ArgChoice}" PlaceholderText="Add an argument..." HorizontalAlignment="Stretch">
<ComboBox.ItemTemplate>
<DataTemplate DataType="m:LaunchArgOption">
<StackPanel ToolTip.Tip="{Binding Description}">
<TextBlock Text="{Binding Flag}" FontWeight="Medium"/>
<TextBlock Text="{Binding Description}" Classes="dim" FontSize="11" MaxWidth="360" TextTrimming="CharacterEllipsis"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</Grid>
</StackPanel>
</Border>
<Border Classes="card">
<StackPanel Spacing="10">
<TextBlock Text="MelonLoader (version.dll)" Classes="h2"/>
<TextBlock Text="{Binding MlText}" Classes="dim"/>
<StackPanel Orientation="Horizontal" Spacing="8">
<ComboBox ItemsSource="{Binding MlVersions}" SelectedItem="{Binding MlVersionChoice}" PlaceholderText="Version" MinWidth="150"/>
<Button Content="Install this version" Command="{Binding SetMlVersionCommand}"/>
<Button Content="{Binding MlToggleText}" Command="{Binding ToggleMlCommand}"/>
</StackPanel>
</StackPanel>
</Border>
<Border Classes="card">
<StackPanel Spacing="8">
<TextBlock Text="Hooks" Classes="h2"/>
<ItemsControl ItemsSource="{Binding Hooks}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="vm:InstallHookVM">
<Grid ColumnDefinitions="Auto,*,Auto" ColumnSpacing="12" Margin="0,3">
<CheckBox IsChecked="{Binding Enabled}" MinWidth="0"/>
<StackPanel Grid.Column="1" VerticalAlignment="Center">
<TextBlock Text="{Binding Name}" FontWeight="Medium"/>
<TextBlock Text="{Binding When}" Classes="dim" FontSize="12"/>
</StackPanel>
<Button Grid.Column="2" Content="Run now" Command="{Binding RunCommand}"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Border>
<Border Classes="card">
<Grid ColumnDefinitions="*,Auto" ColumnSpacing="12">
<StackPanel Spacing="4">
<TextBlock Text="Shared cache" Classes="h2"/>
<TextBlock Text="{Binding CacheText}" Classes="dim"/>
</StackPanel>
<Button Grid.Column="1" Content="Link to shared cache" Command="{Binding LinkCacheCommand}" VerticalAlignment="Center"/>
</Grid>
</Border>
</StackPanel>
</ScrollViewer>
<Grid IsVisible="{Binding ShowModsTab}" RowDefinitions="Auto,Auto,*,Auto" Margin="0,0,0,4">
<Grid ColumnDefinitions="*,200" ColumnSpacing="8" Margin="0,0,0,8">
<TextBox Text="{Binding Main.ModSearch}" PlaceholderText="Search all available mods"/>
<ComboBox Grid.Column="1" ItemsSource="{x:Static vm:MainViewModel.ModFilters}" SelectedItem="{Binding Main.ModFilter}" HorizontalAlignment="Stretch"/>
</Grid>
<Grid Grid.Row="1" ColumnDefinitions="34,250,90,90,*,96" Margin="12,0,12,4">
<TextBlock Grid.Column="1" Text="Name" Classes="dim" FontSize="12"/>
<TextBlock Grid.Column="2" Text="Installed" Classes="dim" FontSize="12"/>
<TextBlock Grid.Column="3" Text="Latest" Classes="dim" FontSize="12"/>
<TextBlock Grid.Column="4" Text="{Binding Main.AvailableStatus}" Classes="dim" FontSize="12"/>
</Grid>
<ListBox Grid.Row="2" Classes="table" ItemsSource="{Binding Main.ModRows}" SelectedItem="{Binding Main.SelectedRow}" SelectionChanged="OnTableSelection">
<ListBox.DataTemplates>
<DataTemplate DataType="vm:GroupHeader">
<Border Background="{DynamicResource GroupHeaderBg}" Padding="12,9" Margin="0,6,0,0" CornerRadius="6" Cursor="Hand">
<TextBlock Text="{Binding Text}" FontWeight="SemiBold"/>
</Border>
</DataTemplate>
<DataTemplate DataType="vm:ModVM">
<Grid ColumnDefinitions="34,250,90,90,*,96" Margin="12,6" ToolTip.Tip="{Binding Description}">
<CheckBox IsChecked="{Binding InstallUsed}" IsEnabled="{Binding HasInstall}" MinWidth="0" VerticalAlignment="Center"/>
<StackPanel Grid.Column="1" VerticalAlignment="Center" Margin="0,0,10,0">
<TextBlock Text="{Binding Name}" FontWeight="Medium" TextTrimming="CharacterEllipsis"/>
<TextBlock Text="{Binding AuthorLine}" Classes="dim" FontSize="11" TextTrimming="CharacterEllipsis"/>
</StackPanel>
<StackPanel Grid.Column="2" VerticalAlignment="Center" Margin="0,0,8,0">
<TextBlock Text="{Binding InstalledText}" TextTrimming="CharacterEllipsis"/>
<TextBlock Text="update" FontSize="11" Foreground="{DynamicResource WarnFg}" IsVisible="{Binding UpdateAvailable}"/>
</StackPanel>
<TextBlock Grid.Column="3" Text="{Binding LatestText}" VerticalAlignment="Center" TextTrimming="CharacterEllipsis" Margin="0,0,8,0"/>
<TextBlock Grid.Column="4" Text="{Binding ShortDescription}" Classes="dim" VerticalAlignment="Center" TextWrapping="Wrap" MaxHeight="34" TextTrimming="CharacterEllipsis" Margin="0,0,10,0"/>
<Button Grid.Column="5" Content="Manage" Command="{Binding ManageCommand}" Padding="10,5" HorizontalAlignment="Right" VerticalAlignment="Center"/>
</Grid>
</DataTemplate>
</ListBox.DataTemplates>
</ListBox>
<Grid Grid.Row="3" ColumnDefinitions="Auto,Auto,*,Auto,Auto" ColumnSpacing="8" Margin="0,12,0,0">
<StackPanel Grid.ColumnSpan="2" Orientation="Horizontal" Spacing="8">
<Button Content="Scan Steam install" Command="{Binding Main.ScanSteamInstallCommand}" IsVisible="{Binding Main.HasDetected}"/>
<Button Content="Scan this install's folder" Command="{Binding ImportModsCommand}"/>
<Button Content="Refresh sources" Command="{Binding Main.RefreshAllModsCommand}" Classes="ghost"/>
</StackPanel>
<TextBlock Grid.Column="2" Text="{Binding PendingText}" Foreground="{DynamicResource WarnFg}" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="0,0,12,0"/>
<Button Grid.Column="3" Content="Add local file(s)..." Command="{Binding Main.AddLocalNewCommand}"/>
<Button Grid.Column="4" Content="Install / Update" Command="{Binding ApplyCommand}" Classes="accent"/>
</Grid>
</Grid>
<Grid IsVisible="{Binding ShowLogs}" RowDefinitions="Auto,*" Margin="0,0,0,4">
<StackPanel Orientation="Horizontal" Margin="0,0,0,8" Spacing="4">
<RadioButton Classes="tab" GroupName="logtab" Content="MelonLoader" IsChecked="{Binding ShowMlLog}" Padding="14,8"/>
<RadioButton Classes="tab" GroupName="logtab" Content="Unity" IsChecked="{Binding ShowUnityLog}" Padding="14,8"/>
<TextBlock Text="Shared by all installs" Classes="dim" FontSize="12" VerticalAlignment="Center" Margin="12,0,0,0" IsVisible="{Binding ShowUnityLog}"/>
</StackPanel>
<v:LogView Grid.Row="1" Text="{Binding MlLogText}" IsVisible="{Binding ShowMlLog}"/>
<v:LogView Grid.Row="1" Text="{Binding UnityLogText}" IsVisible="{Binding ShowUnityLog}"/>
</Grid>
</Panel>
</DockPanel>
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>
</Panel>
</Grid>
<Grid ColumnDefinitions="320,*" Margin="24,20,24,20" IsVisible="{Binding IsModsPage}">
<DockPanel Margin="0,0,20,0">
<TextBlock DockPanel.Dock="Top" Text="Sources" Classes="h1" Margin="0,0,0,14"/>
<Grid DockPanel.Dock="Bottom" ColumnDefinitions="*,Auto" ColumnSpacing="8" Margin="0,8,0,0">
<TextBox Text="{Binding AddSourceRepo}" PlaceholderText="owner/repo or URL"/>
<Button Grid.Column="1" Content="Add" Command="{Binding AddSourceCommand}" Classes="accent" Padding="16,8"/>
</Grid>
<ListBox Classes="cards" ItemsSource="{Binding Sources}" SelectedItem="{Binding SelectedSource}">
<ListBox.ItemTemplate>
<DataTemplate DataType="vm:SourceVM">
<StackPanel Spacing="2" Margin="16,12">
<TextBlock Text="{Binding Name}" FontWeight="SemiBold" TextTrimming="CharacterEllipsis"/>
<TextBlock Text="{Binding Detail}" Classes="dim" FontSize="12" TextTrimming="CharacterEllipsis"/>
<TextBlock Text="{Binding CountText}" Classes="dim" FontSize="12"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DockPanel>
<ContentControl Grid.Column="1" Content="{Binding SelectedSource}">
<ContentControl.ContentTemplate>
<DataTemplate DataType="vm:SourceVM">
<DockPanel>
<StackPanel DockPanel.Dock="Top" Spacing="10" Margin="0,0,0,12">
<Grid ColumnDefinitions="*,Auto,Auto" ColumnSpacing="8">
<TextBlock Text="{Binding Name}" Classes="h1" VerticalAlignment="Center"/>
<Button Grid.Column="1" Content="Refresh" Command="{Binding Main.RefreshAllModsCommand}" VerticalAlignment="Center"/>
<Button Grid.Column="2" Content="Remove source" Command="{Binding RemoveCommand}" IsVisible="{Binding CanRemove}" Classes="ghost danger" VerticalAlignment="Center"/>
</Grid>
<StackPanel Orientation="Horizontal" Spacing="8">
<Border Classes="chip"><TextBlock Text="{Binding Kind}"/></Border>
<Border Classes="chip"><TextBlock Text="{Binding CountText}"/></Border>
</StackPanel>
<TextBlock Text="{Binding Link}" Classes="dim"/>
<Grid ColumnDefinitions="*,Auto,260" ColumnSpacing="8">
<TextBox Text="{Binding Filter}" PlaceholderText="Search this source"/>
<TextBlock Grid.Column="1" Text="Add to" VerticalAlignment="Center" Classes="dim"/>
<ComboBox Grid.Column="2" ItemsSource="{Binding Main.Installs}" SelectedItem="{Binding Main.SelectedInstall}" HorizontalAlignment="Stretch" PlaceholderText="Pick an install">
<ComboBox.ItemTemplate>
<DataTemplate DataType="vm:InstallVM"><TextBlock Text="{Binding Name}"/></DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</Grid>
</StackPanel>
<Grid DockPanel.Dock="Bottom" ColumnDefinitions="*,Auto" Margin="0,12,0,0" IsVisible="{Binding Main.HasSelectedInstall}">
<TextBlock Text="{Binding Main.SelectedInstall.PendingText}" Foreground="{DynamicResource WarnFg}" VerticalAlignment="Center"/>
<Button Grid.Column="1" Content="Install / Update" Command="{Binding Main.SelectedInstall.ApplyCommand}" Classes="accent"/>
</Grid>
<ListBox Classes="plain" ItemsSource="{Binding VisibleMods}">
<ListBox.ItemTemplate>
<DataTemplate DataType="vm:ModVM">
<Grid ColumnDefinitions="*,110,110,Auto,Auto" ColumnSpacing="10" Margin="8,6" ToolTip.Tip="{Binding Description}">
<StackPanel VerticalAlignment="Center">
<TextBlock Text="{Binding Name}" FontWeight="Medium" TextTrimming="CharacterEllipsis"/>
<TextBlock Text="{Binding ShortDescription}" Classes="dim" FontSize="11" TextTrimming="CharacterEllipsis"/>
</StackPanel>
<TextBlock Grid.Column="1" Text="{Binding InstalledText}" VerticalAlignment="Center" TextTrimming="CharacterEllipsis"/>
<TextBlock Grid.Column="2" Text="{Binding LatestText}" VerticalAlignment="Center" TextTrimming="CharacterEllipsis"/>
<Button Grid.Column="3" Content="{Binding ToggleInstallText}" Command="{Binding ToggleInstallCommand}" IsEnabled="{Binding HasInstall}" Padding="10,5" VerticalAlignment="Center"/>
<Button Grid.Column="4" Content="Manage" Command="{Binding ManageCommand}" Classes="ghost" Padding="10,5" VerticalAlignment="Center"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DockPanel>
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>
</Grid>
<DockPanel Margin="24,20,24,20" IsVisible="{Binding IsGalleryPage}">
<Grid DockPanel.Dock="Top" ColumnDefinitions="*,Auto,Auto" ColumnSpacing="8" Margin="0,0,0,14">
<StackPanel>
<TextBlock Text="Gallery" Classes="h1"/>
<TextBlock Text="{Binding Gallery.FolderText}" Classes="dim" FontSize="12"/>
</StackPanel>
<Button Grid.Column="1" Content="Refresh" Command="{Binding Gallery.RefreshCommand}" VerticalAlignment="Center"/>
<Button Grid.Column="2" Content="Open folder" Command="{Binding Gallery.OpenFolderCommand}" VerticalAlignment="Center"/>
</Grid>
<TextBlock DockPanel.Dock="Bottom" Text="{Binding Gallery.Status}" Classes="dim" Margin="0,8,0,0"/>
<ScrollViewer>
<StackPanel>
<TextBlock Text="No screenshots yet." Classes="dim" IsVisible="{Binding Gallery.IsEmpty}" Margin="0,20"/>
<ItemsControl ItemsSource="{Binding Gallery.Items}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate><WrapPanel/></ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate DataType="vm:GalleryItemVM">
<Border Classes="card" Width="276" Margin="0,0,12,12" Padding="10">
<StackPanel Spacing="8">
<Border Background="{DynamicResource AppBg}" CornerRadius="6" ClipToBounds="True" Height="150">
<Image Source="{Binding Thumb}" Stretch="UniformToFill"/>
</Border>
<TextBlock Text="{Binding DateText}" FontWeight="Medium"/>
<TextBlock Text="{Binding Name}" Classes="dim" FontSize="11" TextTrimming="CharacterEllipsis"/>
<Grid ColumnDefinitions="*,*,Auto,Auto" ColumnSpacing="6">
<Button Content="Copy" Command="{Binding CopyCommand}" HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" Padding="6,5"/>
<Button Grid.Column="1" Content="Open" Command="{Binding OpenCommand}" HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" Padding="6,5"/>
<Button Grid.Column="2" Content="Show" Command="{Binding ShowCommand}" Classes="ghost" Padding="8,5"/>
<Button Grid.Column="3" Content="Delete" Command="{Binding DeleteCommand}" Classes="ghost danger" Padding="8,5"/>
</Grid>
</StackPanel>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Button Content="Load more" Command="{Binding Gallery.MoreCommand}" IsVisible="{Binding Gallery.HasMore}" HorizontalAlignment="Center" Margin="0,8,0,16"/>
</StackPanel>
</ScrollViewer>
</DockPanel>
<ScrollViewer IsVisible="{Binding IsSettingsPage}">
<StackPanel Spacing="14" Margin="24,20,24,20" MaxWidth="780" HorizontalAlignment="Stretch">
<TextBlock Text="Settings" Classes="h1"/>
<Border Classes="card">
<StackPanel Spacing="10">
<TextBlock Text="{Binding VersionText}" Classes="h2"/>
<TextBlock Text="{Binding UpdateStatus}" Classes="dim" FontSize="12" IsVisible="{Binding UpdateStatus, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
<StackPanel Orientation="Horizontal" Spacing="8">
<Button Content="Check for updates" Command="{Binding CheckUpdateCommand}"/>
<Button Content="{Binding InstallUpdateText}" Command="{Binding InstallUpdateCommand}" IsVisible="{Binding UpdateReady}" Classes="accent"/>
</StackPanel>
<CheckBox IsChecked="{Binding CheckUpdates}" Content="Check on startup"/>
</StackPanel>
</Border>
<Border Classes="card">
<StackPanel Spacing="10">
<TextBlock Text="Steam account" Classes="h2"/>
<TextBlock Text="{Binding SteamAccountText}" Classes="dim" FontSize="12" TextWrapping="Wrap"/>
<StackPanel Orientation="Horizontal" Spacing="8">
<Button Content="Sign in..." Command="{Binding SteamSignInCommand}"/>
<Button Content="Sign out" Command="{Binding SteamSignOutCommand}" IsVisible="{Binding SteamSignedIn}" Classes="ghost"/>
</StackPanel>
<TextBlock Text="{Binding SteamClientText}" Classes="dim" FontSize="12" TextWrapping="Wrap"/>
</StackPanel>
</Border>
<Border Classes="card">
<StackPanel Spacing="10">
<TextBlock Text="Game accounts" Classes="h2"/>
<ItemsControl ItemsSource="{Binding Accounts}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="vm:AccountVM">
<Grid ColumnDefinitions="220,*,Auto" ColumnSpacing="10" Margin="0,0,0,6">
<TextBox Text="{Binding Name}"/>
<TextBlock Grid.Column="1" Text="{Binding Username}" Classes="dim" VerticalAlignment="Center" TextTrimming="CharacterEllipsis"/>
<Button Grid.Column="2" Content="✕" Command="{Binding RemoveCommand}" Classes="ghost" ToolTip.Tip="Remove"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Grid ColumnDefinitions="220,*,Auto,Auto" ColumnSpacing="10">
<TextBox Text="{Binding NewAccountUser}" PlaceholderText="Username"/>
<TextBox Grid.Column="1" Text="{Binding NewAccountKey}" PlaceholderText="Access key" PasswordChar="•"/>
<Button Grid.Column="2" Content="Add" Command="{Binding AddAccountCommand}"/>
<Button Grid.Column="3" Content="Import from installs" Command="{Binding ImportAccountsCommand}"/>
</Grid>
</StackPanel>
</Border>
<Border Classes="card">
<StackPanel Spacing="10">
<TextBlock Text="Appearance" Classes="h2"/>
<TextBlock Text="{Binding ThemeNote}" IsVisible="{Binding ThemeNote, Converter={x:Static StringConverters.IsNotNullOrEmpty}}" Classes="dim" TextWrapping="Wrap"/>
<ComboBox ItemsSource="{Binding ThemeNames}" SelectedItem="{Binding Theme}" MinWidth="260" HorizontalAlignment="Left"/>
</StackPanel>
</Border>
<Border Classes="card">
<StackPanel Spacing="10">
<TextBlock Text="Library location" Classes="h2"/>
<Grid ColumnDefinitions="*,Auto,Auto" ColumnSpacing="8">
<TextBox Text="{Binding LibraryRoot}" IsEnabled="{Binding CanChangeRoot}"/>
<Button Grid.Column="1" Content="Browse..." Command="{Binding BrowseLibraryRootCommand}" IsEnabled="{Binding CanChangeRoot}"/>
<Button Grid.Column="2" Content="Apply" Command="{Binding ApplyLibraryRootCommand}" IsEnabled="{Binding CanChangeRoot}"/>
</Grid>
<StackPanel Orientation="Horizontal" Spacing="8">
<Button Content="Open library" Command="{Binding OpenLibraryCommand}"/>
<Button Content="Open shared cache" Command="{Binding OpenCacheCommand}"/>
<Button Content="Open mod store" Command="{Binding OpenModStoreCommand}"/>
</StackPanel>
</StackPanel>
</Border>
<Border Classes="card">
<StackPanel Spacing="10">
<TextBlock Text="Cache" Classes="h2"/>
<StackPanel Orientation="Horizontal" Spacing="12">
<Button Content="Deduplicate and relink all caches" Command="{Binding DedupeCommand}"/>
<TextBlock Text="{Binding CacheSize}" Classes="dim" VerticalAlignment="Center"/>
</StackPanel>
<CheckBox IsChecked="{Binding CacheGuard}" Content="Multi-instance cache guard"/>
</StackPanel>
</Border>
<Border Classes="card">
<StackPanel Spacing="10">
<TextBlock Text="Hooks" Classes="h2"/>
<TextBlock Text="{}{game} {install} {branch} {build} work in arguments." TextWrapping="Wrap" Classes="dim"/>
<ItemsControl ItemsSource="{Binding Hooks}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="vm:HookVM">
<Border BorderBrush="{DynamicResource CardBorder}" BorderThickness="1" CornerRadius="8" Padding="14" Margin="0,0,0,10">
<StackPanel Spacing="8">
<Grid ColumnDefinitions="*,Auto" ColumnSpacing="8">
<TextBox Text="{Binding Name}" FontWeight="SemiBold"/>
<Button Grid.Column="1" Content="Remove" Command="{Binding RemoveCommand}" Classes="ghost danger"/>
</Grid>
<WrapPanel>
<CheckBox IsChecked="{Binding BeforeUpdate}" Content="Before update" Margin="0,0,18,0"/>
<CheckBox IsChecked="{Binding AfterUpdate}" Content="After install / update" Margin="0,0,18,0"/>
<CheckBox IsChecked="{Binding BeforeLaunch}" Content="Before launch"/>
</WrapPanel>
<StackPanel Spacing="8">
<TextBox Text="{Binding Command}" PlaceholderText="Script or program"/>
<TextBox Text="{Binding Arguments}" PlaceholderText="Arguments, e.g. --target &quot;{game}&quot;"/>
</StackPanel>
<CheckBox IsChecked="{Binding DefaultOn}" Content="Enable on new installs"/>
</StackPanel>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Button Content="+ Add command hook" Command="{Binding AddHookCommand}" HorizontalAlignment="Left"/>
</StackPanel>
</Border>
<Border Classes="card">
<StackPanel Spacing="10">
<TextBlock Text="Activity log" Classes="h2"/>
<v:LogView Text="{Binding LogText}" Height="260"/>
</StackPanel>
</Border>
<Border Classes="card">
<StackPanel Spacing="10">
<TextBlock Text="GitHub" Classes="h2"/>
<TextBox Text="{Binding GitHubToken}" PasswordChar="●" PlaceholderText="Personal access token (optional)"/>
</StackPanel>
</Border>
</StackPanel>
</ScrollViewer>
</Panel>
</DockPanel>
<Border IsVisible="{Binding ShowNew}" Background="#B0000000">
<Border Classes="card" Width="540" VerticalAlignment="Center" HorizontalAlignment="Center" Background="{DynamicResource OverlayBg}">
<StackPanel Spacing="10">
<TextBlock Text="New install" Classes="h1"/>
<TextBlock Text="Name" Classes="label"/>
<TextBox Text="{Binding NewName}" PlaceholderText="Name"/>
<TextBlock Text="Branch" Classes="label"/>
<Grid ColumnDefinitions="*,Auto" ColumnSpacing="8">
<ComboBox ItemsSource="{Binding BranchChoices}" SelectedItem="{Binding NewChoice}" HorizontalAlignment="Stretch">
<ComboBox.ItemTemplate>
<DataTemplate DataType="m:BranchChoice"><TextBlock Text="{Binding Display}"/></DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<Button Grid.Column="1" Content="+ Beta code" Command="{Binding EnterCodeNewCommand}" VerticalAlignment="Stretch"/>
</Grid>
<CheckBox IsChecked="{Binding NewImport}" Content="Mirror an existing install" Margin="0,8,0,0"/>
<StackPanel Spacing="8" IsVisible="{Binding NewImport}">
<Grid ColumnDefinitions="*,Auto" ColumnSpacing="8">
<ComboBox ItemsSource="{Binding DetectedInstalls}" SelectedItem="{Binding NewDetected}" PlaceholderText="Detected Steam installs" HorizontalAlignment="Stretch"/>
<Button Grid.Column="1" Content="Browse..." Command="{Binding BrowseImportCommand}"/>
</Grid>
<TextBox Text="{Binding NewImportPath}" PlaceholderText="Folder with ChilloutVR.exe"/>
<CheckBox IsChecked="{Binding NewMoveCache}" Content="Copy its cache too"/>
<TextBlock Text="The original is not modified." Classes="dim" FontSize="12" TextWrapping="Wrap"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Spacing="8" HorizontalAlignment="Right" Margin="0,12,0,0">
<Button Content="Cancel" Command="{Binding CancelNewCommand}" Classes="ghost"/>
<Button Content="Create install" Command="{Binding CreateInstallCommand}" Classes="accent"/>
</StackPanel>
</StackPanel>
</Border>
</Border>
<Border IsVisible="{Binding ShowManage}" Background="#B0000000">
<Border Classes="card" Width="500" MaxHeight="680" VerticalAlignment="Center" HorizontalAlignment="Center" Background="{DynamicResource OverlayBg}" DataContext="{Binding ManagedMod}">
<ScrollViewer>
<StackPanel Spacing="12">
<StackPanel Spacing="10">
<TextBlock Text="{Binding Name}" FontSize="16" FontWeight="SemiBold"/>
<TextBlock Text="{Binding Details}" Classes="dim" FontSize="12" TextWrapping="Wrap"/>
<TextBlock Text="Version" Classes="label"/>
<ComboBox ItemsSource="{Binding VersionChoices}" SelectedItem="{Binding InstallVersion}" IsEnabled="{Binding HasInstall}" HorizontalAlignment="Stretch"/>
<StackPanel Orientation="Horizontal" Spacing="10" IsVisible="{Binding HasSourceChoice}">
<TextBlock Text="Source" VerticalAlignment="Center" Classes="dim"/>
<ComboBox ItemsSource="{Binding SourceOptions}" SelectedItem="{Binding SelectedSource}" MinHeight="30" Padding="10,4"/>
</StackPanel>
<Grid ColumnDefinitions="150,*" ColumnSpacing="10">
<ComboBox ItemsSource="{x:Static vm:ModVM.Types}" SelectedItem="{Binding Type}" HorizontalAlignment="Stretch"/>
<TextBox Grid.Column="1" Text="{Binding AssetFilter}" PlaceholderText="Asset filter (optional)" IsVisible="{Binding !IsLocal}"/>
</Grid>
<TextBlock Text="Available versions" Classes="label"/>
<ListBox Classes="plain" ItemsSource="{Binding Releases}" SelectedItem="{Binding SelectedRelease}" MaxHeight="170">
<ListBox.ItemTemplate>
<DataTemplate DataType="vm:ReleaseRow"><TextBlock Text="{Binding Text}" FontSize="12"/></DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<TextBlock Text="{Binding UsedBy}" Classes="dim" FontSize="12"/>
<WrapPanel>
<Button Content="Download selected" Command="{Binding DownloadCommand}" IsVisible="{Binding !IsLocal}" Margin="0,0,6,6"/>
<Button Content="Replace local files..." Command="{Binding AddLocalCommand}" IsVisible="{Binding IsLocal}" Margin="0,0,6,6"/>
<Button Content="Delete download" Command="{Binding DeleteDownloadCommand}" Margin="0,0,6,6"/>
<Button Content="Remove from catalog" Command="{Binding RemoveCommand}" IsEnabled="{Binding InCatalog}" Classes="ghost danger" Margin="0,0,6,6"/>
</WrapPanel>
</StackPanel>
<Button Content="Close" Command="{Binding Main.CloseManageCommand}" Classes="accent" HorizontalAlignment="Right"/>
</StackPanel>
</ScrollViewer>
</Border>
</Border>
<Border IsVisible="{Binding ShowSignIn}" Background="#B0000000">
<Border Classes="card" Width="440" VerticalAlignment="Center" HorizontalAlignment="Center" Background="{DynamicResource OverlayBg}">
<StackPanel Spacing="10">
<TextBlock Text="Sign in to Steam" Classes="h1" FontSize="20"/>
<TextBlock Text="{Binding SignInPrompt}" Classes="dim" TextWrapping="Wrap"/>
<TextBox Text="{Binding SignInUser}" PlaceholderText="Steam username" IsVisible="{Binding SignInNeedsPassword}"/>
<TextBox Text="{Binding SignInPassword}" PasswordChar="●" PlaceholderText="Password" IsVisible="{Binding SignInNeedsPassword}">
<TextBox.KeyBindings>
<KeyBinding Gesture="Enter" Command="{Binding SubmitSignInCommand}"/>
</TextBox.KeyBindings>
</TextBox>
<TextBox Text="{Binding SignInCode}" PlaceholderText="Steam Guard code" IsVisible="{Binding SignInNeedsCode}">
<TextBox.KeyBindings>
<KeyBinding Gesture="Enter" Command="{Binding SubmitSignInCommand}"/>
</TextBox.KeyBindings>
</TextBox>
<TextBlock Text="The password is not saved." Classes="dim" FontSize="12" TextWrapping="Wrap"/>
<StackPanel Orientation="Horizontal" Spacing="8" HorizontalAlignment="Right" Margin="0,8,0,0">
<Button Content="Cancel" Command="{Binding CancelSignInCommand}" Classes="ghost"/>
<Button Content="Continue" Command="{Binding SubmitSignInCommand}" Classes="accent" IsVisible="{Binding SignInCanContinue}"/>
</StackPanel>
</StackPanel>
</Border>
</Border>
<Border IsVisible="{Binding ShowCodeEntry}" Background="#B0000000">
<Border Classes="card" Width="440" VerticalAlignment="Center" HorizontalAlignment="Center" Background="{DynamicResource OverlayBg}">
<StackPanel Spacing="10">
<TextBlock Text="Enter beta code" Classes="h1" FontSize="20"/>
<TextBlock Text="{Binding CodeIntro}" Classes="dim" TextWrapping="Wrap"/>
<TextBox Text="{Binding CodeText}" PlaceholderText="Beta access code" IsEnabled="{Binding CodeIdle}">
<TextBox.KeyBindings>
<KeyBinding Gesture="Enter" Command="{Binding SubmitCodeCommand}"/>
</TextBox.KeyBindings>
</TextBox>
<TextBlock Text="{Binding CodeError}" IsVisible="{Binding HasCodeError}" Foreground="{DynamicResource DangerFg}" TextWrapping="Wrap"/>
<TextBlock Text="Checking..." IsVisible="{Binding CodeBusy}" Classes="dim"/>
<StackPanel Orientation="Horizontal" Spacing="8" HorizontalAlignment="Right" Margin="0,8,0,0">
<Button Content="Cancel" Command="{Binding CancelCodeCommand}" IsEnabled="{Binding CodeIdle}" Classes="ghost"/>
<Button Content="Check code" Command="{Binding SubmitCodeCommand}" IsEnabled="{Binding CodeIdle}" Classes="accent"/>
</StackPanel>
</StackPanel>
</Border>
</Border>
<Border IsVisible="{Binding ToastVisible}" Classes="card" Background="{DynamicResource ToastBg}" Padding="0" HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="24" MinWidth="340" MaxWidth="480">
<Grid ColumnDefinitions="Auto,*,Auto">
<Border Width="4" CornerRadius="10,0,0,10" Background="{DynamicResource AccentBrush}" IsVisible="{Binding !ToastError}"/>
<Border Width="4" CornerRadius="10,0,0,10" Background="{DynamicResource DangerFg}" IsVisible="{Binding ToastError}"/>
<StackPanel Grid.Column="1" Spacing="8" Margin="14,12">
<TextBlock Text="{Binding Status}" TextWrapping="Wrap"/>
<ProgressBar Value="{Binding Progress}" Maximum="100" IsIndeterminate="{Binding Indeterminate}" Height="4" IsVisible="{Binding IsBusy}"/>
</StackPanel>
<StackPanel Grid.Column="2" VerticalAlignment="Center" Margin="0,0,8,0">
<Button Content="Cancel" Command="{Binding CancelCommand}" Classes="ghost" IsVisible="{Binding IsBusy}"/>
<Button Content="✕" Command="{Binding DismissToastCommand}" Classes="ghost" IsVisible="{Binding IsIdle}"/>
</StackPanel>
</Grid>
</Border>
</Grid>
</Window>