Table of Contents

Class ServerModsViewModel

Namespace
McServerLauncher.ViewModels
Assembly
McServerLauncher.dll

A base class for objects of which the properties must be observable.

public class ServerModsViewModel : ObservableObject, INotifyPropertyChanged, INotifyPropertyChanging
Inheritance
ServerModsViewModel
Implements
Inherited Members

Constructors

ServerModsViewModel(ServerConfig)

public ServerModsViewModel(ServerConfig config)

Parameters

config ServerConfig

Properties

ActiveFilters

Everything narrowing the results right now, as one row of chips: the server's own loader and Minecraft version (always on, not removable) followed by the categories the user picked. Putting them together answers "why am I seeing these results?" in one glance.

public ObservableCollection<ActiveFilterViewModel> ActiveFilters { get; }

Property Value

ObservableCollection<ActiveFilterViewModel>

BrowseTags

The category chips, built from the tag catalogue and filtered to what makes sense for this kind of server. Tags that map to a Modrinth facet filter exactly; the rest fall back to a search term.

public IReadOnlyList<StoreTagViewModel> BrowseTags { get; }

Property Value

IReadOnlyList<StoreTagViewModel>

BrowseTitle

public string BrowseTitle { get; }

Property Value

string

CanLoadMore

[ExcludeFromCodeCoverage]
public bool CanLoadMore { get; set; }

Property Value

bool

CheckUpdatesCommand

[ExcludeFromCodeCoverage]
public IAsyncRelayCommand CheckUpdatesCommand { get; }

Property Value

IAsyncRelayCommand

ClearFiltersCommand

Gets an IRelayCommand instance wrapping McServerLauncher.ViewModels.ServerModsViewModel.ClearFilters().

[ExcludeFromCodeCoverage]
public IRelayCommand ClearFiltersCommand { get; }

Property Value

IRelayCommand

ContentTabTitle

public string ContentTabTitle { get; }

Property Value

string

DeleteModCommand

Gets an IAsyncRelayCommand<T> instance wrapping DeleteMod(ModItem).

[ExcludeFromCodeCoverage]
public IAsyncRelayCommand<ModItem?> DeleteModCommand { get; }

Property Value

IAsyncRelayCommand<ModItem>

Details

The open details page, or null while the browser list is showing. The list is deliberately left untouched underneath, so coming back is instant and keeps the scroll position.

[ExcludeFromCodeCoverage]
public ModDetailsViewModel? Details { get; set; }

Property Value

ModDetailsViewModel

DismissInstallNoticeCommand

Gets an IRelayCommand instance wrapping McServerLauncher.ViewModels.ServerModsViewModel.DismissInstallNotice().

[ExcludeFromCodeCoverage]
public IRelayCommand DismissInstallNoticeCommand { get; }

Property Value

IRelayCommand

ExportModpackCommand

Gets an IAsyncRelayCommand instance wrapping McServerLauncher.ViewModels.ServerModsViewModel.ExportModpack().

[ExcludeFromCodeCoverage]
public IAsyncRelayCommand ExportModpackCommand { get; }

Property Value

IAsyncRelayCommand

FacetTags

Categories Modrinth can filter on exactly. These stack: each adds its own facet group, and Modrinth ANDs the groups.

public IReadOnlyList<StoreTagViewModel> FacetTags { get; }

Property Value

IReadOnlyList<StoreTagViewModel>

FilterTip

public string FilterTip { get; }

Property Value

string

FilterTypeBrush

public IBrush FilterTypeBrush { get; }

Property Value

IBrush

FilterTypeText

public string FilterTypeText { get; }

Property Value

string

FilterVersionText

public string FilterVersionText { get; }

Property Value

string

HasInstallNotice

public bool HasInstallNotice { get; }

Property Value

bool

HasMissingDependencies

public bool HasMissingDependencies { get; }

Property Value

bool

HasSelectedTags

public bool HasSelectedTags { get; }

Property Value

bool

HowToPlaySteps

Instructions to play: install the loader client (mods) or just join (plugins).

public string HowToPlaySteps { get; }

Property Value

string

HowToPlayTitle

public string HowToPlayTitle { get; }

Property Value

string

InstallFailed

True when the notice reports a failure, which draws it in red rather than green.

[ExcludeFromCodeCoverage]
public bool InstallFailed { get; set; }

Property Value

bool

InstallMissingDependenciesCommand

[ExcludeFromCodeCoverage]
public IAsyncRelayCommand InstallMissingDependenciesCommand { get; }

Property Value

IAsyncRelayCommand

InstallNotice

What the last install said, shown as a banner over the store and the details page.

[ExcludeFromCodeCoverage]
public string? InstallNotice { get; set; }

Property Value

string

InstalledMods

public ObservableCollection<ModItem> InstalledMods { get; }

Property Value

ObservableCollection<ModItem>

InstalledTitle

public string InstalledTitle { get; }

Property Value

string

IsBrowsing

public bool IsBrowsing { get; }

Property Value

bool

IsCheckingUpdates

[ExcludeFromCodeCoverage]
public bool IsCheckingUpdates { get; set; }

Property Value

bool

IsFiltersOpen

Whether the filters popup is open (its toggle button binds both ways).

[ExcludeFromCodeCoverage]
public bool IsFiltersOpen { get; set; }

Property Value

bool

IsHowToPlayOpen

Whether the "how to play" popup is open.

[ExcludeFromCodeCoverage]
public bool IsHowToPlayOpen { get; set; }

Property Value

bool

IsInstalledPanelOpen

Whether the installed panel is showing. Collapsing it is the cheapest way to give the results room: it is 300px that mostly holds a short list, and on a 1150px window it is the difference between one column of results and two.

[ExcludeFromCodeCoverage]
public bool IsInstalledPanelOpen { get; set; }

Property Value

bool

IsInstallingDependencies

[ExcludeFromCodeCoverage]
public bool IsInstallingDependencies { get; set; }

Property Value

bool

IsPluginBased

public bool IsPluginBased { get; }

Property Value

bool

IsSearching

[ExcludeFromCodeCoverage]
public bool IsSearching { get; set; }

Property Value

bool

LoadMoreCommand

[ExcludeFromCodeCoverage]
public IAsyncRelayCommand LoadMoreCommand { get; }

Property Value

IAsyncRelayCommand

MissingDependencyText

[ExcludeFromCodeCoverage]
public string? MissingDependencyText { get; set; }

Property Value

string

NoInstalledText

public string NoInstalledText { get; }

Property Value

string

QueryTags

Categories Modrinth has no facet for, which can only contribute words to the query. Picking a second one would blur the search instead of narrowing it, so they behave as a radio group.

public IReadOnlyList<StoreTagViewModel> QueryTags { get; }

Property Value

IReadOnlyList<StoreTagViewModel>

RefreshInstalledModsCommand

Gets an IRelayCommand instance wrapping McServerLauncher.ViewModels.ServerModsViewModel.RefreshInstalledMods().

[ExcludeFromCodeCoverage]
public IRelayCommand RefreshInstalledModsCommand { get; }

Property Value

IRelayCommand

RemoveTagCommand

[ExcludeFromCodeCoverage]
public IRelayCommand<StoreTagViewModel?> RemoveTagCommand { get; }

Property Value

IRelayCommand<StoreTagViewModel>

SearchCommand

Gets an IAsyncRelayCommand instance wrapping Search(CancellationToken).

[ExcludeFromCodeCoverage]
public IAsyncRelayCommand SearchCommand { get; }

Property Value

IAsyncRelayCommand

SearchPlaceholder

public string SearchPlaceholder { get; }

Property Value

string

SearchQuery

[ExcludeFromCodeCoverage]
public string SearchQuery { get; set; }

Property Value

string

SearchResults

The results, flat. Replaced in one go rather than emptied and refilled: a list that sits empty across a network round trip makes the whole panel blink out and back.

public BulkObservableCollection<ModrinthProjectViewModel> SearchResults { get; }

Property Value

BulkObservableCollection<ModrinthProjectViewModel>

SearchStatus

[ExcludeFromCodeCoverage]
public string SearchStatus { get; set; }

Property Value

string

SelectedSortIndex

[ExcludeFromCodeCoverage]
public int SelectedSortIndex { get; set; }

Property Value

int

SelectedTags

The categories currently filtering the browse, in the order the user picked them. Shown as removable chips, so a filter can never be selected but scrolled out of sight.

public ObservableCollection<StoreTagViewModel> SelectedTags { get; }

Property Value

ObservableCollection<StoreTagViewModel>

SortOptions

Sort options shown in the UI. Index 0 = relevance, 1 = downloads.

public IReadOnlyList<string> SortOptions { get; }

Property Value

IReadOnlyList<string>

ToggleModCommand

Gets an IRelayCommand<T> instance wrapping ToggleMod(ModItem).

[ExcludeFromCodeCoverage]
public IRelayCommand<ModItem?> ToggleModCommand { get; }

Property Value

IRelayCommand<ModItem>

ToggleTagCommand

[ExcludeFromCodeCoverage]
public IRelayCommand<StoreTagViewModel?> ToggleTagCommand { get; }

Property Value

IRelayCommand<StoreTagViewModel>

UpdateModCommand

Gets an IAsyncRelayCommand<T> instance wrapping UpdateMod(ModItem).

[ExcludeFromCodeCoverage]
public IAsyncRelayCommand<ModItem?> UpdateModCommand { get; }

Property Value

IAsyncRelayCommand<ModItem>

UpdateStatus

[ExcludeFromCodeCoverage]
public string UpdateStatus { get; set; }

Property Value

string

Methods

EnsureLoaded()

Loads the first page of mods the first time the Mods tab is shown.

public void EnsureLoaded()

GoBack()

Goes back to the previous details page, or to the list when there isn't one.

public void GoBack()

InstallMissingAsync(IEnumerable<string>, IProgress<string>?, CancellationToken)

Fetches the mods or plugins named by ids, for the check before a start.

public Task InstallMissingAsync(IEnumerable<string> ids, IProgress<string>? log = null, CancellationToken ct = default)

Parameters

ids IEnumerable<string>
log IProgress<string>
ct CancellationToken

Returns

Task

Remarks

The ids come from the jars, and a mod id is not a store id: cristallib is published on Modrinth as cristel-lib, and there is no rule that maps one to the other. So anything the store does not recognise is skipped rather than reported as an error — the caller checks again afterwards and says what is still missing, which is the honest answer.

Progress goes to the caller's log rather than to this tab's status line: the user pressed Start and is looking at the server's console, not at the Mods tab.

InstallModAsync(string, VersionResult?)

Installs a project. chosen installs that exact version (the details page offers the last few); without it the newest compatible one is resolved, as before. This is the only install path in the app — the details page routes through it too.

public Task InstallModAsync(string projectId, VersionResult? chosen = null)

Parameters

projectId string
chosen VersionResult

Returns

Task

ReloadInstalled()

Re-reads the content folder, for jars that arrived without the user putting them there.

public void ReloadInstalled()

Remarks

The panel takes its snapshot when it is built, which is the same moment the server is created — before crossplay has downloaded Geyser and Floodgate into it. Without this the two jars are on disk and loaded by the server while the Mods tab still shows nothing, and the only way to see them is the refresh button, which nobody thinks to press for mods they did not install.

ShowDetails(StoreItem)

Opens the details page for a store item, remembering the current one.

public void ShowDetails(StoreItem item)

Parameters

item StoreItem

Shutdown()

Drops the open details page, cancelling whatever it is still fetching. Called when the app closes so pending requests don't outlive the window they were going to fill.

public void Shutdown()