Downloads UI Architecture & Views
The Downloads UI in GenHub provides a responsive, desktop-optimized interface for browsing, filtering, inspecting, and installing community modifications, patches, game clients, and tools. Built with Avalonia UI and CommunityToolkit MVVM, it replaces legacy publisher card interfaces with a unified master-detail browser experience.
For pipeline architecture, background downloading, and service mechanics, see the Downloads Feature Guide.
Component Architecture
The Downloads UI consists of seven specialized Avalonia views and dialogs coordinated by MVVM ViewModels:
1. DownloadsBrowserView
Source: GenHub/Features/Downloads/Views/DownloadsBrowserView.axaml
DataContext: DownloadsBrowserViewModel
DownloadsBrowserView is the primary tab view. It is structured around an Avalonia SidebarLayout containing a collapsible publisher pane and a main scrollable content area.
Visual Structure
Left Sidebar Pane (
SidebarLayout):- Displays available publishers: built-in static providers (Generals Online, TheSuperHackers, Community Outpost), built-in dynamic providers (GitHub), and user-subscribed creator catalogs.
- Each item displays the publisher logo (via
infraControls:ImageLoader), publisher display name, and content count badge. - Footer contains a "Manifests Folder" button (
OpenManifestsFolderCommand) to open local manifests in file manager.
Top Header & Toolbar:
- Page title dynamically displaying the selected publisher's name.
- Search box (
TextBox.search-box) with two-way binding toSearchTermand reactive search debouncing. - Filter toggle button (
ToggleButton.filter-toggle-btn) visible when the active publisher supports filtering (CanShowFilters). - Refresh button and in-flight loading spinners.
Flyout Filter Panel:
- Embeds
FilterPanelView, bound toCurrentFilterViewModel. - Slides down or toggles open when the user clicks the Filter button.
- Embeds
Content Cards Grid:
- An adaptive responsive grid presenting
ContentCardViewcards for each item inContentItems. - Handles empty states ("No content found") and loading shimmer indicators.
- An adaptive responsive grid presenting
Load More Footer:
- Displays a "Load More" button when
CanLoadMoreis true and more content is available from the publisher.
- Displays a "Load More" button when
Detail View Modal Layer:
- Renders
ContentDetailViewin a full overlay whenIsDetailViewVisibleis true (SelectedContent != null).
- Renders
2. ContentCardView
Source: GenHub/Features/Downloads/Views/ContentCardView.axaml
DataContext: ContentGridItemViewModel
ContentCardView represents an individual downloadable item in the browser grid.
Key Card Elements
- Preview Media: Thumbnail image with fallback icon when no screenshot is provided.
- Header Badges:
- Content Type Badge: Styled using
ContentTypeToBrushConverter(for border and foreground text againstCardBackground) to visually identifyMod,Patch,GameClient,Tool,Map, etc. (Tinted background viaContentTypeToBadgeBackgroundConverteris featured inContentDetailView). - Publisher Identifier: Pill identifying the source publisher.
- Content Type Badge: Styled using
- Title & Description: Title with two-line character ellipsis truncation, and clean summary text formatted by
ReleaseDescriptionHelper. - Variant Selector: Dropdown selector displayed when
HasVariantsis true (e.g. resolution variants, game-client variants for Generals vs Zero Hour). - Bundle Components Indicator: Displays component count and individual completion status when
HasBundleComponentsis true. - State-Driven Action Buttons:
- Download Button (visible when
CurrentState == NotDownloaded): TriggersDownloadContentCommandviaIContentDownloadCoordinator. - Progress Indicator (visible when
IsDownloading == true): Displays live progress bar and status text (DownloadStatus). - Update Available Button (visible when
CurrentState == UpdateAvailable): Orange highlight to acquire the latest version. - Add to Profile Button (visible when
CurrentState == Downloaded): OpensProfileSelectionViewmodal.
- Download Button (visible when
3. ContentDetailView
Source: GenHub/Features/Downloads/Views/ContentDetailView.axaml
DataContext: ContentDetailViewModel
ContentDetailView provides an immersive modal overlay with tabbed navigation, rich media carousels, and version management.
Tab Organization
- Overview Tab:
- Hero banner and screenshot carousel.
- Rich Markdown description rendered via Markdown.Avalonia.
- Markdown Security: Employs
SafeMarkdownHyperlinkCommand(restricting navigation strictly to HTTP/HTTPS URLs) andSafeMarkdownPathResolverto prevent arbitrary URL scheme execution or UNC exploits.
- Releases Tab:
- Detailed list of releases, changelogs, file sizes, and release dates.
- Addons Tab:
- Discovered compatible addons, map packs, and complementary files.
- Dynamic Custom Tabs:
- Populated dynamically at runtime via
ITabProviderRegistryandCatalogTabProvider. - Allows creator catalogs to define dedicated documentation, server configuration, or extra information tabs directly in their
catalog.json.
- Populated dynamically at runtime via
4. FilterPanelView
Source: GenHub/Features/Downloads/Views/FilterPanelView.axaml
DataContext: IFilterPanelViewModel (e.g. GitHubFilterViewModel, CommunityOutpostFilterViewModel, SuperHackersFilterViewModel)
Provides a collapsible drawer of publisher-specific filters.
- Reactive Filtering: Raising
FiltersAppliedupdates the content collection without full-page reloads. - Clear All Filters: Resets filters to defaults and re-runs the baseline discovery query.
5. ProfileSelectionView
Source: GenHub/Features/Downloads/Views/ProfileSelectionView.axaml
DataContext: ProfileSelectionViewModel
A modal dialog that appears when a user clicks "Add to Profile" on downloaded content.
- Game Compatibility Categorization:
- Compatible Profiles: Highlighted profiles matching the content's target game (Generals or Zero Hour).
- Other Profiles: Incompatible profiles shown with cautionary badges to avoid accidental cross-game attachment.
- Direct Command Selection: Directly binds
SelectProfileCommandwith the selectedProfileOptionViewModelparameter. - Quick Create Profile: Allows one-click creation of a new game profile preconfigured with the downloaded content.
6. DependencyPreviewView
Source: GenHub/Features/Downloads/Views/DependencyPreviewView.axaml
DataContext: DependencyPreviewViewModel
Shown before attaching content to a profile if unresolved dependencies or conflicts exist.
- Displays hierarchical dependency requirements (e.g. requires specific patches or base clients).
- Highlights already satisfied dependencies vs missing dependencies that must be downloaded first.
7. SubscriptionConfirmationDialog
Source: GenHub/Features/Downloads/Views/SubscriptionConfirmationDialog.axaml
DataContext: SubscriptionConfirmationViewModel
Modal dialog displayed when the application intercepts a genhub://subscribe?url=<catalog_url> protocol link or when the user enters a catalog subscription URL manually.
- Fetches and previews catalog metadata (publisher name, avatar, catalog version, description, content item count) using
CatalogDocumentReader. - Confirms user intent before saving the subscription to
IPublisherSubscriptionStore.
UI Converters and Theme Resources
The Downloads UI utilizes several custom Avalonia converters located in GenHub.Infrastructure.Converters:
| Converter | Type | Role in Downloads UI |
|---|---|---|
ContentTypeToBrushConverter | IValueConverter | Translates ContentType enum values into vivid accent brushes for badge borders, text, and card outlines. |
ContentTypeToBadgeBackgroundConverter | IValueConverter | Produces a 14.5% opacity tinted background brush (alpha 0x25 / 37) matching the content type accent color. |
ProfileSelectionConverter | IMultiValueConverter | Legacy multi-value converter packaging content item and target GameProfile into command parameters for profile assignment. |
SafeMarkdownHyperlinkCommand | ICommand | Sanitizes markdown hyperlinks to ensure only external HTTP/HTTPS browser links can be triggered. |
All styling tokens, including brush keys (SurfaceElevatedBrush, SurfaceHoverBrush, AccentBrush, BorderBrush), are defined in GenHub/Assets/Styles/ThemeResources.axaml.
