Files
galeon 1d781b5324
tests / package-smoke-linux (push) Skipped
tests / package-smoke-windows (push) Skipped
tests / package-smoke-macos (push) Skipped
tests / macos (push) Successful in 1m20s
tests / linux (push) Successful in 2m14s
tests / windows (push) Failing after 23m21s
fix #23 by adding validating on first startup and close #30 by adding
version number

Signed-off-by: galeon <dertiellis@gmail.com>
2026-10-23 09:55:15 +03:00

11 KiB
Raw Permalink Blame History

Main.qml

Главное окно, оно же точка входа: main.cpp загружает его через engine.loadFromModule("BiLauncher", "Main"). Корень — Window 1280×720.

Что в нём есть:

  • единственный экземпляр LauncherBackend и все обработчики его сигналов;
  • экран запуска: фон, кнопка игры по центру, список профилей, кнопка активной сборки, кнопки папки модов, настроек и сезонных сборок;
  • плашка сообщений и две панели прогресса (ProgressPanel);
  • диалоги, которые не вынесены в отдельные файлы: новый профиль, редактирование профиля, код двухфакторной аутентификации, настройки запуска.

Отдельными файлами сделаны BuildsDialog, SeasonalBuildsDialog, JavaPickerDialog и MicrosoftLoginDialog. Окно передаёт им бэкенд через свойство backend.

Стиль Qt Quick Controls — Basic (выставлен в main.cpp), и почти у каждого контрола здесь своё оформление.

Раскладка

Всё стоит на якорях вокруг кнопки запуска: список профилей слева сверху от неё, кнопка активной сборки справа сверху, кнопки папки и настроек под списком профилей. Кнопка сезонных сборок стоит в правом нижнем углу, потому что остальные углы заняты.

В левом верхнем углу фона стоит подпись launcherVersion — «Версия: 1.0.1-dev». Текст из app.label.version, номер из Qt.application.version, то есть из LAUNCHER_VERSION (см. main.cpp).

Обе панели прогресса (загрузки и смены сборки) стоят в левом нижнем углу на одних и тех же якорях. Одновременно они не появляются: пока лаунчер занят загрузкой, бэкенд не начнёт смену сборки, и наоборот. Панель смены сборки отменить нельзя.

У заголовков и подвалов всех диалогов корнем служит Item с явным implicitHeight. У Rectangle implicitHeight всегда 0, и Dialog не смог бы посчитать свою высоту.

Функции

showToast(text, color, timeout) — показать сообщение в плашке. timeout в миллисекундах, по умолчанию 4000. 0 значит «держать до следующего сообщения». Так показываются шаги запуска, чтобы сообщение не исчезало посреди долгой операции.

openMicrosoftLogin(url) — открыть окно входа Microsoft. Окно создаётся при первом вызове через Qt.createComponent() и хранится в microsoftLoginDialog. Объявить его прямо в файле нельзя: MicrosoftLoginDialog.qml есть в модуле только в сборках с WebEngine, и в остальных сломалось бы всё главное окно. Если компонент не создался, вход отменяется у бэкенда и показывается сообщение.

formatMb(bytes) — байты в мегабайты с одним знаком после запятой, для панели загрузки.

Сигналы бэкенда

Сигнал Что делает окно
launched зелёное сообщение «запущено»
launchProgress сообщение без таймаута
launchError красное сообщение на 8 секунд
twoFactorRequired открывает диалог кода
gameFinished сообщение о закрытии игры; если код не 0 или процесс упал, красное и с кодом
microsoftLoginUrlReady openMicrosoftLogin()
microsoftLoginSucceeded сообщение. Выбор в списке профилей не трогает: новый профиль уже выбран тем, кто его создал, а повторный вход мог быть не для последнего профиля
microsoftLoginFailed красное сообщение на 8 секунд
microsoftReloginRequired сразу startMicrosoftLogin() для этого профиля
gameOutput console.log
seasonalInstallFinished сообщение «сборка установлена, можно играть»
javaRuntimeInstalled обновляет строку Java в настройках

Кнопка запуска выключена, пока busy или gameRunning. Список профилей выключен, пока busy; кнопка активной сборки — пока busy или gameRunning. Так во время загрузки и установки (в том числе сезонной сборки) доступна только отмена на панели загрузки.

Профили

Выпадающий список профилей переделан целиком. Наверху всплывающей панели закреплена кнопка «+ Добавить профиль», под ней список. У каждой строки при наведении появляются карандаш (открывает редактирование через openFor()) и корзина (removeProfile()).

Типы входа во всех списках идут в одном порядке: 0 — offline, 1 — elyby, 2 — microsoft. Модель берётся из Loc.t.profile.authTypes, и порядок в каталоге важен, потому что код сравнивает currentIndex с 1 и 2. Без WebEngine третий пункт отрезается через .slice(0, 2). В окне редактирования он остаётся, если профиль уже лицензионный: иначе в сборке без WebEngine такой профиль молча стал бы офлайновым.

Новый профиль. addProfile(), новый профиль выбирается в списке. Если тип «Microsoft», сразу начинается вход, потому что без него такой профиль бесполезен. Скрытые поля при сохранении не читаются: в них мог остаться текст, набранный до смены типа.

Редактирование. Дополнительные свойства диалога: editIndex, msProfile, msLinked (есть ли сессия Microsoft), msName (ник из аккаунта). Ник показывается отдельным полем только для чтения, а не подставляется в поле логина. Иначе привязка оборвалась бы при первом же вводе в это поле у обычного профиля. Кнопка входа сначала сохраняет профиль с типом microsoft через updateProfile() и только потом вызывает startMicrosoftLogin(). Тип могли переключить только что, и без этого токены достались бы профилю другого типа.

Двухфакторная аутентификация

Диалог показывает имя профиля (profileName) и поле для кода. «Подтвердить» вызывает submitTwoFactorCode(), «Отмена» — cancelPendingLaunch(). Если отмену не вызвать, запуск так и повиснет.

Настройки

settingsDialog.load() читает settings() и detectedJava(), раскладывает значения по полям и открывает диалог. «Сохранить» собирает всё в одну карту и отдаёт в updateSettings().

  • Язык стоит первым, потому что относится ко всему приложению, а не к запуску игры. В модели переведённые подписи, рядом лежит непереводимый список codes (system, ru, en). Язык применяется по «Сохранить» и сразу, без перезапуска.
  • Папка игры, а под полем — путь, который получится на самом деле (resolvedGameDir). Путь хранится в свойстве, а не записывается в текст напрямую, иначе подпись не обновилась бы при смене языка.
  • Java. Поле открывает JavaPickerDialog с текущим выбором и требованием активной сборки (requiredJavaMajor()). Крестик сбрасывает выбор, и тогда Java ищется в системе. Выбор хранится в javaRuntimeId и записывается только по «Сохранить». javaRuntimeInfo обновляется при смене javaRuntimeId и по javaRuntimeInstalled, потому что javaRuntimeInfo() — обычный вызов, а не привязка. Если сборка выбрана, запуск идёт ею, а путь из соседнего поля остаётся запасным вариантом.
  • Память, размер окна, аргументы JVM, полноэкранный режим.
  • Ниже для справки список найденных в системе java.

Окно выбора Java объявлено рядом с диалогом настроек, а не внутри него. Оно шире настроек и центрируется по окну лаунчера.

Кнопки

  • папка — openMinecraftFolder() (открывает mods);
  • настройки — settingsDialog.load();
  • сезонные сборки — seasonalDialog.openCatalog();
  • активная сборка — buildsDialog.open().

Все тексты окна берутся из Loc.t, литералов в разметке нет.


При создании этого документа использовался ИИ.