aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore4
-rw-r--r--BUILD.md5
-rw-r--r--CMakeLists.txt4
-rw-r--r--changelog.md78
-rw-r--r--launcher/Application.cpp (renamed from launcher/Launcher.cpp)329
-rw-r--r--launcher/Application.h (renamed from launcher/Launcher.h)99
-rw-r--r--launcher/ApplicationMessage.cpp (renamed from launcher/LauncherMessage.cpp)6
-rw-r--r--launcher/ApplicationMessage.h (renamed from launcher/LauncherMessage.h)2
-rw-r--r--launcher/BaseInstance.h5
-rw-r--r--launcher/BaseVersionList.h2
-rw-r--r--launcher/CMakeLists.txt591
-rw-r--r--launcher/ColumnResizer.cpp199
-rw-r--r--launcher/ColumnResizer.h41
-rw-r--r--launcher/Env.cpp210
-rw-r--r--launcher/Env.h63
-rw-r--r--launcher/InstanceImportTask.cpp17
-rw-r--r--launcher/InstanceImportTask.h2
-rw-r--r--launcher/InstancePageProvider.h34
-rw-r--r--launcher/JavaCommon.cpp2
-rw-r--r--launcher/LaunchController.cpp241
-rw-r--r--launcher/NullInstance.h3
-rw-r--r--launcher/QObjectPtr.h6
-rw-r--r--launcher/SkinUtils.cpp4
-rw-r--r--launcher/Usable.h10
-rw-r--r--launcher/VersionProxyModel.cpp8
-rw-r--r--launcher/icons/IIconList.cpp7
-rw-r--r--launcher/icons/IIconList.h25
-rw-r--r--launcher/icons/IconList.h23
-rw-r--r--launcher/icons/MMCIcon.h10
-rw-r--r--launcher/java/JavaChecker.cpp12
-rw-r--r--launcher/java/JavaInstallList.cpp4
-rw-r--r--launcher/java/JavaInstallList.h4
-rw-r--r--launcher/java/JavaUtils.cpp19
-rw-r--r--launcher/launch/steps/CheckJava.cpp (renamed from launcher/java/launch/CheckJava.cpp)0
-rw-r--r--launcher/launch/steps/CheckJava.h (renamed from launcher/java/launch/CheckJava.h)0
-rw-r--r--launcher/launch/steps/Update.h2
-rw-r--r--launcher/main.cpp16
-rw-r--r--launcher/meta/BaseEntity.cpp20
-rw-r--r--launcher/meta/BaseEntity.h6
-rw-r--r--launcher/meta/Index_test.cpp7
-rw-r--r--launcher/meta/VersionList.cpp2
-rw-r--r--launcher/meta/VersionList.h2
-rw-r--r--launcher/minecraft/AssetsUtils.cpp4
-rw-r--r--launcher/minecraft/AssetsUtils.h4
-rw-r--r--launcher/minecraft/Component.cpp18
-rw-r--r--launcher/minecraft/ComponentUpdateTask.cpp33
-rw-r--r--launcher/minecraft/Library.cpp5
-rw-r--r--launcher/minecraft/Library.h2
-rw-r--r--launcher/minecraft/Library_test.cpp2
-rw-r--r--launcher/minecraft/MinecraftInstance.cpp48
-rw-r--r--launcher/minecraft/MinecraftInstance.h4
-rw-r--r--launcher/minecraft/MinecraftLoadAndCheck.h2
-rw-r--r--launcher/minecraft/MinecraftUpdate.cpp1
-rw-r--r--launcher/minecraft/PackProfile.cpp23
-rw-r--r--launcher/minecraft/PackProfile.h2
-rw-r--r--launcher/minecraft/PackProfile_p.h2
-rw-r--r--launcher/minecraft/VersionFilterData.cpp1
-rw-r--r--launcher/minecraft/VersionFilterData.h2
-rw-r--r--launcher/minecraft/auth/AccountData.cpp49
-rw-r--r--launcher/minecraft/auth/AccountData.h24
-rw-r--r--launcher/minecraft/auth/AccountList.cpp314
-rw-r--r--launcher/minecraft/auth/AccountList.h52
-rw-r--r--launcher/minecraft/auth/AccountTask.cpp79
-rw-r--r--launcher/minecraft/auth/AccountTask.h72
-rw-r--r--launcher/minecraft/auth/AuthRequest.cpp (renamed from launcher/minecraft/auth/flows/AuthRequest.cpp)16
-rw-r--r--launcher/minecraft/auth/AuthRequest.h (renamed from launcher/minecraft/auth/flows/AuthRequest.h)9
-rw-r--r--launcher/minecraft/auth/AuthSession.h4
-rw-r--r--launcher/minecraft/auth/AuthStep.cpp7
-rw-r--r--launcher/minecraft/auth/AuthStep.h33
-rw-r--r--launcher/minecraft/auth/MinecraftAccount.cpp272
-rw-r--r--launcher/minecraft/auth/MinecraftAccount.h56
-rw-r--r--launcher/minecraft/auth/Parsers.cpp316
-rw-r--r--launcher/minecraft/auth/Parsers.h19
-rw-r--r--launcher/minecraft/auth/Yggdrasil.cpp (renamed from launcher/minecraft/auth/flows/Yggdrasil.cpp)106
-rw-r--r--launcher/minecraft/auth/Yggdrasil.h (renamed from launcher/minecraft/auth/flows/Yggdrasil.h)28
-rw-r--r--launcher/minecraft/auth/flows/AuthContext.cpp911
-rw-r--r--launcher/minecraft/auth/flows/AuthContext.h107
-rw-r--r--launcher/minecraft/auth/flows/AuthFlow.cpp71
-rw-r--r--launcher/minecraft/auth/flows/AuthFlow.h45
-rw-r--r--launcher/minecraft/auth/flows/MSA.cpp37
-rw-r--r--launcher/minecraft/auth/flows/MSA.h22
-rw-r--r--launcher/minecraft/auth/flows/MSAInteractive.cpp20
-rw-r--r--launcher/minecraft/auth/flows/MSAInteractive.h10
-rw-r--r--launcher/minecraft/auth/flows/MSASilent.cpp16
-rw-r--r--launcher/minecraft/auth/flows/MSASilent.h10
-rw-r--r--launcher/minecraft/auth/flows/Mojang.cpp27
-rw-r--r--launcher/minecraft/auth/flows/Mojang.h26
-rw-r--r--launcher/minecraft/auth/flows/MojangLogin.cpp14
-rw-r--r--launcher/minecraft/auth/flows/MojangLogin.h13
-rw-r--r--launcher/minecraft/auth/flows/MojangRefresh.cpp14
-rw-r--r--launcher/minecraft/auth/flows/MojangRefresh.h10
-rw-r--r--launcher/minecraft/auth/steps/EntitlementsStep.cpp53
-rw-r--r--launcher/minecraft/auth/steps/EntitlementsStep.h25
-rw-r--r--launcher/minecraft/auth/steps/GetSkinStep.cpp43
-rw-r--r--launcher/minecraft/auth/steps/GetSkinStep.h22
-rw-r--r--launcher/minecraft/auth/steps/LauncherLoginStep.cpp78
-rw-r--r--launcher/minecraft/auth/steps/LauncherLoginStep.h22
-rw-r--r--launcher/minecraft/auth/steps/MSAStep.cpp111
-rw-r--r--launcher/minecraft/auth/steps/MSAStep.h32
-rw-r--r--launcher/minecraft/auth/steps/MigrationEligibilityStep.cpp45
-rw-r--r--launcher/minecraft/auth/steps/MigrationEligibilityStep.h22
-rw-r--r--launcher/minecraft/auth/steps/MinecraftProfileStep.cpp83
-rw-r--r--launcher/minecraft/auth/steps/MinecraftProfileStep.h22
-rw-r--r--launcher/minecraft/auth/steps/XboxAuthorizationStep.cpp158
-rw-r--r--launcher/minecraft/auth/steps/XboxAuthorizationStep.h34
-rw-r--r--launcher/minecraft/auth/steps/XboxProfileStep.cpp73
-rw-r--r--launcher/minecraft/auth/steps/XboxProfileStep.h22
-rw-r--r--launcher/minecraft/auth/steps/XboxUserStep.cpp68
-rw-r--r--launcher/minecraft/auth/steps/XboxUserStep.h22
-rw-r--r--launcher/minecraft/auth/steps/YggdrasilStep.cpp51
-rw-r--r--launcher/minecraft/auth/steps/YggdrasilStep.h28
-rw-r--r--launcher/minecraft/launch/ClaimAccount.cpp6
-rw-r--r--launcher/minecraft/launch/LauncherPartLaunch.cpp15
-rw-r--r--launcher/minecraft/launch/VerifyJavaInstall.cpp11
-rw-r--r--launcher/minecraft/legacy/LegacyInstance.cpp12
-rw-r--r--launcher/minecraft/legacy/LegacyInstance.h8
-rw-r--r--launcher/minecraft/services/CapeChange.cpp20
-rw-r--r--launcher/minecraft/services/CapeChange.h8
-rw-r--r--launcher/minecraft/services/SkinDelete.cpp14
-rw-r--r--launcher/minecraft/services/SkinDelete.h11
-rw-r--r--launcher/minecraft/services/SkinUpload.cpp14
-rw-r--r--launcher/minecraft/services/SkinUpload.h9
-rw-r--r--launcher/minecraft/update/AssetUpdateTask.cpp12
-rw-r--r--launcher/minecraft/update/AssetUpdateTask.h2
-rw-r--r--launcher/minecraft/update/FMLLibrariesTask.cpp14
-rw-r--r--launcher/minecraft/update/FMLLibrariesTask.h2
-rw-r--r--launcher/minecraft/update/LibrariesTask.cpp8
-rw-r--r--launcher/minecraft/update/LibrariesTask.h2
-rw-r--r--launcher/modplatform/atlauncher/ATLPackInstallTask.cpp39
-rw-r--r--launcher/modplatform/atlauncher/ATLPackInstallTask.h2
-rw-r--r--launcher/modplatform/flame/FileResolvingTask.cpp8
-rw-r--r--launcher/modplatform/flame/FileResolvingTask.h5
-rw-r--r--launcher/modplatform/legacy_ftb/PackFetchTask.cpp18
-rw-r--r--launcher/modplatform/legacy_ftb/PackFetchTask.h5
-rw-r--r--launcher/modplatform/legacy_ftb/PackInstallTask.cpp26
-rw-r--r--launcher/modplatform/legacy_ftb/PackInstallTask.h7
-rw-r--r--launcher/modplatform/modpacksch/FTBPackInstallTask.cpp13
-rw-r--r--launcher/modplatform/modpacksch/FTBPackInstallTask.h2
-rw-r--r--launcher/modplatform/technic/SingleZipPackInstallTask.cpp11
-rw-r--r--launcher/modplatform/technic/SingleZipPackInstallTask.h2
-rw-r--r--launcher/modplatform/technic/SolderPackInstallTask.cpp14
-rw-r--r--launcher/modplatform/technic/SolderPackInstallTask.h6
-rw-r--r--launcher/net/Download.cpp19
-rw-r--r--launcher/net/Download.h6
-rw-r--r--launcher/net/FileSink.cpp1
-rw-r--r--launcher/net/HttpMetaCache.cpp1
-rw-r--r--launcher/net/MetaCacheSink.cpp4
-rw-r--r--launcher/net/NetAction.h15
-rw-r--r--launcher/net/NetJob.cpp4
-rw-r--r--launcher/net/NetJob.h30
-rw-r--r--launcher/net/PasteUpload.cpp7
-rw-r--r--launcher/news/NewsChecker.cpp5
-rw-r--r--launcher/news/NewsChecker.h6
-rw-r--r--launcher/notifications/NotificationChecker.cpp6
-rw-r--r--launcher/notifications/NotificationChecker.h2
-rw-r--r--launcher/resources/backgrounds/backgrounds.qrc1
-rw-r--r--launcher/resources/backgrounds/cattiversary.pngbin0 -> 99736 bytes
-rw-r--r--launcher/resources/sources/burfcat_hat.pngbin0 -> 15813 bytes
-rw-r--r--launcher/resources/sources/cattiversary.xcfbin0 -> 121675 bytes
-rw-r--r--launcher/screenshots/ImgurAlbumCreation.cpp10
-rw-r--r--launcher/screenshots/ImgurAlbumCreation.h11
-rw-r--r--launcher/screenshots/ImgurUpload.cpp10
-rw-r--r--launcher/screenshots/ImgurUpload.h28
-rw-r--r--launcher/screenshots/Screenshot.h10
-rw-r--r--launcher/tasks/SequentialTask.cpp6
-rw-r--r--launcher/tasks/SequentialTask.h6
-rw-r--r--launcher/tasks/Task.h4
-rw-r--r--launcher/translations/TranslationsModel.cpp42
-rw-r--r--launcher/ui/ColorCache.cpp (renamed from launcher/ColorCache.cpp)0
-rw-r--r--launcher/ui/ColorCache.h (renamed from launcher/ColorCache.h)0
-rw-r--r--launcher/ui/GuiUtil.cpp (renamed from launcher/GuiUtil.cpp)19
-rw-r--r--launcher/ui/GuiUtil.h (renamed from launcher/GuiUtil.h)0
-rw-r--r--launcher/ui/InstanceWindow.cpp (renamed from launcher/InstanceWindow.cpp)25
-rw-r--r--launcher/ui/InstanceWindow.h (renamed from launcher/InstanceWindow.h)9
-rw-r--r--launcher/ui/MainWindow.cpp (renamed from launcher/MainWindow.cpp)356
-rw-r--r--launcher/ui/MainWindow.h (renamed from launcher/MainWindow.h)6
-rw-r--r--launcher/ui/dialogs/AboutDialog.cpp (renamed from launcher/dialogs/AboutDialog.cpp)8
-rw-r--r--launcher/ui/dialogs/AboutDialog.h (renamed from launcher/dialogs/AboutDialog.h)2
-rw-r--r--launcher/ui/dialogs/AboutDialog.ui (renamed from launcher/dialogs/AboutDialog.ui)0
-rw-r--r--launcher/ui/dialogs/CopyInstanceDialog.cpp (renamed from launcher/dialogs/CopyInstanceDialog.cpp)12
-rw-r--r--launcher/ui/dialogs/CopyInstanceDialog.h (renamed from launcher/dialogs/CopyInstanceDialog.h)0
-rw-r--r--launcher/ui/dialogs/CopyInstanceDialog.ui (renamed from launcher/dialogs/CopyInstanceDialog.ui)0
-rw-r--r--launcher/ui/dialogs/CustomMessageBox.cpp (renamed from launcher/dialogs/CustomMessageBox.cpp)0
-rw-r--r--launcher/ui/dialogs/CustomMessageBox.h (renamed from launcher/dialogs/CustomMessageBox.h)0
-rw-r--r--launcher/ui/dialogs/EditAccountDialog.cpp (renamed from launcher/dialogs/EditAccountDialog.cpp)0
-rw-r--r--launcher/ui/dialogs/EditAccountDialog.h (renamed from launcher/dialogs/EditAccountDialog.h)0
-rw-r--r--launcher/ui/dialogs/EditAccountDialog.ui (renamed from launcher/dialogs/EditAccountDialog.ui)0
-rw-r--r--launcher/ui/dialogs/ExportInstanceDialog.cpp (renamed from launcher/dialogs/ExportInstanceDialog.cpp)4
-rw-r--r--launcher/ui/dialogs/ExportInstanceDialog.h (renamed from launcher/dialogs/ExportInstanceDialog.h)0
-rw-r--r--launcher/ui/dialogs/ExportInstanceDialog.ui (renamed from launcher/dialogs/ExportInstanceDialog.ui)0
-rw-r--r--launcher/ui/dialogs/IconPickerDialog.cpp (renamed from launcher/dialogs/IconPickerDialog.cpp)14
-rw-r--r--launcher/ui/dialogs/IconPickerDialog.h (renamed from launcher/dialogs/IconPickerDialog.h)0
-rw-r--r--launcher/ui/dialogs/IconPickerDialog.ui (renamed from launcher/dialogs/IconPickerDialog.ui)0
-rw-r--r--launcher/ui/dialogs/LoginDialog.cpp (renamed from launcher/dialogs/LoginDialog.cpp)2
-rw-r--r--launcher/ui/dialogs/LoginDialog.h (renamed from launcher/dialogs/LoginDialog.h)3
-rw-r--r--launcher/ui/dialogs/LoginDialog.ui (renamed from launcher/dialogs/LoginDialog.ui)0
-rw-r--r--launcher/ui/dialogs/MSALoginDialog.cpp (renamed from launcher/dialogs/MSALoginDialog.cpp)2
-rw-r--r--launcher/ui/dialogs/MSALoginDialog.h (renamed from launcher/dialogs/MSALoginDialog.h)2
-rw-r--r--launcher/ui/dialogs/MSALoginDialog.ui (renamed from launcher/dialogs/MSALoginDialog.ui)0
-rw-r--r--launcher/ui/dialogs/NewComponentDialog.cpp (renamed from launcher/dialogs/NewComponentDialog.cpp)4
-rw-r--r--launcher/ui/dialogs/NewComponentDialog.h (renamed from launcher/dialogs/NewComponentDialog.h)0
-rw-r--r--launcher/ui/dialogs/NewComponentDialog.ui (renamed from launcher/dialogs/NewComponentDialog.ui)0
-rw-r--r--launcher/ui/dialogs/NewInstanceDialog.cpp (renamed from launcher/dialogs/NewInstanceDialog.cpp)40
-rw-r--r--launcher/ui/dialogs/NewInstanceDialog.h (renamed from launcher/dialogs/NewInstanceDialog.h)2
-rw-r--r--launcher/ui/dialogs/NewInstanceDialog.ui (renamed from launcher/dialogs/NewInstanceDialog.ui)0
-rw-r--r--launcher/ui/dialogs/NotificationDialog.cpp (renamed from launcher/dialogs/NotificationDialog.cpp)0
-rw-r--r--launcher/ui/dialogs/NotificationDialog.h (renamed from launcher/dialogs/NotificationDialog.h)0
-rw-r--r--launcher/ui/dialogs/NotificationDialog.ui (renamed from launcher/dialogs/NotificationDialog.ui)0
-rw-r--r--launcher/ui/dialogs/ProfileSelectDialog.cpp (renamed from launcher/dialogs/ProfileSelectDialog.cpp)9
-rw-r--r--launcher/ui/dialogs/ProfileSelectDialog.h (renamed from launcher/dialogs/ProfileSelectDialog.h)2
-rw-r--r--launcher/ui/dialogs/ProfileSelectDialog.ui (renamed from launcher/dialogs/ProfileSelectDialog.ui)0
-rw-r--r--launcher/ui/dialogs/ProfileSetupDialog.cpp256
-rw-r--r--launcher/ui/dialogs/ProfileSetupDialog.h88
-rw-r--r--launcher/ui/dialogs/ProfileSetupDialog.ui74
-rw-r--r--launcher/ui/dialogs/ProgressDialog.cpp (renamed from launcher/dialogs/ProgressDialog.cpp)0
-rw-r--r--launcher/ui/dialogs/ProgressDialog.h (renamed from launcher/dialogs/ProgressDialog.h)0
-rw-r--r--launcher/ui/dialogs/ProgressDialog.ui (renamed from launcher/dialogs/ProgressDialog.ui)0
-rw-r--r--launcher/ui/dialogs/SkinUploadDialog.cpp (renamed from launcher/dialogs/SkinUploadDialog.cpp)20
-rw-r--r--launcher/ui/dialogs/SkinUploadDialog.h (renamed from launcher/dialogs/SkinUploadDialog.h)0
-rw-r--r--launcher/ui/dialogs/SkinUploadDialog.ui (renamed from launcher/dialogs/SkinUploadDialog.ui)0
-rw-r--r--launcher/ui/dialogs/UpdateDialog.cpp (renamed from launcher/dialogs/UpdateDialog.cpp)14
-rw-r--r--launcher/ui/dialogs/UpdateDialog.h (renamed from launcher/dialogs/UpdateDialog.h)2
-rw-r--r--launcher/ui/dialogs/UpdateDialog.ui (renamed from launcher/dialogs/UpdateDialog.ui)0
-rw-r--r--launcher/ui/dialogs/VersionSelectDialog.cpp (renamed from launcher/dialogs/VersionSelectDialog.cpp)18
-rw-r--r--launcher/ui/dialogs/VersionSelectDialog.h (renamed from launcher/dialogs/VersionSelectDialog.h)0
-rw-r--r--launcher/ui/instanceview/AccessibleInstanceView.cpp (renamed from launcher/instanceview/AccessibleInstanceView.cpp)0
-rw-r--r--launcher/ui/instanceview/AccessibleInstanceView.h (renamed from launcher/instanceview/AccessibleInstanceView.h)0
-rw-r--r--launcher/ui/instanceview/AccessibleInstanceView_p.h (renamed from launcher/instanceview/AccessibleInstanceView_p.h)0
-rw-r--r--launcher/ui/instanceview/InstanceDelegate.cpp (renamed from launcher/instanceview/InstanceDelegate.cpp)0
-rw-r--r--launcher/ui/instanceview/InstanceDelegate.h (renamed from launcher/instanceview/InstanceDelegate.h)0
-rw-r--r--launcher/ui/instanceview/InstanceProxyModel.cpp (renamed from launcher/instanceview/InstanceProxyModel.cpp)6
-rw-r--r--launcher/ui/instanceview/InstanceProxyModel.h (renamed from launcher/instanceview/InstanceProxyModel.h)0
-rw-r--r--launcher/ui/instanceview/InstanceView.cpp (renamed from launcher/instanceview/InstanceView.cpp)4
-rw-r--r--launcher/ui/instanceview/InstanceView.h (renamed from launcher/instanceview/InstanceView.h)0
-rw-r--r--launcher/ui/instanceview/VisualGroup.cpp (renamed from launcher/instanceview/VisualGroup.cpp)0
-rw-r--r--launcher/ui/instanceview/VisualGroup.h (renamed from launcher/instanceview/VisualGroup.h)0
-rw-r--r--launcher/ui/pagedialog/PageDialog.cpp (renamed from launcher/pagedialog/PageDialog.cpp)11
-rw-r--r--launcher/ui/pagedialog/PageDialog.h (renamed from launcher/pagedialog/PageDialog.h)2
-rw-r--r--launcher/ui/pages/BasePage.h (renamed from launcher/pages/BasePage.h)0
-rw-r--r--launcher/ui/pages/BasePageContainer.h (renamed from launcher/pages/BasePageContainer.h)0
-rw-r--r--launcher/ui/pages/BasePageProvider.h (renamed from launcher/pages/BasePageProvider.h)2
-rw-r--r--launcher/ui/pages/global/AccountListPage.cpp (renamed from launcher/pages/global/AccountListPage.cpp)69
-rw-r--r--launcher/ui/pages/global/AccountListPage.h (renamed from launcher/pages/global/AccountListPage.h)10
-rw-r--r--launcher/ui/pages/global/AccountListPage.ui (renamed from launcher/pages/global/AccountListPage.ui)4
-rw-r--r--launcher/ui/pages/global/CustomCommandsPage.cpp (renamed from launcher/pages/global/CustomCommandsPage.cpp)4
-rw-r--r--launcher/ui/pages/global/CustomCommandsPage.h (renamed from launcher/pages/global/CustomCommandsPage.h)8
-rw-r--r--launcher/ui/pages/global/ExternalToolsPage.cpp (renamed from launcher/pages/global/ExternalToolsPage.cpp)18
-rw-r--r--launcher/ui/pages/global/ExternalToolsPage.h (renamed from launcher/pages/global/ExternalToolsPage.h)8
-rw-r--r--launcher/ui/pages/global/ExternalToolsPage.ui (renamed from launcher/pages/global/ExternalToolsPage.ui)0
-rw-r--r--launcher/ui/pages/global/JavaPage.cpp (renamed from launcher/pages/global/JavaPage.cpp)10
-rw-r--r--launcher/ui/pages/global/JavaPage.h (renamed from launcher/pages/global/JavaPage.h)6
-rw-r--r--launcher/ui/pages/global/JavaPage.ui (renamed from launcher/pages/global/JavaPage.ui)0
-rw-r--r--launcher/ui/pages/global/LanguagePage.cpp (renamed from launcher/pages/global/LanguagePage.cpp)4
-rw-r--r--launcher/ui/pages/global/LanguagePage.h (renamed from launcher/pages/global/LanguagePage.h)6
-rw-r--r--launcher/ui/pages/global/LauncherPage.cpp (renamed from launcher/pages/global/LauncherPage.cpp)30
-rw-r--r--launcher/ui/pages/global/LauncherPage.h (renamed from launcher/pages/global/LauncherPage.h)8
-rw-r--r--launcher/ui/pages/global/LauncherPage.ui (renamed from launcher/pages/global/LauncherPage.ui)0
-rw-r--r--launcher/ui/pages/global/MinecraftPage.cpp (renamed from launcher/pages/global/MinecraftPage.cpp)6
-rw-r--r--launcher/ui/pages/global/MinecraftPage.h (renamed from launcher/pages/global/MinecraftPage.h)6
-rw-r--r--launcher/ui/pages/global/MinecraftPage.ui (renamed from launcher/pages/global/MinecraftPage.ui)0
-rw-r--r--launcher/ui/pages/global/PasteEEPage.cpp (renamed from launcher/pages/global/PasteEEPage.cpp)6
-rw-r--r--launcher/ui/pages/global/PasteEEPage.h (renamed from launcher/pages/global/PasteEEPage.h)6
-rw-r--r--launcher/ui/pages/global/PasteEEPage.ui (renamed from launcher/pages/global/PasteEEPage.ui)0
-rw-r--r--launcher/ui/pages/global/ProxyPage.cpp (renamed from launcher/pages/global/ProxyPage.cpp)17
-rw-r--r--launcher/ui/pages/global/ProxyPage.h (renamed from launcher/pages/global/ProxyPage.h)6
-rw-r--r--launcher/ui/pages/global/ProxyPage.ui (renamed from launcher/pages/global/ProxyPage.ui)0
-rw-r--r--launcher/ui/pages/instance/GameOptionsPage.cpp (renamed from launcher/pages/instance/GameOptionsPage.cpp)0
-rw-r--r--launcher/ui/pages/instance/GameOptionsPage.h (renamed from launcher/pages/instance/GameOptionsPage.h)6
-rw-r--r--launcher/ui/pages/instance/GameOptionsPage.ui (renamed from launcher/pages/instance/GameOptionsPage.ui)0
-rw-r--r--launcher/ui/pages/instance/InstanceSettingsPage.cpp (renamed from launcher/pages/instance/InstanceSettingsPage.cpp)27
-rw-r--r--launcher/ui/pages/instance/InstanceSettingsPage.h (renamed from launcher/pages/instance/InstanceSettingsPage.h)6
-rw-r--r--launcher/ui/pages/instance/InstanceSettingsPage.ui (renamed from launcher/pages/instance/InstanceSettingsPage.ui)2
-rw-r--r--launcher/ui/pages/instance/LegacyUpgradePage.cpp (renamed from launcher/pages/instance/LegacyUpgradePage.cpp)11
-rw-r--r--launcher/ui/pages/instance/LegacyUpgradePage.h (renamed from launcher/pages/instance/LegacyUpgradePage.h)6
-rw-r--r--launcher/ui/pages/instance/LegacyUpgradePage.ui (renamed from launcher/pages/instance/LegacyUpgradePage.ui)0
-rw-r--r--launcher/ui/pages/instance/LogPage.cpp (renamed from launcher/pages/instance/LogPage.cpp)14
-rw-r--r--launcher/ui/pages/instance/LogPage.h (renamed from launcher/pages/instance/LogPage.h)6
-rw-r--r--launcher/ui/pages/instance/LogPage.ui (renamed from launcher/pages/instance/LogPage.ui)2
-rw-r--r--launcher/ui/pages/instance/ModFolderPage.cpp (renamed from launcher/pages/instance/ModFolderPage.cpp)15
-rw-r--r--launcher/ui/pages/instance/ModFolderPage.h (renamed from launcher/pages/instance/ModFolderPage.h)7
-rw-r--r--launcher/ui/pages/instance/ModFolderPage.ui (renamed from launcher/pages/instance/ModFolderPage.ui)6
-rw-r--r--launcher/ui/pages/instance/NotesPage.cpp (renamed from launcher/pages/instance/NotesPage.cpp)0
-rw-r--r--launcher/ui/pages/instance/NotesPage.h (renamed from launcher/pages/instance/NotesPage.h)8
-rw-r--r--launcher/ui/pages/instance/NotesPage.ui (renamed from launcher/pages/instance/NotesPage.ui)0
-rw-r--r--launcher/ui/pages/instance/OtherLogsPage.cpp (renamed from launcher/pages/instance/OtherLogsPage.cpp)7
-rw-r--r--launcher/ui/pages/instance/OtherLogsPage.h (renamed from launcher/pages/instance/OtherLogsPage.h)6
-rw-r--r--launcher/ui/pages/instance/OtherLogsPage.ui (renamed from launcher/pages/instance/OtherLogsPage.ui)0
-rw-r--r--launcher/ui/pages/instance/ResourcePackPage.h (renamed from launcher/pages/instance/ResourcePackPage.h)0
-rw-r--r--launcher/ui/pages/instance/ScreenshotsPage.cpp (renamed from launcher/pages/instance/ScreenshotsPage.cpp)19
-rw-r--r--launcher/ui/pages/instance/ScreenshotsPage.h (renamed from launcher/pages/instance/ScreenshotsPage.h)6
-rw-r--r--launcher/ui/pages/instance/ScreenshotsPage.ui (renamed from launcher/pages/instance/ScreenshotsPage.ui)2
-rw-r--r--launcher/ui/pages/instance/ServersPage.cpp (renamed from launcher/pages/instance/ServersPage.cpp)4
-rw-r--r--launcher/ui/pages/instance/ServersPage.h (renamed from launcher/pages/instance/ServersPage.h)6
-rw-r--r--launcher/ui/pages/instance/ServersPage.ui (renamed from launcher/pages/instance/ServersPage.ui)2
-rw-r--r--launcher/ui/pages/instance/ShaderPackPage.h (renamed from launcher/pages/instance/ShaderPackPage.h)0
-rw-r--r--launcher/ui/pages/instance/TexturePackPage.h (renamed from launcher/pages/instance/TexturePackPage.h)0
-rw-r--r--launcher/ui/pages/instance/VersionPage.cpp (renamed from launcher/pages/instance/VersionPage.cpp)52
-rw-r--r--launcher/ui/pages/instance/VersionPage.h (renamed from launcher/pages/instance/VersionPage.h)2
-rw-r--r--launcher/ui/pages/instance/VersionPage.ui (renamed from launcher/pages/instance/VersionPage.ui)6
-rw-r--r--launcher/ui/pages/instance/WorldListPage.cpp (renamed from launcher/pages/instance/WorldListPage.cpp)22
-rw-r--r--launcher/ui/pages/instance/WorldListPage.h (renamed from launcher/pages/instance/WorldListPage.h)6
-rw-r--r--launcher/ui/pages/instance/WorldListPage.ui (renamed from launcher/pages/instance/WorldListPage.ui)2
-rw-r--r--launcher/ui/pages/modplatform/ImportPage.cpp (renamed from launcher/pages/modplatform/ImportPage.cpp)8
-rw-r--r--launcher/ui/pages/modplatform/ImportPage.h (renamed from launcher/pages/modplatform/ImportPage.h)6
-rw-r--r--launcher/ui/pages/modplatform/ImportPage.ui (renamed from launcher/pages/modplatform/ImportPage.ui)0
-rw-r--r--launcher/ui/pages/modplatform/VanillaPage.cpp (renamed from launcher/pages/modplatform/VanillaPage.cpp)17
-rw-r--r--launcher/ui/pages/modplatform/VanillaPage.h (renamed from launcher/pages/modplatform/VanillaPage.h)6
-rw-r--r--launcher/ui/pages/modplatform/VanillaPage.ui (renamed from launcher/pages/modplatform/VanillaPage.ui)2
-rw-r--r--launcher/ui/pages/modplatform/atlauncher/AtlFilterModel.cpp (renamed from launcher/pages/modplatform/atlauncher/AtlFilterModel.cpp)0
-rw-r--r--launcher/ui/pages/modplatform/atlauncher/AtlFilterModel.h (renamed from launcher/pages/modplatform/atlauncher/AtlFilterModel.h)0
-rw-r--r--launcher/ui/pages/modplatform/atlauncher/AtlListModel.cpp (renamed from launcher/pages/modplatform/atlauncher/AtlListModel.cpp)13
-rw-r--r--launcher/ui/pages/modplatform/atlauncher/AtlListModel.h (renamed from launcher/pages/modplatform/atlauncher/AtlListModel.h)2
-rw-r--r--launcher/ui/pages/modplatform/atlauncher/AtlOptionalModDialog.cpp (renamed from launcher/pages/modplatform/atlauncher/AtlOptionalModDialog.cpp)0
-rw-r--r--launcher/ui/pages/modplatform/atlauncher/AtlOptionalModDialog.h (renamed from launcher/pages/modplatform/atlauncher/AtlOptionalModDialog.h)0
-rw-r--r--launcher/ui/pages/modplatform/atlauncher/AtlOptionalModDialog.ui (renamed from launcher/pages/modplatform/atlauncher/AtlOptionalModDialog.ui)2
-rw-r--r--launcher/ui/pages/modplatform/atlauncher/AtlPage.cpp (renamed from launcher/pages/modplatform/atlauncher/AtlPage.cpp)10
-rw-r--r--launcher/ui/pages/modplatform/atlauncher/AtlPage.h (renamed from launcher/pages/modplatform/atlauncher/AtlPage.h)6
-rw-r--r--launcher/ui/pages/modplatform/atlauncher/AtlPage.ui (renamed from launcher/pages/modplatform/atlauncher/AtlPage.ui)0
-rw-r--r--launcher/ui/pages/modplatform/flame/FlameModel.cpp (renamed from launcher/pages/modplatform/flame/FlameModel.cpp)13
-rw-r--r--launcher/ui/pages/modplatform/flame/FlameModel.h (renamed from launcher/pages/modplatform/flame/FlameModel.h)2
-rw-r--r--launcher/ui/pages/modplatform/flame/FlamePage.cpp (renamed from launcher/pages/modplatform/flame/FlamePage.cpp)15
-rw-r--r--launcher/ui/pages/modplatform/flame/FlamePage.h (renamed from launcher/pages/modplatform/flame/FlamePage.h)6
-rw-r--r--launcher/ui/pages/modplatform/flame/FlamePage.ui (renamed from launcher/pages/modplatform/flame/FlamePage.ui)0
-rw-r--r--launcher/ui/pages/modplatform/ftb/FtbFilterModel.cpp (renamed from launcher/pages/modplatform/ftb/FtbFilterModel.cpp)0
-rw-r--r--launcher/ui/pages/modplatform/ftb/FtbFilterModel.h (renamed from launcher/pages/modplatform/ftb/FtbFilterModel.h)0
-rw-r--r--launcher/ui/pages/modplatform/ftb/FtbListModel.cpp (renamed from launcher/pages/modplatform/ftb/FtbListModel.cpp)15
-rw-r--r--launcher/ui/pages/modplatform/ftb/FtbListModel.h (renamed from launcher/pages/modplatform/ftb/FtbListModel.h)4
-rw-r--r--launcher/ui/pages/modplatform/ftb/FtbPage.cpp (renamed from launcher/pages/modplatform/ftb/FtbPage.cpp)2
-rw-r--r--launcher/ui/pages/modplatform/ftb/FtbPage.h (renamed from launcher/pages/modplatform/ftb/FtbPage.h)6
-rw-r--r--launcher/ui/pages/modplatform/ftb/FtbPage.ui (renamed from launcher/pages/modplatform/ftb/FtbPage.ui)0
-rw-r--r--launcher/ui/pages/modplatform/legacy_ftb/ListModel.cpp (renamed from launcher/pages/modplatform/legacy_ftb/ListModel.cpp)11
-rw-r--r--launcher/ui/pages/modplatform/legacy_ftb/ListModel.h (renamed from launcher/pages/modplatform/legacy_ftb/ListModel.h)0
-rw-r--r--launcher/ui/pages/modplatform/legacy_ftb/Page.cpp (renamed from launcher/pages/modplatform/legacy_ftb/Page.cpp)12
-rw-r--r--launcher/ui/pages/modplatform/legacy_ftb/Page.h (renamed from launcher/pages/modplatform/legacy_ftb/Page.h)6
-rw-r--r--launcher/ui/pages/modplatform/legacy_ftb/Page.ui (renamed from launcher/pages/modplatform/legacy_ftb/Page.ui)0
-rw-r--r--launcher/ui/pages/modplatform/technic/TechnicData.h (renamed from launcher/pages/modplatform/technic/TechnicData.h)0
-rw-r--r--launcher/ui/pages/modplatform/technic/TechnicModel.cpp (renamed from launcher/pages/modplatform/technic/TechnicModel.cpp)13
-rw-r--r--launcher/ui/pages/modplatform/technic/TechnicModel.h (renamed from launcher/pages/modplatform/technic/TechnicModel.h)2
-rw-r--r--launcher/ui/pages/modplatform/technic/TechnicPage.cpp (renamed from launcher/pages/modplatform/technic/TechnicPage.cpp)13
-rw-r--r--launcher/ui/pages/modplatform/technic/TechnicPage.h (renamed from launcher/pages/modplatform/technic/TechnicPage.h)6
-rw-r--r--launcher/ui/pages/modplatform/technic/TechnicPage.ui (renamed from launcher/pages/modplatform/technic/TechnicPage.ui)2
-rw-r--r--launcher/ui/setupwizard/AnalyticsWizardPage.cpp (renamed from launcher/setupwizard/AnalyticsWizardPage.cpp)6
-rw-r--r--launcher/ui/setupwizard/AnalyticsWizardPage.h (renamed from launcher/setupwizard/AnalyticsWizardPage.h)0
-rw-r--r--launcher/ui/setupwizard/BaseWizardPage.h (renamed from launcher/setupwizard/BaseWizardPage.h)0
-rw-r--r--launcher/ui/setupwizard/JavaWizardPage.cpp (renamed from launcher/setupwizard/JavaWizardPage.cpp)24
-rw-r--r--launcher/ui/setupwizard/JavaWizardPage.h (renamed from launcher/setupwizard/JavaWizardPage.h)0
-rw-r--r--launcher/ui/setupwizard/LanguageWizardPage.cpp (renamed from launcher/setupwizard/LanguageWizardPage.cpp)8
-rw-r--r--launcher/ui/setupwizard/LanguageWizardPage.h (renamed from launcher/setupwizard/LanguageWizardPage.h)0
-rw-r--r--launcher/ui/setupwizard/SetupWizard.cpp (renamed from launcher/setupwizard/SetupWizard.cpp)2
-rw-r--r--launcher/ui/setupwizard/SetupWizard.h (renamed from launcher/setupwizard/SetupWizard.h)0
-rw-r--r--launcher/ui/themes/BrightTheme.cpp (renamed from launcher/themes/BrightTheme.cpp)0
-rw-r--r--launcher/ui/themes/BrightTheme.h (renamed from launcher/themes/BrightTheme.h)0
-rw-r--r--launcher/ui/themes/CustomTheme.cpp (renamed from launcher/themes/CustomTheme.cpp)0
-rw-r--r--launcher/ui/themes/CustomTheme.h (renamed from launcher/themes/CustomTheme.h)0
-rw-r--r--launcher/ui/themes/DarkTheme.cpp (renamed from launcher/themes/DarkTheme.cpp)0
-rw-r--r--launcher/ui/themes/DarkTheme.h (renamed from launcher/themes/DarkTheme.h)0
-rw-r--r--launcher/ui/themes/FusionTheme.cpp (renamed from launcher/themes/FusionTheme.cpp)0
-rw-r--r--launcher/ui/themes/FusionTheme.h (renamed from launcher/themes/FusionTheme.h)0
-rw-r--r--launcher/ui/themes/ITheme.cpp (renamed from launcher/themes/ITheme.cpp)6
-rw-r--r--launcher/ui/themes/ITheme.h (renamed from launcher/themes/ITheme.h)0
-rw-r--r--launcher/ui/themes/SystemTheme.cpp (renamed from launcher/themes/SystemTheme.cpp)0
-rw-r--r--launcher/ui/themes/SystemTheme.h (renamed from launcher/themes/SystemTheme.h)0
-rw-r--r--launcher/ui/widgets/Common.cpp (renamed from launcher/widgets/Common.cpp)0
-rw-r--r--launcher/ui/widgets/Common.h (renamed from launcher/widgets/Common.h)0
-rw-r--r--launcher/ui/widgets/CustomCommands.cpp (renamed from launcher/widgets/CustomCommands.cpp)0
-rw-r--r--launcher/ui/widgets/CustomCommands.h (renamed from launcher/widgets/CustomCommands.h)0
-rw-r--r--launcher/ui/widgets/CustomCommands.ui (renamed from launcher/widgets/CustomCommands.ui)0
-rw-r--r--launcher/ui/widgets/DropLabel.cpp (renamed from launcher/widgets/DropLabel.cpp)0
-rw-r--r--launcher/ui/widgets/DropLabel.h (renamed from launcher/widgets/DropLabel.h)0
-rw-r--r--launcher/ui/widgets/ErrorFrame.cpp134
-rw-r--r--launcher/ui/widgets/ErrorFrame.h49
-rw-r--r--launcher/ui/widgets/ErrorFrame.ui92
-rw-r--r--launcher/ui/widgets/FocusLineEdit.cpp (renamed from launcher/widgets/FocusLineEdit.cpp)0
-rw-r--r--launcher/ui/widgets/FocusLineEdit.h (renamed from launcher/widgets/FocusLineEdit.h)0
-rw-r--r--launcher/ui/widgets/IconLabel.cpp (renamed from launcher/widgets/IconLabel.cpp)0
-rw-r--r--launcher/ui/widgets/IconLabel.h (renamed from launcher/widgets/IconLabel.h)0
-rw-r--r--launcher/ui/widgets/InstanceCardWidget.ui (renamed from launcher/widgets/InstanceCardWidget.ui)0
-rw-r--r--launcher/ui/widgets/JavaSettingsWidget.cpp (renamed from launcher/widgets/JavaSettingsWidget.cpp)31
-rw-r--r--launcher/ui/widgets/JavaSettingsWidget.h (renamed from launcher/widgets/JavaSettingsWidget.h)0
-rw-r--r--launcher/ui/widgets/LabeledToolButton.cpp (renamed from launcher/widgets/LabeledToolButton.cpp)0
-rw-r--r--launcher/ui/widgets/LabeledToolButton.h (renamed from launcher/widgets/LabeledToolButton.h)0
-rw-r--r--launcher/ui/widgets/LanguageSelectionWidget.cpp (renamed from launcher/widgets/LanguageSelectionWidget.cpp)8
-rw-r--r--launcher/ui/widgets/LanguageSelectionWidget.h (renamed from launcher/widgets/LanguageSelectionWidget.h)0
-rw-r--r--launcher/ui/widgets/LineSeparator.cpp (renamed from launcher/widgets/LineSeparator.cpp)0
-rw-r--r--launcher/ui/widgets/LineSeparator.h (renamed from launcher/widgets/LineSeparator.h)0
-rw-r--r--launcher/ui/widgets/LogView.cpp (renamed from launcher/widgets/LogView.cpp)0
-rw-r--r--launcher/ui/widgets/LogView.h (renamed from launcher/widgets/LogView.h)0
-rw-r--r--launcher/ui/widgets/MCModInfoFrame.cpp (renamed from launcher/widgets/MCModInfoFrame.cpp)3
-rw-r--r--launcher/ui/widgets/MCModInfoFrame.h (renamed from launcher/widgets/MCModInfoFrame.h)0
-rw-r--r--launcher/ui/widgets/MCModInfoFrame.ui (renamed from launcher/widgets/MCModInfoFrame.ui)0
-rw-r--r--launcher/ui/widgets/ModListView.cpp (renamed from launcher/widgets/ModListView.cpp)0
-rw-r--r--launcher/ui/widgets/ModListView.h (renamed from launcher/widgets/ModListView.h)0
-rw-r--r--launcher/ui/widgets/PageContainer.cpp (renamed from launcher/widgets/PageContainer.cpp)17
-rw-r--r--launcher/ui/widgets/PageContainer.h (renamed from launcher/widgets/PageContainer.h)4
-rw-r--r--launcher/ui/widgets/PageContainer_p.h (renamed from launcher/widgets/PageContainer_p.h)0
-rw-r--r--launcher/ui/widgets/ProgressWidget.cpp (renamed from launcher/widgets/ProgressWidget.cpp)0
-rw-r--r--launcher/ui/widgets/ProgressWidget.h (renamed from launcher/widgets/ProgressWidget.h)0
-rw-r--r--launcher/ui/widgets/VersionListView.cpp (renamed from launcher/widgets/VersionListView.cpp)1
-rw-r--r--launcher/ui/widgets/VersionListView.h (renamed from launcher/widgets/VersionListView.h)0
-rw-r--r--launcher/ui/widgets/VersionSelectWidget.cpp (renamed from launcher/widgets/VersionSelectWidget.cpp)9
-rw-r--r--launcher/ui/widgets/VersionSelectWidget.h (renamed from launcher/widgets/VersionSelectWidget.h)0
-rw-r--r--launcher/ui/widgets/WideBar.cpp (renamed from launcher/widgets/WideBar.cpp)0
-rw-r--r--launcher/ui/widgets/WideBar.h (renamed from launcher/widgets/WideBar.h)0
-rw-r--r--launcher/updater/DownloadTask.cpp14
-rw-r--r--launcher/updater/DownloadTask.h9
-rw-r--r--launcher/updater/GoUpdate.cpp2
-rw-r--r--launcher/updater/GoUpdate.h2
-rw-r--r--launcher/updater/UpdateChecker.cpp38
-rw-r--r--launcher/updater/UpdateChecker.h8
-rw-r--r--launcher/updater/UpdateChecker_test.cpp6
-rw-r--r--libraries/LocalPeer/CMakeLists.txt3
-rw-r--r--libraries/katabasis/CMakeLists.txt6
-rw-r--r--libraries/katabasis/include/katabasis/Bits.h6
-rw-r--r--libraries/katabasis/include/katabasis/DeviceFlow.h150
-rw-r--r--libraries/katabasis/include/katabasis/OAuth2.h233
-rw-r--r--libraries/katabasis/include/katabasis/Reply.h7
-rw-r--r--libraries/katabasis/include/katabasis/ReplyServer.h53
-rw-r--r--libraries/katabasis/src/DeviceFlow.cpp451
-rw-r--r--libraries/katabasis/src/OAuth2.cpp672
-rw-r--r--libraries/katabasis/src/Reply.cpp17
-rwxr-xr-xlibraries/katabasis/src/ReplyServer.cpp182
421 files changed, 5700 insertions, 4921 deletions
diff --git a/.gitignore b/.gitignore
index f0336b63..69dda72c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,6 +21,10 @@ Debug
build
/build-*
+# Install dirs
+install
+/install-*
+
# Ctags File
tags
diff --git a/BUILD.md b/BUILD.md
index 838b48c6..b4ba173c 100644
--- a/BUILD.md
+++ b/BUILD.md
@@ -194,7 +194,7 @@ cmake \
-DCMAKE_C_COMPILER=/usr/bin/clang \
-DCMAKE_CXX_COMPILER=/usr/bin/clang++ \
-DCMAKE_BUILD_TYPE=Release \
- -DCMAKE_INSTALL_PREFIX:PATH="../dist/" \
+ -DCMAKE_INSTALL_PREFIX:PATH="$(dirname $PWD)/dist/" \
-DCMAKE_PREFIX_PATH="/path/to/Qt5.6/" \
-DQt5_DIR="/path/to/Qt5.6/" \
-DLauncher_LAYOUT=mac-bundle \
@@ -202,3 +202,6 @@ cmake \
..
make install
```
+
+**Note:** The final app bundle may not run due to code signing issues, which
+need to be fixed with `codesign -fs -`.
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0cf93758..a0a8c5ec 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -55,7 +55,7 @@ set(Launcher_NEWS_RSS_URL "https://multimc.org/rss.xml" CACHE STRING "URL to fet
######## Set version numbers ########
set(Launcher_VERSION_MAJOR 0)
set(Launcher_VERSION_MINOR 6)
-set(Launcher_VERSION_HOTFIX 13)
+set(Launcher_VERSION_HOTFIX 14)
# Build number
set(Launcher_VERSION_BUILD -1 CACHE STRING "Build number. -1 for no build number.")
@@ -186,7 +186,7 @@ if(Launcher_LAYOUT_REAL STREQUAL "mac-bundle")
set(INSTALL_BUNDLE "full")
# Add the icon
- install(FILES ${Launcher_Branding_ICNS} DESTINATION ${RESOURCES_DEST_DIR})
+ install(FILES ${Launcher_Branding_ICNS} DESTINATION ${RESOURCES_DEST_DIR} RENAME ${Launcher_Name}.icns)
elseif(Launcher_LAYOUT_REAL STREQUAL "lin-nodeps")
set(BINARY_DEST_DIR "bin")
diff --git a/changelog.md b/changelog.md
index b2cbdd81..7b1d4ae8 100644
--- a/changelog.md
+++ b/changelog.md
@@ -1,4 +1,69 @@
-# MultiMC 0.6.13
+# MultiMC 0.6.14
+
+This further refines Microsoft account support, along with small fixes related to modpack platforms and Java runtime detection.
+
+It's also been 10 years since the first release of MultiMC. All background cats are now ready to party!
+
+### Microsoft accounts
+
+The account system now refreshes accounts in the background while the application is running.
+
+- GH-4071: Errors encountered while refreshing account tokens no longer always result in the tokens expiring:
+ - Network errors encountered when refreshing the main account tokens result in the account being **Offline**.
+ - **Hard** errors are produced by the main tokens becoming provably invalid.
+ - Errors encountered later are treated as **Soft** - they do make the account unusable, but still recoverable by trying again.
+ - **Soft** errors are treated as **Hard** errors when adding the account initially.
+
+In general, this should make MultiMC much more forgiving towards various temporary and non-fatal errors.
+
+- GH-4217: Added support for GamePass accounts and Minecraft profile setup:
+ - The new endpoint for logging in with Microsoft is now used (`/launcher/login`), enabling compatibility with GamePass.
+ - Game ownership is checked instead of only relying on Minecraft profile presence.
+ - Accounts can now be added even when they do not have a profile.
+ - The launcher should guide you through selecting a Minecraft name if you don't have one yet.
+
+### Modpack platform changes
+
+- GH-4055: MultiMC now tries to avoid downloading multiple files to the same path for FTB modpacks.
+
+- Search as you type is now used for FTB.
+
+- GH-4185: Version of the modpack is now included in the name of the instance by default.
+
+- The modpack platform UIs now include text field clear buttons.
+
+### Other changes
+
+- Adjusted warnings about Java runtime required for Minecraft 1.18 (it's not Java 16, it's Java 17).
+
+- GH-3490: Instance sorting is now aware of numbers (and sorts 99 before 100).
+
+- GH-4164: Reimplemented assigning instances to groups using drag & drop.
+
+- GH-1795: Added terminal launch option to use a specific Minecraft profile (in-game player name).
+
+ Used like this:
+ ```
+ ./MultiMC --launch 1.17.1 --profile MultiMCTest --server mc.hypixel.net
+ ```
+
+- GH-4227: Fix crash related to invalid Forge mod metadata.
+
+- GH-4200: Search for the *Eclipse Foundation* and *Adoptium* Java runtimes in the Windows Registry.
+
+- Added shader packs page to instances.
+
+- Removed Mojang services status information from the main window - the status is no longer provided by Mojang.
+
+- It is now possible to turn of global tracking of play time.
+
+### Technical changes
+
+- Debranding is mostly finished. You may see some changes in the logo being used in less places.
+
+# Previous releases
+
+## MultiMC 0.6.13
This release brings initial support for Microsoft accounts, along with a nice pile of modpack platform support changes and improved Java runtime detection.
@@ -6,7 +71,7 @@ Java runtimes still need an overhaul, so we're staying on the 0.6 version for a
Next release should also tackle the current Forge 1.17.x issues in a systematic way.
-### Microsoft accounts
+#### Microsoft accounts
This is the first release with Microsoft accounts in.
@@ -24,7 +89,7 @@ As part of this, the skin fetching no longer uses a third party service and inst
Capes can also be selected in MultiMC now. With how many people will now get one for migrating their accounts, it only makes sense.
-### macOS update
+#### macOS update
Because of issues with the Microsoft accounts, we now have two builds on macOS:
@@ -36,7 +101,7 @@ MultiMC will update to the 5.15.2 builds when it detects that this is possible.
Similar approach got attempted on Windows, aiming to fix various display scaling and theming issues, but it ran into too many problems and will be attempted later, with more caution.
-### Modpack platforms
+#### Modpack platforms
In general, the modpack platform pages have been made more consistent with each other (GH-3118, GH-3720, GH-3731).
@@ -77,7 +142,7 @@ In general, the modpack platform pages have been made more consistent with each
- Fixed bugs in FTB platform search.
-### Other changes
+#### Other changes
- Forge installation is disabled on Minecraft 1.17+ because of incompatible/unresolved changes on the Forge side.
@@ -117,11 +182,10 @@ In general, the modpack platform pages have been made more consistent with each
- Quick and dirty minimum Java runtime versions checks have been added. This needs to be expanded in the future.
-### Technical changes
+#### Technical changes
- The codebase continues to move towards being debranded and harder to build as 'MultiMC' for third parties.
-# Previous releases
## MultiMC 0.6.12
diff --git a/launcher/Launcher.cpp b/launcher/Application.cpp
index a69fb8f3..2d0c81bb 100644
--- a/launcher/Launcher.cpp
+++ b/launcher/Application.cpp
@@ -1,36 +1,42 @@
-#include "Launcher.h"
+#include "Application.h"
#include "BuildConfig.h"
-#include "MainWindow.h"
-#include "InstanceWindow.h"
-#include "instanceview/AccessibleInstanceView.h"
-#include <QAccessible>
+#include "ui/MainWindow.h"
+#include "ui/InstanceWindow.h"
+
+#include "ui/instanceview/AccessibleInstanceView.h"
+
+#include "ui/pages/BasePageProvider.h"
+#include "ui/pages/global/LauncherPage.h"
+#include "ui/pages/global/MinecraftPage.h"
+#include "ui/pages/global/JavaPage.h"
+#include "ui/pages/global/LanguagePage.h"
+#include "ui/pages/global/ProxyPage.h"
+#include "ui/pages/global/ExternalToolsPage.h"
+#include "ui/pages/global/AccountListPage.h"
+#include "ui/pages/global/PasteEEPage.h"
+#include "ui/pages/global/CustomCommandsPage.h"
+
+#include "ui/themes/ITheme.h"
+#include "ui/themes/SystemTheme.h"
+#include "ui/themes/DarkTheme.h"
+#include "ui/themes/BrightTheme.h"
+#include "ui/themes/CustomTheme.h"
-#include "pages/BasePageProvider.h"
-#include "pages/global/LauncherPage.h"
-#include "pages/global/MinecraftPage.h"
-#include "pages/global/JavaPage.h"
-#include "pages/global/LanguagePage.h"
-#include "pages/global/ProxyPage.h"
-#include "pages/global/ExternalToolsPage.h"
-#include "pages/global/AccountListPage.h"
-#include "pages/global/PasteEEPage.h"
-#include "pages/global/CustomCommandsPage.h"
-
-#include "themes/ITheme.h"
-#include "themes/SystemTheme.h"
-#include "themes/DarkTheme.h"
-#include "themes/BrightTheme.h"
-#include "themes/CustomTheme.h"
-
-#include "LauncherMessage.h"
-
-#include "setupwizard/SetupWizard.h"
-#include "setupwizard/LanguageWizardPage.h"
-#include "setupwizard/JavaWizardPage.h"
-#include "setupwizard/AnalyticsWizardPage.h"
+#include "ui/setupwizard/SetupWizard.h"
+#include "ui/setupwizard/LanguageWizardPage.h"
+#include "ui/setupwizard/JavaWizardPage.h"
+#include "ui/setupwizard/AnalyticsWizardPage.h"
+
+#include "ui/dialogs/CustomMessageBox.h"
+
+#include "ui/pagedialog/PageDialog.h"
+
+#include "ApplicationMessage.h"
#include <iostream>
+
+#include <QAccessible>
#include <QDir>
#include <QFileInfo>
#include <QNetworkAccessManager>
@@ -41,13 +47,11 @@
#include <QDebug>
#include <QStyleFactory>
-#include "dialogs/CustomMessageBox.h"
#include "InstanceList.h"
#include <minecraft/auth/AccountList.h>
#include "icons/IconList.h"
#include "net/HttpMetaCache.h"
-#include "Env.h"
#include "java/JavaUtils.h"
@@ -62,6 +66,7 @@
#include "settings/Setting.h"
#include "translations/TranslationsModel.h"
+#include "meta/Index.h"
#include <Commandline.h>
#include <FileSystem.h>
@@ -71,7 +76,7 @@
#include <ganalytics.h>
#include <sys.h>
-#include "pagedialog/PageDialog.h"
+#include <Secrets.h>
#if defined Q_OS_WIN32
@@ -99,7 +104,7 @@ void appDebugOutput(QtMsgType type, const QMessageLogContext &context, const QSt
const char *levels = "DWCFIS";
const QString format("%1 %2 %3\n");
- qint64 msecstotal = LAUNCHER->timeSinceStart();
+ qint64 msecstotal = APPLICATION->timeSinceStart();
qint64 seconds = msecstotal / 1000;
qint64 msecs = msecstotal % 1000;
QString foo;
@@ -108,8 +113,8 @@ void appDebugOutput(QtMsgType type, const QMessageLogContext &context, const QSt
QString out = format.arg(buf).arg(levels[type]).arg(msg);
- LAUNCHER->logFile->write(out.toUtf8());
- LAUNCHER->logFile->flush();
+ APPLICATION->logFile->write(out.toUtf8());
+ APPLICATION->logFile->flush();
QTextStream(stderr) << out.toLocal8Bit();
fflush(stderr);
}
@@ -155,7 +160,7 @@ QString getIdealPlatform(QString currentPlatform) {
}
-Launcher::Launcher(int &argc, char **argv) : QApplication(argc, argv)
+Application::Application(int &argc, char **argv) : QApplication(argc, argv)
{
#if defined Q_OS_WIN32
// attach the parent console
@@ -261,7 +266,7 @@ Launcher::Launcher(int &argc, char **argv) : QApplication(argc, argv)
if(argc > 0)
std::cerr << "Try '" << argv[0] << " -h' to get help on command line parameters."
<< std::endl;
- m_status = Launcher::Failed;
+ m_status = Application::Failed;
return;
}
@@ -269,7 +274,7 @@ Launcher::Launcher(int &argc, char **argv) : QApplication(argc, argv)
if (args["help"].toBool())
{
std::cout << qPrintable(parser.compileHelp(arguments()[0]));
- m_status = Launcher::Succeeded;
+ m_status = Application::Succeeded;
return;
}
@@ -278,7 +283,7 @@ Launcher::Launcher(int &argc, char **argv) : QApplication(argc, argv)
{
std::cout << "Version " << BuildConfig.printableVersionString().toStdString() << std::endl;
std::cout << "Git " << BuildConfig.GIT_COMMIT.toStdString() << std::endl;
- m_status = Launcher::Succeeded;
+ m_status = Application::Succeeded;
return;
}
}
@@ -347,14 +352,14 @@ Launcher::Launcher(int &argc, char **argv) : QApplication(argc, argv)
if(m_instanceIdToLaunch.isEmpty() && !m_serverToJoin.isEmpty())
{
std::cerr << "--server can only be used in combination with --launch!" << std::endl;
- m_status = Launcher::Failed;
+ m_status = Application::Failed;
return;
}
if(m_instanceIdToLaunch.isEmpty() && !m_profileToUse.isEmpty())
{
std::cerr << "--account can only be used in combination with --launch!" << std::endl;
- m_status = Launcher::Failed;
+ m_status = Application::Failed;
return;
}
@@ -430,19 +435,19 @@ Launcher::Launcher(int &argc, char **argv) : QApplication(argc, argv)
{
// FIXME: you can run the same binaries with multiple data dirs and they won't clash. This could cause issues for updates.
m_peerInstance = new LocalPeer(this, appID);
- connect(m_peerInstance, &LocalPeer::messageReceived, this, &Launcher::messageReceived);
+ connect(m_peerInstance, &LocalPeer::messageReceived, this, &Application::messageReceived);
if(m_peerInstance->isClient()) {
int timeout = 2000;
if(m_instanceIdToLaunch.isEmpty())
{
- LauncherMessage activate;
+ ApplicationMessage activate;
activate.command = "activate";
m_peerInstance->sendMessage(activate.serialize(), timeout);
if(!m_zipToImport.isEmpty())
{
- LauncherMessage import;
+ ApplicationMessage import;
import.command = "import";
import.args.insert("path", m_zipToImport.toString());
m_peerInstance->sendMessage(import.serialize(), timeout);
@@ -450,7 +455,7 @@ Launcher::Launcher(int &argc, char **argv) : QApplication(argc, argv)
}
else
{
- LauncherMessage launch;
+ ApplicationMessage launch;
launch.command = "launch";
launch.args["id"] = m_instanceIdToLaunch;
@@ -464,7 +469,7 @@ Launcher::Launcher(int &argc, char **argv) : QApplication(argc, argv)
}
m_peerInstance->sendMessage(launch.serialize(), timeout);
}
- m_status = Launcher::Succeeded;
+ m_status = Application::Succeeded;
return;
}
}
@@ -519,10 +524,6 @@ Launcher::Launcher(int &argc, char **argv) : QApplication(argc, argv)
FS::updateTimestamp(m_rootPath);
#endif
-#ifdef MULTIMC_JARS_LOCATION
- ENV.setJarsPath( TOSTRING(MULTIMC_JARS_LOCATION) );
-#endif
-
qDebug() << BuildConfig.LAUNCHER_DISPLAYNAME << ", (c) 2013-2021 " << BuildConfig.LAUNCHER_COPYRIGHT;
qDebug() << "Version : " << BuildConfig.printableVersionString();
qDebug() << "Git commit : " << BuildConfig.GIT_COMMIT;
@@ -729,6 +730,18 @@ Launcher::Launcher(int &argc, char **argv) : QApplication(argc, argv)
QAccessible::installFactory(groupViewAccessibleFactory);
#endif /* !QT_NO_ACCESSIBILITY */
+ // initialize network access and proxy setup
+ {
+ m_network = new QNetworkAccessManager();
+ QString proxyTypeStr = settings()->get("ProxyType").toString();
+ QString addr = settings()->get("ProxyAddr").toString();
+ int port = settings()->get("ProxyPort").value<qint16>();
+ QString user = settings()->get("ProxyUser").toString();
+ QString pass = settings()->get("ProxyPass").toString();
+ updateProxySettings(proxyTypeStr, addr, port, user, pass);
+ qDebug() << "<> Network done.";
+ }
+
// load translations
{
m_translations.reset(new TranslationsModel("translations"));
@@ -744,13 +757,13 @@ Launcher::Launcher(int &argc, char **argv) : QApplication(argc, argv)
auto platform = getIdealPlatform(BuildConfig.BUILD_PLATFORM);
auto channelUrl = BuildConfig.UPDATER_BASE + platform + "/channels.json";
qDebug() << "Initializing updater with platform: " << platform << " -- " << channelUrl;
- m_updateChecker.reset(new UpdateChecker(channelUrl, BuildConfig.VERSION_CHANNEL, BuildConfig.VERSION_BUILD));
+ m_updateChecker.reset(new UpdateChecker(m_network, channelUrl, BuildConfig.VERSION_CHANNEL, BuildConfig.VERSION_BUILD));
qDebug() << "<> Updater started.";
}
// Instance icons
{
- auto setting = LAUNCHER->settings()->getSetting("IconsDir");
+ auto setting = APPLICATION->settings()->getSetting("IconsDir");
QStringList instFolders =
{
":/icons/multimc/32x32/instances/",
@@ -763,7 +776,6 @@ Launcher::Launcher(int &argc, char **argv) : QApplication(argc, argv)
{
m_icons->directoryChanged(value.toString());
});
- ENV.registerIconList(m_icons);
qDebug() << "<> Instance icons intialized.";
}
@@ -815,26 +827,34 @@ Launcher::Launcher(int &argc, char **argv) : QApplication(argc, argv)
qDebug() << "Loading accounts...";
m_accounts->setListFilePath("accounts.json", true);
m_accounts->loadList();
+ m_accounts->fillQueue();
qDebug() << "<> Accounts loaded.";
}
// init the http meta cache
{
- ENV.initHttpMetaCache();
+ m_metacache.reset(new HttpMetaCache("metacache"));
+ m_metacache->addBase("asset_indexes", QDir("assets/indexes").absolutePath());
+ m_metacache->addBase("asset_objects", QDir("assets/objects").absolutePath());
+ m_metacache->addBase("versions", QDir("versions").absolutePath());
+ m_metacache->addBase("libraries", QDir("libraries").absolutePath());
+ m_metacache->addBase("minecraftforge", QDir("mods/minecraftforge").absolutePath());
+ m_metacache->addBase("fmllibs", QDir("mods/minecraftforge/libs").absolutePath());
+ m_metacache->addBase("liteloader", QDir("mods/liteloader").absolutePath());
+ m_metacache->addBase("general", QDir("cache").absolutePath());
+ m_metacache->addBase("ATLauncherPacks", QDir("cache/ATLauncherPacks").absolutePath());
+ m_metacache->addBase("FTBPacks", QDir("cache/FTBPacks").absolutePath());
+ m_metacache->addBase("ModpacksCHPacks", QDir("cache/ModpacksCHPacks").absolutePath());
+ m_metacache->addBase("TechnicPacks", QDir("cache/TechnicPacks").absolutePath());
+ m_metacache->addBase("FlamePacks", QDir("cache/FlamePacks").absolutePath());
+ m_metacache->addBase("root", QDir::currentPath());
+ m_metacache->addBase("translations", QDir("translations").absolutePath());
+ m_metacache->addBase("icons", QDir("cache/icons").absolutePath());
+ m_metacache->addBase("meta", QDir("meta").absolutePath());
+ m_metacache->Load();
qDebug() << "<> Cache initialized.";
}
- // init proxy settings
- {
- QString proxyTypeStr = settings()->get("ProxyType").toString();
- QString addr = settings()->get("ProxyAddr").toString();
- int port = settings()->get("ProxyPort").value<qint16>();
- QString user = settings()->get("ProxyUser").toString();
- QString pass = settings()->get("ProxyPass").toString();
- ENV.updateProxySettings(proxyTypeStr, addr, port, user, pass);
- qDebug() << "<> Proxy settings done.";
- }
-
// now we have network, download translation updates
m_translations->downloadIndex();
@@ -851,7 +871,7 @@ Launcher::Launcher(int &argc, char **argv) : QApplication(argc, argv)
m_mcedit.reset(new MCEditTool(m_settings));
}
- connect(this, &Launcher::aboutToQuit, [this](){
+ connect(this, &Application::aboutToQuit, [this](){
if(m_instances)
{
// save any remaining instance state
@@ -881,7 +901,7 @@ Launcher::Launcher(int &argc, char **argv) : QApplication(argc, argv)
}
auto analyticsSetting = m_settings->getSetting("Analytics");
- connect(analyticsSetting.get(), &Setting::SettingChanged, this, &Launcher::analyticsSettingChanged);
+ connect(analyticsSetting.get(), &Setting::SettingChanged, this, &Application::analyticsSettingChanged);
QString clientID = m_settings->get("AnalyticsClientID").toString();
if(clientID.isEmpty())
{
@@ -893,7 +913,8 @@ Launcher::Launcher(int &argc, char **argv) : QApplication(argc, argv)
m_analytics = new GAnalytics(BuildConfig.ANALYTICS_ID, clientID, analyticsVersion, this);
m_analytics->setLogLevel(GAnalytics::Debug);
m_analytics->setAnonymizeIPs(true);
- m_analytics->setNetworkAccessManager(&ENV.qnam());
+ // FIXME: the ganalytics library has no idea about our fancy shared pointers...
+ m_analytics->setNetworkAccessManager(network().get());
if(m_settings->get("AnalyticsSeen").toInt() < m_analytics->version())
{
@@ -917,7 +938,7 @@ Launcher::Launcher(int &argc, char **argv) : QApplication(argc, argv)
performMainStartupAction();
}
-bool Launcher::createSetupWizard()
+bool Application::createSetupWizard()
{
bool javaRequired = [&]()
{
@@ -975,22 +996,22 @@ bool Launcher::createSetupWizard()
{
m_setupWizard->addPage(new AnalyticsWizardPage(m_setupWizard));
}
- connect(m_setupWizard, &QDialog::finished, this, &Launcher::setupWizardFinished);
+ connect(m_setupWizard, &QDialog::finished, this, &Application::setupWizardFinished);
m_setupWizard->show();
return true;
}
return false;
}
-void Launcher::setupWizardFinished(int status)
+void Application::setupWizardFinished(int status)
{
qDebug() << "Wizard result =" << status;
performMainStartupAction();
}
-void Launcher::performMainStartupAction()
+void Application::performMainStartupAction()
{
- m_status = Launcher::Initialized;
+ m_status = Application::Initialized;
if(!m_instanceIdToLaunch.isEmpty())
{
auto inst = instances()->getInstanceById(m_instanceIdToLaunch);
@@ -1033,18 +1054,15 @@ void Launcher::performMainStartupAction()
}
}
-void Launcher::showFatalErrorMessage(const QString& title, const QString& content)
+void Application::showFatalErrorMessage(const QString& title, const QString& content)
{
- m_status = Launcher::Failed;
+ m_status = Application::Failed;
auto dialog = CustomMessageBox::selectable(nullptr, title, content, QMessageBox::Critical);
dialog->exec();
}
-Launcher::~Launcher()
+Application::~Application()
{
- // kill the other globals.
- Env::dispose();
-
// Shut down logger by setting the logger function to nothing
qInstallMessageHandler(nullptr);
@@ -1060,7 +1078,7 @@ Launcher::~Launcher()
#endif
}
-void Launcher::messageReceived(const QByteArray& message)
+void Application::messageReceived(const QByteArray& message)
{
if(status() != Initialized)
{
@@ -1068,7 +1086,7 @@ void Launcher::messageReceived(const QByteArray& message)
return;
}
- LauncherMessage received;
+ ApplicationMessage received;
received.parse(message);
auto & command = received.command;
@@ -1134,7 +1152,7 @@ void Launcher::messageReceived(const QByteArray& message)
}
}
-void Launcher::analyticsSettingChanged(const Setting&, QVariant value)
+void Application::analyticsSettingChanged(const Setting&, QVariant value)
{
if(!m_analytics)
return;
@@ -1150,12 +1168,12 @@ void Launcher::analyticsSettingChanged(const Setting&, QVariant value)
m_analytics->enable(enabled);
}
-std::shared_ptr<TranslationsModel> Launcher::translations()
+std::shared_ptr<TranslationsModel> Application::translations()
{
return m_translations;
}
-std::shared_ptr<JavaInstallList> Launcher::javalist()
+std::shared_ptr<JavaInstallList> Application::javalist()
{
if (!m_javalist)
{
@@ -1164,7 +1182,7 @@ std::shared_ptr<JavaInstallList> Launcher::javalist()
return m_javalist;
}
-std::vector<ITheme *> Launcher::getValidApplicationThemes()
+std::vector<ITheme *> Application::getValidApplicationThemes()
{
std::vector<ITheme *> ret;
auto iter = m_themes.cbegin();
@@ -1176,7 +1194,7 @@ std::vector<ITheme *> Launcher::getValidApplicationThemes()
return ret;
}
-void Launcher::setApplicationTheme(const QString& name, bool initial)
+void Application::setApplicationTheme(const QString& name, bool initial)
{
auto systemPalette = qApp->palette();
auto themeIter = m_themes.find(name);
@@ -1191,12 +1209,12 @@ void Launcher::setApplicationTheme(const QString& name, bool initial)
}
}
-void Launcher::setIconTheme(const QString& name)
+void Application::setIconTheme(const QString& name)
{
XdgIcon::setThemeName(name);
}
-QIcon Launcher::getThemedIcon(const QString& name)
+QIcon Application::getThemedIcon(const QString& name)
{
if(name == "logo") {
return QIcon(":/logo.svg");
@@ -1204,7 +1222,7 @@ QIcon Launcher::getThemedIcon(const QString& name)
return XdgIcon::fromTheme(name);
}
-bool Launcher::openJsonEditor(const QString &filename)
+bool Application::openJsonEditor(const QString &filename)
{
const QString file = QDir::current().absoluteFilePath(filename);
if (m_settings->get("JsonEditor").toString().isEmpty())
@@ -1218,7 +1236,7 @@ bool Launcher::openJsonEditor(const QString &filename)
}
}
-bool Launcher::launch(
+bool Application::launch(
InstancePtr instance,
bool online,
BaseProfilerFactory *profiler,
@@ -1255,8 +1273,8 @@ bool Launcher::launch(
{
controller->setParentWidget(m_mainWindow);
}
- connect(controller.get(), &LaunchController::succeeded, this, &Launcher::controllerSucceeded);
- connect(controller.get(), &LaunchController::failed, this, &Launcher::controllerFailed);
+ connect(controller.get(), &LaunchController::succeeded, this, &Application::controllerSucceeded);
+ connect(controller.get(), &LaunchController::failed, this, &Application::controllerFailed);
addRunningInstance();
controller->start();
return true;
@@ -1274,7 +1292,7 @@ bool Launcher::launch(
return false;
}
-bool Launcher::kill(InstancePtr instance)
+bool Application::kill(InstancePtr instance)
{
if (!instance->isRunning())
{
@@ -1291,7 +1309,7 @@ bool Launcher::kill(InstancePtr instance)
return true;
}
-void Launcher::addRunningInstance()
+void Application::addRunningInstance()
{
m_runningInstances ++;
if(m_runningInstances == 1)
@@ -1300,7 +1318,7 @@ void Launcher::addRunningInstance()
}
}
-void Launcher::subRunningInstance()
+void Application::subRunningInstance()
{
if(m_runningInstances == 0)
{
@@ -1314,23 +1332,23 @@ void Launcher::subRunningInstance()
}
}
-bool Launcher::shouldExitNow() const
+bool Application::shouldExitNow() const
{
return m_runningInstances == 0 && m_openWindows == 0;
}
-bool Launcher::updatesAreAllowed()
+bool Application::updatesAreAllowed()
{
return m_runningInstances == 0;
}
-void Launcher::updateIsRunning(bool running)
+void Application::updateIsRunning(bool running)
{
m_updateRunning = running;
}
-void Launcher::controllerSucceeded()
+void Application::controllerSucceeded()
{
auto controller = qobject_cast<LaunchController *>(QObject::sender());
if(!controller)
@@ -1357,7 +1375,7 @@ void Launcher::controllerSucceeded()
}
}
-void Launcher::controllerFailed(const QString& error)
+void Application::controllerFailed(const QString& error)
{
Q_UNUSED(error);
auto controller = qobject_cast<LaunchController *>(QObject::sender());
@@ -1378,21 +1396,21 @@ void Launcher::controllerFailed(const QString& error)
}
}
-void Launcher::ShowGlobalSettings(class QWidget* parent, QString open_page)
+void Application::ShowGlobalSettings(class QWidget* parent, QString open_page)
{
if(!m_globalSettingsProvider) {
return;
}
emit globalSettingsAboutToOpen();
{
- SettingsObject::Lock lock(LAUNCHER->settings());
+ SettingsObject::Lock lock(APPLICATION->settings());
PageDialog dlg(m_globalSettingsProvider.get(), open_page, parent);
dlg.exec();
}
emit globalSettingsClosed();
}
-MainWindow* Launcher::showMainWindow(bool minimized)
+MainWindow* Application::showMainWindow(bool minimized)
{
if(m_mainWindow)
{
@@ -1403,8 +1421,8 @@ MainWindow* Launcher::showMainWindow(bool minimized)
else
{
m_mainWindow = new MainWindow();
- m_mainWindow->restoreState(QByteArray::fromBase64(LAUNCHER->settings()->get("MainWindowState").toByteArray()));
- m_mainWindow->restoreGeometry(QByteArray::fromBase64(LAUNCHER->settings()->get("MainWindowGeometry").toByteArray()));
+ m_mainWindow->restoreState(QByteArray::fromBase64(APPLICATION->settings()->get("MainWindowState").toByteArray()));
+ m_mainWindow->restoreGeometry(QByteArray::fromBase64(APPLICATION->settings()->get("MainWindowGeometry").toByteArray()));
if(minimized)
{
m_mainWindow->showMinimized();
@@ -1415,8 +1433,8 @@ MainWindow* Launcher::showMainWindow(bool minimized)
}
m_mainWindow->checkInstancePathForProblems();
- connect(this, &Launcher::updateAllowedChanged, m_mainWindow, &MainWindow::updatesAllowedChanged);
- connect(m_mainWindow, &MainWindow::isClosing, this, &Launcher::on_windowClose);
+ connect(this, &Application::updateAllowedChanged, m_mainWindow, &MainWindow::updatesAllowedChanged);
+ connect(m_mainWindow, &MainWindow::isClosing, this, &Application::on_windowClose);
m_openWindows++;
}
// FIXME: move this somewhere else...
@@ -1476,7 +1494,7 @@ MainWindow* Launcher::showMainWindow(bool minimized)
return m_mainWindow;
}
-InstanceWindow *Launcher::showInstanceWindow(InstancePtr instance, QString page)
+InstanceWindow *Application::showInstanceWindow(InstancePtr instance, QString page)
{
if(!instance)
return nullptr;
@@ -1493,7 +1511,7 @@ InstanceWindow *Launcher::showInstanceWindow(InstancePtr instance, QString page)
{
window = new InstanceWindow(instance);
m_openWindows ++;
- connect(window, &InstanceWindow::isClosing, this, &Launcher::on_windowClose);
+ connect(window, &InstanceWindow::isClosing, this, &Application::on_windowClose);
}
if(!page.isEmpty())
{
@@ -1506,7 +1524,7 @@ InstanceWindow *Launcher::showInstanceWindow(InstancePtr instance, QString page)
return window;
}
-void Launcher::on_windowClose()
+void Application::on_windowClose()
{
m_openWindows--;
auto instWindow = qobject_cast<InstanceWindow *>(QObject::sender());
@@ -1530,3 +1548,96 @@ void Launcher::on_windowClose()
exit(0);
}
}
+
+QString Application::msaClientId() const {
+ return Secrets::getMSAClientID('-');
+}
+
+void Application::updateProxySettings(QString proxyTypeStr, QString addr, int port, QString user, QString password)
+{
+ // Set the application proxy settings.
+ if (proxyTypeStr == "SOCKS5")
+ {
+ QNetworkProxy::setApplicationProxy(
+ QNetworkProxy(QNetworkProxy::Socks5Proxy, addr, port, user, password));
+ }
+ else if (proxyTypeStr == "HTTP")
+ {
+ QNetworkProxy::setApplicationProxy(
+ QNetworkProxy(QNetworkProxy::HttpProxy, addr, port, user, password));
+ }
+ else if (proxyTypeStr == "None")
+ {
+ // If we have no proxy set, set no proxy and return.
+ QNetworkProxy::setApplicationProxy(QNetworkProxy(QNetworkProxy::NoProxy));
+ }
+ else
+ {
+ // If we have "Default" selected, set Qt to use the system proxy settings.
+ QNetworkProxyFactory::setUseSystemConfiguration(true);
+ }
+
+ qDebug() << "Detecting proxy settings...";
+ QNetworkProxy proxy = QNetworkProxy::applicationProxy();
+ m_network->setProxy(proxy);
+
+ QString proxyDesc;
+ if (proxy.type() == QNetworkProxy::NoProxy)
+ {
+ qDebug() << "Using no proxy is an option!";
+ return;
+ }
+ switch (proxy.type())
+ {
+ case QNetworkProxy::DefaultProxy:
+ proxyDesc = "Default proxy: ";
+ break;
+ case QNetworkProxy::Socks5Proxy:
+ proxyDesc = "Socks5 proxy: ";
+ break;
+ case QNetworkProxy::HttpProxy:
+ proxyDesc = "HTTP proxy: ";
+ break;
+ case QNetworkProxy::HttpCachingProxy:
+ proxyDesc = "HTTP caching: ";
+ break;
+ case QNetworkProxy::FtpCachingProxy:
+ proxyDesc = "FTP caching: ";
+ break;
+ default:
+ proxyDesc = "DERP proxy: ";
+ break;
+ }
+ proxyDesc += QString("%1:%2")
+ .arg(proxy.hostName())
+ .arg(proxy.port());
+ qDebug() << proxyDesc;
+}
+
+shared_qobject_ptr< HttpMetaCache > Application::metacache()
+{
+ return m_metacache;
+}
+
+shared_qobject_ptr<QNetworkAccessManager> Application::network()
+{
+ return m_network;
+}
+
+shared_qobject_ptr<Meta::Index> Application::metadataIndex()
+{
+ if (!m_metadataIndex)
+ {
+ m_metadataIndex.reset(new Meta::Index());
+ }
+ return m_metadataIndex;
+}
+
+QString Application::getJarsPath()
+{
+ if(m_jarsPath.isEmpty())
+ {
+ return FS::PathCombine(QCoreApplication::applicationDirPath(), "jars");
+ }
+ return m_jarsPath;
+}
diff --git a/launcher/Launcher.h b/launcher/Application.h
index 8d97525f..1b2a2b60 100644
--- a/launcher/Launcher.h
+++ b/launcher/Application.h
@@ -18,7 +18,6 @@ class LocalPeer;
class InstanceWindow;
class MainWindow;
class SetupWizard;
-class FolderInstanceProvider;
class GenericPageProvider;
class QFile;
class HttpMetaCache;
@@ -36,18 +35,21 @@ class ITheme;
class MCEditTool;
class GAnalytics;
-#if defined(LAUNCHER)
-#undef LAUNCHER
+namespace Meta {
+ class Index;
+}
+
+#if defined(APPLICATION)
+#undef APPLICATION
#endif
-#define LAUNCHER (static_cast<Launcher *>(QCoreApplication::instance()))
+#define APPLICATION (static_cast<Application *>(QCoreApplication::instance()))
-class Launcher : public QApplication
+class Application : public QApplication
{
// friends for the purpose of limiting access to deprecated stuff
Q_OBJECT
public:
- enum Status
- {
+ enum Status {
StartingUp,
Failed,
Succeeded,
@@ -55,21 +57,18 @@ public:
};
public:
- Launcher(int &argc, char **argv);
- virtual ~Launcher();
+ Application(int &argc, char **argv);
+ virtual ~Application();
- GAnalytics *analytics() const
- {
+ GAnalytics *analytics() const {
return m_analytics;
}
- std::shared_ptr<SettingsObject> settings() const
- {
+ std::shared_ptr<SettingsObject> settings() const {
return m_settings;
}
- qint64 timeSinceStart() const
- {
+ qint64 timeSinceStart() const {
return startTime.msecsTo(QDateTime::currentDateTime());
}
@@ -81,9 +80,7 @@ public:
void setApplicationTheme(const QString& name, bool initial);
- // DownloadUpdateTask
- std::shared_ptr<UpdateChecker> updateChecker()
- {
+ shared_qobject_ptr<UpdateChecker> updateChecker() {
return m_updateChecker;
}
@@ -91,44 +88,44 @@ public:
std::shared_ptr<JavaInstallList> javalist();
- std::shared_ptr<InstanceList> instances() const
- {
+ std::shared_ptr<InstanceList> instances() const {
return m_instances;
}
- FolderInstanceProvider * folderProvider() const
- {
- return m_instanceFolder;
- }
-
- std::shared_ptr<IconList> icons() const
- {
+ std::shared_ptr<IconList> icons() const {
return m_icons;
}
- MCEditTool *mcedit() const
- {
+ MCEditTool *mcedit() const {
return m_mcedit.get();
}
- std::shared_ptr<AccountList> accounts() const
- {
+ shared_qobject_ptr<AccountList> accounts() const {
return m_accounts;
}
- Status status() const
- {
+ QString msaClientId() const;
+
+ Status status() const {
return m_status;
}
- const QMap<QString, std::shared_ptr<BaseProfilerFactory>> &profilers() const
- {
+ const QMap<QString, std::shared_ptr<BaseProfilerFactory>> &profilers() const {
return m_profilers;
}
+ void updateProxySettings(QString proxyTypeStr, QString addr, int port, QString user, QString password);
+
+ shared_qobject_ptr<QNetworkAccessManager> network();
+
+ shared_qobject_ptr<HttpMetaCache> metacache();
+
+ shared_qobject_ptr<Meta::Index> metadataIndex();
+
+ QString getJarsPath();
+
/// this is the root of the 'installation'. Used for automatic updates
- const QString &root()
- {
+ const QString &root() {
return m_rootPath;
}
@@ -153,11 +150,11 @@ signals:
public slots:
bool launch(
- InstancePtr instance,
- bool online = true,
- BaseProfilerFactory *profiler = nullptr,
- MinecraftServerTargetPtr serverToJoin = nullptr,
- MinecraftAccountPtr accountToUse = nullptr
+ InstancePtr instance,
+ bool online = true,
+ BaseProfilerFactory *profiler = nullptr,
+ MinecraftServerTargetPtr serverToJoin = nullptr,
+ MinecraftAccountPtr accountToUse = nullptr
);
bool kill(InstancePtr instance);
@@ -184,22 +181,29 @@ private:
private:
QDateTime startTime;
+ shared_qobject_ptr<QNetworkAccessManager> m_network;
+
+ shared_qobject_ptr<UpdateChecker> m_updateChecker;
+ shared_qobject_ptr<AccountList> m_accounts;
+
+ shared_qobject_ptr<HttpMetaCache> m_metacache;
+ shared_qobject_ptr<Meta::Index> m_metadataIndex;
+
std::shared_ptr<SettingsObject> m_settings;
std::shared_ptr<InstanceList> m_instances;
- FolderInstanceProvider * m_instanceFolder = nullptr;
std::shared_ptr<IconList> m_icons;
- std::shared_ptr<UpdateChecker> m_updateChecker;
- std::shared_ptr<AccountList> m_accounts;
std::shared_ptr<JavaInstallList> m_javalist;
std::shared_ptr<TranslationsModel> m_translations;
std::shared_ptr<GenericPageProvider> m_globalSettingsProvider;
std::map<QString, std::unique_ptr<ITheme>> m_themes;
std::unique_ptr<MCEditTool> m_mcedit;
+ QString m_jarsPath;
+ QSet<QString> m_features;
QMap<QString, std::shared_ptr<BaseProfilerFactory>> m_profilers;
QString m_rootPath;
- Status m_status = Launcher::StartingUp;
+ Status m_status = Application::StartingUp;
#if defined Q_OS_WIN32
// used on Windows to attach the standard IO streams
@@ -207,8 +211,7 @@ private:
#endif
// FIXME: attach to instances instead.
- struct InstanceXtras
- {
+ struct InstanceXtras {
InstanceWindow * window = nullptr;
shared_qobject_ptr<LaunchController> controller;
};
diff --git a/launcher/LauncherMessage.cpp b/launcher/ApplicationMessage.cpp
index 4cc56e22..e22bf13c 100644
--- a/launcher/LauncherMessage.cpp
+++ b/launcher/ApplicationMessage.cpp
@@ -1,9 +1,9 @@
-#include "LauncherMessage.h"
+#include "ApplicationMessage.h"
#include <QJsonDocument>
#include <QJsonObject>
-void LauncherMessage::parse(const QByteArray & input) {
+void ApplicationMessage::parse(const QByteArray & input) {
auto doc = QJsonDocument::fromBinaryData(input);
auto root = doc.object();
@@ -16,7 +16,7 @@ void LauncherMessage::parse(const QByteArray & input) {
}
}
-QByteArray LauncherMessage::serialize() {
+QByteArray ApplicationMessage::serialize() {
QJsonObject root;
root.insert("command", command);
QJsonObject outArgs;
diff --git a/launcher/LauncherMessage.h b/launcher/ApplicationMessage.h
index 024b16a5..745bdead 100644
--- a/launcher/LauncherMessage.h
+++ b/launcher/ApplicationMessage.h
@@ -4,7 +4,7 @@
#include <QMap>
#include <QByteArray>
-struct LauncherMessage {
+struct ApplicationMessage {
QString command;
QMap<QString, QString> args;
diff --git a/launcher/BaseInstance.h b/launcher/BaseInstance.h
index 253d2130..488f2781 100644
--- a/launcher/BaseInstance.h
+++ b/launcher/BaseInstance.h
@@ -100,6 +100,9 @@ public:
return instanceRoot();
}
+ /// Path to the instance's mods directory.
+ virtual QString modsRoot() const = 0;
+
QString name() const;
void setName(QString val);
@@ -143,7 +146,7 @@ public:
virtual SettingsObjectPtr settings() const;
/// returns a valid update task
- virtual shared_qobject_ptr<Task> createUpdateTask(Net::Mode mode) = 0;
+ virtual Task::Ptr createUpdateTask(Net::Mode mode) = 0;
/// returns a valid launcher (task container)
virtual shared_qobject_ptr<LaunchTask> createLaunchTask(
diff --git a/launcher/BaseVersionList.h b/launcher/BaseVersionList.h
index ce7abce1..80a91e8f 100644
--- a/launcher/BaseVersionList.h
+++ b/launcher/BaseVersionList.h
@@ -63,7 +63,7 @@ public:
* The task returned by this function should reset the model when it's done.
* \return A pointer to a task that reloads the version list.
*/
- virtual shared_qobject_ptr<Task> getLoadTask() = 0;
+ virtual Task::Ptr getLoadTask() = 0;
//! Checks whether or not the list is loaded. If this returns false, the list should be
//loaded.
diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt
index eba8f8a1..2dfc78b5 100644
--- a/launcher/CMakeLists.txt
+++ b/launcher/CMakeLists.txt
@@ -43,10 +43,6 @@ set(CORE_SOURCES
# Prefix tree where node names are strings between separators
SeparatorPrefixTree.h
- # WARNING: globals live here
- Env.h
- Env.cpp
-
# String filters
Filter.h
Filter.cpp
@@ -132,6 +128,8 @@ set(NET_SOURCES
# Game launch logic
set(LAUNCH_SOURCES
+ launch/steps/CheckJava.cpp
+ launch/steps/CheckJava.h
launch/steps/LookupServerAddress.cpp
launch/steps/LookupServerAddress.h
launch/steps/PostLaunchCommand.cpp
@@ -191,8 +189,6 @@ set(NEWS_SOURCES
# Icon interface
set(ICONS_SOURCES
# Icons System and related code
- icons/IIconList.h
- icons/IIconList.cpp
icons/IconUtils.h
icons/IconUtils.cpp
)
@@ -200,33 +196,52 @@ set(ICONS_SOURCES
# Support for Minecraft instances and launch
set(MINECRAFT_SOURCES
# Minecraft support
- minecraft/auth/AccountData.h
minecraft/auth/AccountData.cpp
- minecraft/auth/AccountTask.h
+ minecraft/auth/AccountData.h
+ minecraft/auth/AccountList.cpp
+ minecraft/auth/AccountList.h
minecraft/auth/AccountTask.cpp
- minecraft/auth/AuthSession.h
+ minecraft/auth/AccountTask.h
+ minecraft/auth/AuthRequest.cpp
+ minecraft/auth/AuthRequest.h
minecraft/auth/AuthSession.cpp
- minecraft/auth/AccountList.h
- minecraft/auth/AccountList.cpp
- minecraft/auth/MinecraftAccount.h
+ minecraft/auth/AuthSession.h
+ minecraft/auth/AuthStep.cpp
+ minecraft/auth/AuthStep.h
minecraft/auth/MinecraftAccount.cpp
- minecraft/auth/flows/AuthContext.h
- minecraft/auth/flows/AuthContext.cpp
- minecraft/auth/flows/AuthRequest.h
- minecraft/auth/flows/AuthRequest.cpp
-
- minecraft/auth/flows/MSAInteractive.h
- minecraft/auth/flows/MSAInteractive.cpp
- minecraft/auth/flows/MSASilent.h
- minecraft/auth/flows/MSASilent.cpp
-
- minecraft/auth/flows/MojangLogin.h
- minecraft/auth/flows/MojangLogin.cpp
- minecraft/auth/flows/MojangRefresh.h
- minecraft/auth/flows/MojangRefresh.cpp
-
- minecraft/auth/flows/Yggdrasil.h
- minecraft/auth/flows/Yggdrasil.cpp
+ minecraft/auth/MinecraftAccount.h
+ minecraft/auth/Parsers.cpp
+ minecraft/auth/Parsers.h
+ minecraft/auth/Yggdrasil.cpp
+ minecraft/auth/Yggdrasil.h
+
+ minecraft/auth/flows/AuthFlow.cpp
+ minecraft/auth/flows/AuthFlow.h
+ minecraft/auth/flows/Mojang.cpp
+ minecraft/auth/flows/Mojang.h
+ minecraft/auth/flows/MSA.cpp
+ minecraft/auth/flows/MSA.h
+
+ minecraft/auth/steps/EntitlementsStep.cpp
+ minecraft/auth/steps/EntitlementsStep.h
+ minecraft/auth/steps/GetSkinStep.cpp
+ minecraft/auth/steps/GetSkinStep.h
+ minecraft/auth/steps/LauncherLoginStep.cpp
+ minecraft/auth/steps/LauncherLoginStep.h
+ minecraft/auth/steps/MigrationEligibilityStep.cpp
+ minecraft/auth/steps/MigrationEligibilityStep.h
+ minecraft/auth/steps/MinecraftProfileStep.cpp
+ minecraft/auth/steps/MinecraftProfileStep.h
+ minecraft/auth/steps/MSAStep.cpp
+ minecraft/auth/steps/MSAStep.h
+ minecraft/auth/steps/XboxAuthorizationStep.cpp
+ minecraft/auth/steps/XboxAuthorizationStep.h
+ minecraft/auth/steps/XboxProfileStep.cpp
+ minecraft/auth/steps/XboxProfileStep.h
+ minecraft/auth/steps/XboxUserStep.cpp
+ minecraft/auth/steps/XboxUserStep.h
+ minecraft/auth/steps/YggdrasilStep.cpp
+ minecraft/auth/steps/YggdrasilStep.h
minecraft/gameoptions/GameOptions.h
minecraft/gameoptions/GameOptions.cpp
@@ -422,9 +437,6 @@ add_unit_test(INIFile
)
set(JAVA_SOURCES
- # Java related code
- java/launch/CheckJava.cpp
- java/launch/CheckJava.h
java/JavaChecker.h
java/JavaChecker.cpp
java/JavaCheckerJob.h
@@ -561,30 +573,37 @@ set(LOGIC_SOURCES
SET(LAUNCHER_SOURCES
# Application base
- Launcher.h
- Launcher.cpp
+ Application.h
+ Application.cpp
UpdateController.cpp
UpdateController.h
- LauncherMessage.h
- LauncherMessage.cpp
+ ApplicationMessage.h
+ ApplicationMessage.cpp
# GUI - general utilities
DesktopServices.h
DesktopServices.cpp
- GuiUtil.h
- GuiUtil.cpp
- ColumnResizer.h
- ColumnResizer.cpp
VersionProxyModel.h
VersionProxyModel.cpp
- ColorCache.h
- ColorCache.cpp
HoeDown.h
# Super secret!
KonamiCode.h
KonamiCode.cpp
+ # Bundled resources
+ resources/backgrounds/backgrounds.qrc
+ resources/multimc/multimc.qrc
+ resources/pe_dark/pe_dark.qrc
+ resources/pe_light/pe_light.qrc
+ resources/pe_colored/pe_colored.qrc
+ resources/pe_blue/pe_blue.qrc
+ resources/OSX/OSX.qrc
+ resources/iOS/iOS.qrc
+ resources/flat/flat.qrc
+ resources/documents/documents.qrc
+ ../${Launcher_Branding_LogoQRC}
+
# Icons
icons/MMCIcon.h
icons/MMCIcon.cpp
@@ -592,39 +611,43 @@ SET(LAUNCHER_SOURCES
icons/IconList.cpp
# GUI - windows
- MainWindow.h
- MainWindow.cpp
- InstanceWindow.h
- InstanceWindow.cpp
+ ui/GuiUtil.h
+ ui/GuiUtil.cpp
+ ui/ColorCache.h
+ ui/ColorCache.cpp
+ ui/MainWindow.h
+ ui/MainWindow.cpp
+ ui/InstanceWindow.h
+ ui/InstanceWindow.cpp
# FIXME: maybe find a better home for this.
SkinUtils.cpp
SkinUtils.h
# GUI - setup wizard
- setupwizard/SetupWizard.h
- setupwizard/SetupWizard.cpp
- setupwizard/AnalyticsWizardPage.cpp
- setupwizard/AnalyticsWizardPage.h
- setupwizard/BaseWizardPage.h
- setupwizard/JavaWizardPage.cpp
- setupwizard/JavaWizardPage.h
- setupwizard/LanguageWizardPage.cpp
- setupwizard/LanguageWizardPage.h
+ ui/setupwizard/SetupWizard.h
+ ui/setupwizard/SetupWizard.cpp
+ ui/setupwizard/AnalyticsWizardPage.cpp
+ ui/setupwizard/AnalyticsWizardPage.h
+ ui/setupwizard/BaseWizardPage.h
+ ui/setupwizard/JavaWizardPage.cpp
+ ui/setupwizard/JavaWizardPage.h
+ ui/setupwizard/LanguageWizardPage.cpp
+ ui/setupwizard/LanguageWizardPage.h
# GUI - themes
- themes/FusionTheme.cpp
- themes/FusionTheme.h
- themes/BrightTheme.cpp
- themes/BrightTheme.h
- themes/CustomTheme.cpp
- themes/CustomTheme.h
- themes/DarkTheme.cpp
- themes/DarkTheme.h
- themes/ITheme.cpp
- themes/ITheme.h
- themes/SystemTheme.cpp
- themes/SystemTheme.h
+ ui/themes/FusionTheme.cpp
+ ui/themes/FusionTheme.h
+ ui/themes/BrightTheme.cpp
+ ui/themes/BrightTheme.h
+ ui/themes/CustomTheme.cpp
+ ui/themes/CustomTheme.h
+ ui/themes/DarkTheme.cpp
+ ui/themes/DarkTheme.h
+ ui/themes/ITheme.cpp
+ ui/themes/ITheme.h
+ ui/themes/SystemTheme.cpp
+ ui/themes/SystemTheme.h
# Processes
LaunchController.h
@@ -638,241 +661,233 @@ SET(LAUNCHER_SOURCES
JavaCommon.cpp
# GUI - paged dialog base
- pages/BasePage.h
- pages/BasePageContainer.h
- pages/BasePageProvider.h
+ ui/pages/BasePage.h
+ ui/pages/BasePageContainer.h
+ ui/pages/BasePageProvider.h
# GUI - instance pages
- pages/instance/GameOptionsPage.cpp
- pages/instance/GameOptionsPage.h
- pages/instance/VersionPage.cpp
- pages/instance/VersionPage.h
- pages/instance/TexturePackPage.h
- pages/instance/ResourcePackPage.h
- pages/instance/ShaderPackPage.h
- pages/instance/ModFolderPage.cpp
- pages/instance/ModFolderPage.h
- pages/instance/NotesPage.cpp
- pages/instance/NotesPage.h
- pages/instance/LogPage.cpp
- pages/instance/LogPage.h
- pages/instance/InstanceSettingsPage.cpp
- pages/instance/InstanceSettingsPage.h
- pages/instance/ScreenshotsPage.cpp
- pages/instance/ScreenshotsPage.h
- pages/instance/OtherLogsPage.cpp
- pages/instance/OtherLogsPage.h
- pages/instance/ServersPage.cpp
- pages/instance/ServersPage.h
- pages/instance/LegacyUpgradePage.cpp
- pages/instance/LegacyUpgradePage.h
- pages/instance/WorldListPage.cpp
- pages/instance/WorldListPage.h
+ ui/pages/instance/GameOptionsPage.cpp
+ ui/pages/instance/GameOptionsPage.h
+ ui/pages/instance/VersionPage.cpp
+ ui/pages/instance/VersionPage.h
+ ui/pages/instance/TexturePackPage.h
+ ui/pages/instance/ResourcePackPage.h
+ ui/pages/instance/ShaderPackPage.h
+ ui/pages/instance/ModFolderPage.cpp
+ ui/pages/instance/ModFolderPage.h
+ ui/pages/instance/NotesPage.cpp
+ ui/pages/instance/NotesPage.h
+ ui/pages/instance/LogPage.cpp
+ ui/pages/instance/LogPage.h
+ ui/pages/instance/InstanceSettingsPage.cpp
+ ui/pages/instance/InstanceSettingsPage.h
+ ui/pages/instance/ScreenshotsPage.cpp
+ ui/pages/instance/ScreenshotsPage.h
+ ui/pages/instance/OtherLogsPage.cpp
+ ui/pages/instance/OtherLogsPage.h
+ ui/pages/instance/ServersPage.cpp
+ ui/pages/instance/ServersPage.h
+ ui/pages/instance/LegacyUpgradePage.cpp
+ ui/pages/instance/LegacyUpgradePage.h
+ ui/pages/instance/WorldListPage.cpp
+ ui/pages/instance/WorldListPage.h
# GUI - global settings pages
- pages/global/AccountListPage.cpp
- pages/global/AccountListPage.h
- pages/global/CustomCommandsPage.cpp
- pages/global/CustomCommandsPage.h
- pages/global/ExternalToolsPage.cpp
- pages/global/ExternalToolsPage.h
- pages/global/JavaPage.cpp
- pages/global/JavaPage.h
- pages/global/LanguagePage.cpp
- pages/global/LanguagePage.h
- pages/global/MinecraftPage.cpp
- pages/global/MinecraftPage.h
- pages/global/LauncherPage.cpp
- pages/global/LauncherPage.h
- pages/global/ProxyPage.cpp
- pages/global/ProxyPage.h
- pages/global/PasteEEPage.cpp
- pages/global/PasteEEPage.h
+ ui/pages/global/AccountListPage.cpp
+ ui/pages/global/AccountListPage.h
+ ui/pages/global/CustomCommandsPage.cpp
+ ui/pages/global/CustomCommandsPage.h
+ ui/pages/global/ExternalToolsPage.cpp
+ ui/pages/global/ExternalToolsPage.h
+ ui/pages/global/JavaPage.cpp
+ ui/pages/global/JavaPage.h
+ ui/pages/global/LanguagePage.cpp
+ ui/pages/global/LanguagePage.h
+ ui/pages/global/MinecraftPage.cpp
+ ui/pages/global/MinecraftPage.h
+ ui/pages/global/LauncherPage.cpp
+ ui/pages/global/LauncherPage.h
+ ui/pages/global/ProxyPage.cpp
+ ui/pages/global/ProxyPage.h
+ ui/pages/global/PasteEEPage.cpp
+ ui/pages/global/PasteEEPage.h
# GUI - platform pages
- pages/modplatform/VanillaPage.cpp
- pages/modplatform/VanillaPage.h
-
- pages/modplatform/atlauncher/AtlFilterModel.cpp
- pages/modplatform/atlauncher/AtlFilterModel.h
- pages/modplatform/atlauncher/AtlListModel.cpp
- pages/modplatform/atlauncher/AtlListModel.h
- pages/modplatform/atlauncher/AtlOptionalModDialog.cpp
- pages/modplatform/atlauncher/AtlOptionalModDialog.h
- pages/modplatform/atlauncher/AtlPage.cpp
- pages/modplatform/atlauncher/AtlPage.h
-
- pages/modplatform/ftb/FtbFilterModel.cpp
- pages/modplatform/ftb/FtbFilterModel.h
- pages/modplatform/ftb/FtbListModel.cpp
- pages/modplatform/ftb/FtbListModel.h
- pages/modplatform/ftb/FtbPage.cpp
- pages/modplatform/ftb/FtbPage.h
-
- pages/modplatform/legacy_ftb/Page.cpp
- pages/modplatform/legacy_ftb/Page.h
- pages/modplatform/legacy_ftb/ListModel.h
- pages/modplatform/legacy_ftb/ListModel.cpp
-
- pages/modplatform/flame/FlameModel.cpp
- pages/modplatform/flame/FlameModel.h
- pages/modplatform/flame/FlamePage.cpp
- pages/modplatform/flame/FlamePage.h
-
- pages/modplatform/technic/TechnicModel.cpp
- pages/modplatform/technic/TechnicModel.h
- pages/modplatform/technic/TechnicPage.cpp
- pages/modplatform/technic/TechnicPage.h
-
- pages/modplatform/ImportPage.cpp
- pages/modplatform/ImportPage.h
+ ui/pages/modplatform/VanillaPage.cpp
+ ui/pages/modplatform/VanillaPage.h
+
+ ui/pages/modplatform/atlauncher/AtlFilterModel.cpp
+ ui/pages/modplatform/atlauncher/AtlFilterModel.h
+ ui/pages/modplatform/atlauncher/AtlListModel.cpp
+ ui/pages/modplatform/atlauncher/AtlListModel.h
+ ui/pages/modplatform/atlauncher/AtlOptionalModDialog.cpp
+ ui/pages/modplatform/atlauncher/AtlOptionalModDialog.h
+ ui/pages/modplatform/atlauncher/AtlPage.cpp
+ ui/pages/modplatform/atlauncher/AtlPage.h
+
+ ui/pages/modplatform/ftb/FtbFilterModel.cpp
+ ui/pages/modplatform/ftb/FtbFilterModel.h
+ ui/pages/modplatform/ftb/FtbListModel.cpp
+ ui/pages/modplatform/ftb/FtbListModel.h
+ ui/pages/modplatform/ftb/FtbPage.cpp
+ ui/pages/modplatform/ftb/FtbPage.h
+
+ ui/pages/modplatform/legacy_ftb/Page.cpp
+ ui/pages/modplatform/legacy_ftb/Page.h
+ ui/pages/modplatform/legacy_ftb/ListModel.h
+ ui/pages/modplatform/legacy_ftb/ListModel.cpp
+
+ ui/pages/modplatform/flame/FlameModel.cpp
+ ui/pages/modplatform/flame/FlameModel.h
+ ui/pages/modplatform/flame/FlamePage.cpp
+ ui/pages/modplatform/flame/FlamePage.h
+
+ ui/pages/modplatform/technic/TechnicModel.cpp
+ ui/pages/modplatform/technic/TechnicModel.h
+ ui/pages/modplatform/technic/TechnicPage.cpp
+ ui/pages/modplatform/technic/TechnicPage.h
+
+ ui/pages/modplatform/ImportPage.cpp
+ ui/pages/modplatform/ImportPage.h
# GUI - dialogs
- dialogs/AboutDialog.cpp
- dialogs/AboutDialog.h
- dialogs/ProfileSelectDialog.cpp
- dialogs/ProfileSelectDialog.h
- dialogs/CopyInstanceDialog.cpp
- dialogs/CopyInstanceDialog.h
- dialogs/CustomMessageBox.cpp
- dialogs/CustomMessageBox.h
- dialogs/EditAccountDialog.cpp
- dialogs/EditAccountDialog.h
- dialogs/ExportInstanceDialog.cpp
- dialogs/ExportInstanceDialog.h
- dialogs/IconPickerDialog.cpp
- dialogs/IconPickerDialog.h
- dialogs/LoginDialog.cpp
- dialogs/LoginDialog.h
- dialogs/MSALoginDialog.cpp
- dialogs/MSALoginDialog.h
- dialogs/NewComponentDialog.cpp
- dialogs/NewComponentDialog.h
- dialogs/NewInstanceDialog.cpp
- dialogs/NewInstanceDialog.h
- dialogs/NotificationDialog.cpp
- dialogs/NotificationDialog.h
- pagedialog/PageDialog.cpp
- pagedialog/PageDialog.h
- dialogs/ProgressDialog.cpp
- dialogs/ProgressDialog.h
- dialogs/UpdateDialog.cpp
- dialogs/UpdateDialog.h
- dialogs/VersionSelectDialog.cpp
- dialogs/VersionSelectDialog.h
- dialogs/SkinUploadDialog.cpp
- dialogs/SkinUploadDialog.h
+ ui/dialogs/AboutDialog.cpp
+ ui/dialogs/AboutDialog.h
+ ui/dialogs/ProfileSelectDialog.cpp
+ ui/dialogs/ProfileSelectDialog.h
+ ui/dialogs/ProfileSetupDialog.cpp
+ ui/dialogs/ProfileSetupDialog.h
+ ui/dialogs/CopyInstanceDialog.cpp
+ ui/dialogs/CopyInstanceDialog.h
+ ui/dialogs/CustomMessageBox.cpp
+ ui/dialogs/CustomMessageBox.h
+ ui/dialogs/EditAccountDialog.cpp
+ ui/dialogs/EditAccountDialog.h
+ ui/dialogs/ExportInstanceDialog.cpp
+ ui/dialogs/ExportInstanceDialog.h
+ ui/dialogs/IconPickerDialog.cpp
+ ui/dialogs/IconPickerDialog.h
+ ui/dialogs/LoginDialog.cpp
+ ui/dialogs/LoginDialog.h
+ ui/dialogs/MSALoginDialog.cpp
+ ui/dialogs/MSALoginDialog.h
+ ui/dialogs/NewComponentDialog.cpp
+ ui/dialogs/NewComponentDialog.h
+ ui/dialogs/NewInstanceDialog.cpp
+ ui/dialogs/NewInstanceDialog.h
+ ui/dialogs/NotificationDialog.cpp
+ ui/dialogs/NotificationDialog.h
+ ui/pagedialog/PageDialog.cpp
+ ui/pagedialog/PageDialog.h
+ ui/dialogs/ProgressDialog.cpp
+ ui/dialogs/ProgressDialog.h
+ ui/dialogs/UpdateDialog.cpp
+ ui/dialogs/UpdateDialog.h
+ ui/dialogs/VersionSelectDialog.cpp
+ ui/dialogs/VersionSelectDialog.h
+ ui/dialogs/SkinUploadDialog.cpp
+ ui/dialogs/SkinUploadDialog.h
# GUI - widgets
- widgets/Common.cpp
- widgets/Common.h
- widgets/CustomCommands.cpp
- widgets/CustomCommands.h
- widgets/DropLabel.cpp
- widgets/DropLabel.h
- widgets/FocusLineEdit.cpp
- widgets/FocusLineEdit.h
- widgets/IconLabel.cpp
- widgets/IconLabel.h
- widgets/JavaSettingsWidget.cpp
- widgets/JavaSettingsWidget.h
- widgets/LabeledToolButton.cpp
- widgets/LabeledToolButton.h
- widgets/LanguageSelectionWidget.cpp
- widgets/LanguageSelectionWidget.h
- widgets/LineSeparator.cpp
- widgets/LineSeparator.h
- widgets/LogView.cpp
- widgets/LogView.h
- widgets/MCModInfoFrame.cpp
- widgets/MCModInfoFrame.h
- widgets/ModListView.cpp
- widgets/ModListView.h
- widgets/PageContainer.cpp
- widgets/PageContainer.h
- widgets/PageContainer_p.h
- widgets/VersionListView.cpp
- widgets/VersionListView.h
- widgets/VersionSelectWidget.cpp
- widgets/VersionSelectWidget.h
- widgets/ProgressWidget.h
- widgets/ProgressWidget.cpp
- widgets/WideBar.h
- widgets/WideBar.cpp
+ ui/widgets/Common.cpp
+ ui/widgets/Common.h
+ ui/widgets/CustomCommands.cpp
+ ui/widgets/CustomCommands.h
+ ui/widgets/DropLabel.cpp
+ ui/widgets/DropLabel.h
+ ui/widgets/FocusLineEdit.cpp
+ ui/widgets/FocusLineEdit.h
+ ui/widgets/IconLabel.cpp
+ ui/widgets/IconLabel.h
+ ui/widgets/JavaSettingsWidget.cpp
+ ui/widgets/JavaSettingsWidget.h
+ ui/widgets/LabeledToolButton.cpp
+ ui/widgets/LabeledToolButton.h
+ ui/widgets/LanguageSelectionWidget.cpp
+ ui/widgets/LanguageSelectionWidget.h
+ ui/widgets/LineSeparator.cpp
+ ui/widgets/LineSeparator.h
+ ui/widgets/LogView.cpp
+ ui/widgets/LogView.h
+ ui/widgets/MCModInfoFrame.cpp
+ ui/widgets/MCModInfoFrame.h
+ ui/widgets/ModListView.cpp
+ ui/widgets/ModListView.h
+ ui/widgets/PageContainer.cpp
+ ui/widgets/PageContainer.h
+ ui/widgets/PageContainer_p.h
+ ui/widgets/VersionListView.cpp
+ ui/widgets/VersionListView.h
+ ui/widgets/VersionSelectWidget.cpp
+ ui/widgets/VersionSelectWidget.h
+ ui/widgets/ProgressWidget.h
+ ui/widgets/ProgressWidget.cpp
+ ui/widgets/WideBar.h
+ ui/widgets/WideBar.cpp
# GUI - instance group view
- instanceview/InstanceProxyModel.cpp
- instanceview/InstanceProxyModel.h
- instanceview/AccessibleInstanceView.cpp
- instanceview/AccessibleInstanceView.h
- instanceview/AccessibleInstanceView_p.h
- instanceview/InstanceView.cpp
- instanceview/InstanceView.h
- instanceview/InstanceDelegate.cpp
- instanceview/InstanceDelegate.h
- instanceview/VisualGroup.cpp
- instanceview/VisualGroup.h
- )
+ ui/instanceview/InstanceProxyModel.cpp
+ ui/instanceview/InstanceProxyModel.h
+ ui/instanceview/AccessibleInstanceView.cpp
+ ui/instanceview/AccessibleInstanceView.h
+ ui/instanceview/AccessibleInstanceView_p.h
+ ui/instanceview/InstanceView.cpp
+ ui/instanceview/InstanceView.h
+ ui/instanceview/InstanceDelegate.cpp
+ ui/instanceview/InstanceDelegate.h
+ ui/instanceview/VisualGroup.cpp
+ ui/instanceview/VisualGroup.h
+)
-######## UIs ########
-SET(LAUNCHER_UIS
- # Instance pages
- pages/instance/GameOptionsPage.ui
- pages/instance/VersionPage.ui
- pages/instance/ModFolderPage.ui
- pages/instance/LogPage.ui
- pages/instance/InstanceSettingsPage.ui
- pages/instance/NotesPage.ui
- pages/instance/ScreenshotsPage.ui
- pages/instance/OtherLogsPage.ui
- pages/instance/LegacyUpgradePage.ui
- pages/instance/ServersPage.ui
- pages/instance/WorldListPage.ui
-
- # Global settings pages
- pages/global/AccountListPage.ui
- pages/global/ExternalToolsPage.ui
- pages/global/JavaPage.ui
- pages/global/MinecraftPage.ui
- pages/global/LauncherPage.ui
- pages/global/ProxyPage.ui
- pages/global/PasteEEPage.ui
-
- # Platform pages
- pages/modplatform/VanillaPage.ui
- pages/modplatform/atlauncher/AtlPage.ui
- pages/modplatform/ftb/FtbPage.ui
- pages/modplatform/legacy_ftb/Page.ui
- pages/modplatform/flame/FlamePage.ui
- pages/modplatform/technic/TechnicPage.ui
- pages/modplatform/ImportPage.ui
-
- # Platform Dialogs
- pages/modplatform/atlauncher/AtlOptionalModDialog.ui
-
- # Dialogs
- dialogs/CopyInstanceDialog.ui
- dialogs/NewComponentDialog.ui
- dialogs/NewInstanceDialog.ui
- dialogs/AboutDialog.ui
- dialogs/ProgressDialog.ui
- dialogs/IconPickerDialog.ui
- dialogs/ProfileSelectDialog.ui
- dialogs/EditAccountDialog.ui
- dialogs/ExportInstanceDialog.ui
- dialogs/LoginDialog.ui
- dialogs/MSALoginDialog.ui
- dialogs/UpdateDialog.ui
- dialogs/NotificationDialog.ui
- dialogs/SkinUploadDialog.ui
-
- # Widgets/other
- widgets/CustomCommands.ui
- widgets/MCModInfoFrame.ui
+qt5_wrap_ui(LAUNCHER_UI
+ ui/pages/global/AccountListPage.ui
+ ui/pages/global/JavaPage.ui
+ ui/pages/global/LauncherPage.ui
+ ui/pages/global/PasteEEPage.ui
+ ui/pages/global/ProxyPage.ui
+ ui/pages/global/MinecraftPage.ui
+ ui/pages/global/ExternalToolsPage.ui
+ ui/pages/instance/ModFolderPage.ui
+ ui/pages/instance/NotesPage.ui
+ ui/pages/instance/LogPage.ui
+ ui/pages/instance/ServersPage.ui
+ ui/pages/instance/GameOptionsPage.ui
+ ui/pages/instance/OtherLogsPage.ui
+ ui/pages/instance/InstanceSettingsPage.ui
+ ui/pages/instance/VersionPage.ui
+ ui/pages/instance/WorldListPage.ui
+ ui/pages/instance/LegacyUpgradePage.ui
+ ui/pages/instance/ScreenshotsPage.ui
+ ui/pages/modplatform/atlauncher/AtlOptionalModDialog.ui
+ ui/pages/modplatform/atlauncher/AtlPage.ui
+ ui/pages/modplatform/VanillaPage.ui
+ ui/pages/modplatform/flame/FlamePage.ui
+ ui/pages/modplatform/legacy_ftb/Page.ui
+ ui/pages/modplatform/ImportPage.ui
+ ui/pages/modplatform/ftb/FtbPage.ui
+ ui/pages/modplatform/technic/TechnicPage.ui
+ ui/widgets/InstanceCardWidget.ui
+ ui/widgets/CustomCommands.ui
+ ui/widgets/MCModInfoFrame.ui
+ ui/dialogs/CopyInstanceDialog.ui
+ ui/dialogs/ProfileSetupDialog.ui
+ ui/dialogs/ProgressDialog.ui
+ ui/dialogs/NewInstanceDialog.ui
+ ui/dialogs/NotificationDialog.ui
+ ui/dialogs/UpdateDialog.ui
+ ui/dialogs/NewComponentDialog.ui
+ ui/dialogs/ProfileSelectDialog.ui
+ ui/dialogs/SkinUploadDialog.ui
+ ui/dialogs/ExportInstanceDialog.ui
+ ui/dialogs/IconPickerDialog.ui
+ ui/dialogs/MSALoginDialog.ui
+ ui/dialogs/AboutDialog.ui
+ ui/dialogs/LoginDialog.ui
+ ui/dialogs/EditAccountDialog.ui
)
-set(LAUNCHER_QRCS
+qt5_add_resources(LAUNCHER_RESOURCES
resources/backgrounds/backgrounds.qrc
resources/multimc/multimc.qrc
resources/pe_dark/pe_dark.qrc
@@ -891,10 +906,6 @@ if(WIN32)
set(LAUNCHER_RCS ../${Launcher_Branding_WindowsRC})
endif()
-# Qt 5 stuff
-qt5_wrap_ui(LAUNCHER_UI ${LAUNCHER_UIS})
-qt5_add_resources(LAUNCHER_RESOURCES ${LAUNCHER_QRCS})
-
# Add executable
add_library(Launcher_logic STATIC ${LOGIC_SOURCES} ${LAUNCHER_SOURCES} ${LAUNCHER_UI} ${LAUNCHER_RESOURCES})
target_link_libraries(Launcher_logic
diff --git a/launcher/ColumnResizer.cpp b/launcher/ColumnResizer.cpp
deleted file mode 100644
index fe415067..00000000
--- a/launcher/ColumnResizer.cpp
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
-* Copyright 2011 Aurélien Gâteau <agateau@kde.org>
-* License: BSD-3-Clause
-*/
-#include <ColumnResizer.h>
-
-#include <QDebug>
-#include <QEvent>
-#include <QFormLayout>
-#include <QGridLayout>
-#include <QTimer>
-#include <QWidget>
-
-class FormLayoutWidgetItem : public QWidgetItem
-{
-public:
- FormLayoutWidgetItem(QWidget* widget, QFormLayout* formLayout, QFormLayout::ItemRole itemRole)
- : QWidgetItem(widget)
- , m_width(-1)
- , m_formLayout(formLayout)
- , m_itemRole(itemRole)
- {}
-
- QSize sizeHint() const
- {
- QSize size = QWidgetItem::sizeHint();
- if (m_width != -1) {
- size.setWidth(m_width);
- }
- return size;
- }
-
- QSize minimumSize() const
- {
- QSize size = QWidgetItem::minimumSize();
- if (m_width != -1) {
- size.setWidth(m_width);
- }
- return size;
- }
-
- QSize maximumSize() const
- {
- QSize size = QWidgetItem::maximumSize();
- if (m_width != -1) {
- size.setWidth(m_width);
- }
- return size;
- }
-
- void setWidth(int width)
- {
- if (width != m_width) {
- m_width = width;
- invalidate();
- }
- }
-
- void setGeometry(const QRect& _rect)
- {
- QRect rect = _rect;
- int width = widget()->sizeHint().width();
- if (m_itemRole == QFormLayout::LabelRole && m_formLayout->labelAlignment() & Qt::AlignRight) {
- rect.setLeft(rect.right() - width);
- }
- QWidgetItem::setGeometry(rect);
- }
-
- QFormLayout* formLayout() const
- {
- return m_formLayout;
- }
-
-private:
- int m_width;
- QFormLayout* m_formLayout;
- QFormLayout::ItemRole m_itemRole;
-};
-
-typedef QPair<QGridLayout*, int> GridColumnInfo;
-
-class ColumnResizerPrivate
-{
-public:
- ColumnResizerPrivate(ColumnResizer* q_ptr)
- : q(q_ptr)
- , m_updateTimer(new QTimer(q))
- {
- m_updateTimer->setSingleShot(true);
- m_updateTimer->setInterval(0);
- QObject::connect(m_updateTimer, SIGNAL(timeout()), q, SLOT(updateWidth()));
- }
-
- void scheduleWidthUpdate()
- {
- m_updateTimer->start();
- }
-
- ColumnResizer* q;
- QTimer* m_updateTimer;
- QList<QWidget*> m_widgets;
- QList<FormLayoutWidgetItem*> m_wrWidgetItemList;
- QList<GridColumnInfo> m_gridColumnInfoList;
-};
-
-ColumnResizer::ColumnResizer(QObject* parent)
-: QObject(parent)
-, d(new ColumnResizerPrivate(this))
-{}
-
-ColumnResizer::~ColumnResizer()
-{
- delete d;
-}
-
-void ColumnResizer::addWidget(QWidget* widget)
-{
- d->m_widgets.append(widget);
- widget->installEventFilter(this);
- d->scheduleWidthUpdate();
-}
-
-void ColumnResizer::updateWidth()
-{
- int width = 0;
- Q_FOREACH(QWidget* widget, d->m_widgets) {
- width = qMax(widget->sizeHint().width(), width);
- }
- Q_FOREACH(FormLayoutWidgetItem* item, d->m_wrWidgetItemList) {
- item->setWidth(width);
- item->formLayout()->update();
- }
- Q_FOREACH(GridColumnInfo info, d->m_gridColumnInfoList) {
- info.first->setColumnMinimumWidth(info.second, width);
- }
-}
-
-bool ColumnResizer::eventFilter(QObject*, QEvent* event)
-{
- if (event->type() == QEvent::Resize) {
- d->scheduleWidthUpdate();
- }
- return false;
-}
-
-void ColumnResizer::addWidgetsFromLayout(QLayout* layout, int column)
-{
- Q_ASSERT(column >= 0);
- QGridLayout* gridLayout = qobject_cast<QGridLayout*>(layout);
- QFormLayout* formLayout = qobject_cast<QFormLayout*>(layout);
- if (gridLayout) {
- addWidgetsFromGridLayout(gridLayout, column);
- } else if (formLayout) {
- if (column > QFormLayout::SpanningRole) {
- qCritical() << "column should not be more than" << QFormLayout::SpanningRole << "for QFormLayout";
- return;
- }
- QFormLayout::ItemRole role = static_cast<QFormLayout::ItemRole>(column);
- addWidgetsFromFormLayout(formLayout, role);
- } else {
- qCritical() << "Don't know how to handle layout" << layout;
- }
-}
-
-void ColumnResizer::addWidgetsFromGridLayout(QGridLayout* layout, int column)
-{
- for (int row = 0; row < layout->rowCount(); ++row) {
- QLayoutItem* item = layout->itemAtPosition(row, column);
- if (!item) {
- continue;
- }
- QWidget* widget = item->widget();
- if (!widget) {
- continue;
- }
- addWidget(widget);
- }
- d->m_gridColumnInfoList << GridColumnInfo(layout, column);
-}
-
-void ColumnResizer::addWidgetsFromFormLayout(QFormLayout* layout, QFormLayout::ItemRole role)
-{
- for (int row = 0; row < layout->rowCount(); ++row) {
- QLayoutItem* item = layout->itemAt(row, role);
- if (!item) {
- continue;
- }
- QWidget* widget = item->widget();
- if (!widget) {
- continue;
- }
- layout->removeItem(item);
- delete item;
- FormLayoutWidgetItem* newItem = new FormLayoutWidgetItem(widget, layout, role);
- layout->setItem(row, role, newItem);
- addWidget(widget);
- d->m_wrWidgetItemList << newItem;
- }
-}
diff --git a/launcher/ColumnResizer.h b/launcher/ColumnResizer.h
deleted file mode 100644
index 8c920f01..00000000
--- a/launcher/ColumnResizer.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
-* Copyright 2011 Aurélien Gâteau <agateau@kde.org>
-* License: BSD-3-Clause
-*/
-#ifndef COLUMNRESIZER_H
-#define COLUMNRESIZER_H
-
-#include <QFormLayout>
-
-#include <QtCore/QObject>
-#include <QtCore/QList>
-
-class QEvent;
-class QGridLayout;
-class QLayout;
-class QWidget;
-
-class ColumnResizerPrivate;
-class ColumnResizer : public QObject
-{
- Q_OBJECT
-public:
- ColumnResizer(QObject* parent = 0);
- ~ColumnResizer();
-
- void addWidget(QWidget* widget);
- void addWidgetsFromLayout(QLayout*, int column);
- void addWidgetsFromGridLayout(QGridLayout*, int column);
- void addWidgetsFromFormLayout(QFormLayout*, QFormLayout::ItemRole role);
-
-private Q_SLOTS:
- void updateWidth();
-
-protected:
- bool eventFilter(QObject*, QEvent* event);
-
-private:
- ColumnResizerPrivate* const d;
-};
-
-#endif /* COLUMNRESIZER_H */
diff --git a/launcher/Env.cpp b/launcher/Env.cpp
deleted file mode 100644
index abf9f58c..00000000
--- a/launcher/Env.cpp
+++ /dev/null
@@ -1,210 +0,0 @@
-#include "Env.h"
-#include "net/HttpMetaCache.h"
-#include "BaseVersion.h"
-#include "BaseVersionList.h"
-#include <QDir>
-#include <QCoreApplication>
-#include <QNetworkProxy>
-#include <QNetworkAccessManager>
-#include <QDebug>
-#include "tasks/Task.h"
-#include "meta/Index.h"
-#include "FileSystem.h"
-#include <QDebug>
-
-
-struct Env::Private
-{
- QNetworkAccessManager m_qnam;
- shared_qobject_ptr<HttpMetaCache> m_metacache;
- std::shared_ptr<IIconList> m_iconlist;
- shared_qobject_ptr<Meta::Index> m_metadataIndex;
- QString m_jarsPath;
- QSet<QString> m_features;
-};
-
-static Env * instance;
-
-/*
- * The *NEW* global rat nest of an object. Handle with care.
- */
-
-Env::Env()
-{
- d = new Private();
-}
-
-Env::~Env()
-{
- delete d;
-}
-
-Env& Env::Env::getInstance()
-{
- if(!instance)
- {
- instance = new Env();
- }
- return *instance;
-}
-
-void Env::dispose()
-{
- delete instance;
- instance = nullptr;
-}
-
-shared_qobject_ptr< HttpMetaCache > Env::metacache()
-{
- return d->m_metacache;
-}
-
-QNetworkAccessManager& Env::qnam() const
-{
- return d->m_qnam;
-}
-
-std::shared_ptr<IIconList> Env::icons()
-{
- return d->m_iconlist;
-}
-
-void Env::registerIconList(std::shared_ptr<IIconList> iconlist)
-{
- d->m_iconlist = iconlist;
-}
-
-shared_qobject_ptr<Meta::Index> Env::metadataIndex()
-{
- if (!d->m_metadataIndex)
- {
- d->m_metadataIndex.reset(new Meta::Index());
- }
- return d->m_metadataIndex;
-}
-
-
-void Env::initHttpMetaCache()
-{
- auto &m_metacache = d->m_metacache;
- m_metacache.reset(new HttpMetaCache("metacache"));
- m_metacache->addBase("asset_indexes", QDir("assets/indexes").absolutePath());
- m_metacache->addBase("asset_objects", QDir("assets/objects").absolutePath());
- m_metacache->addBase("versions", QDir("versions").absolutePath());
- m_metacache->addBase("libraries", QDir("libraries").absolutePath());
- m_metacache->addBase("minecraftforge", QDir("mods/minecraftforge").absolutePath());
- m_metacache->addBase("fmllibs", QDir("mods/minecraftforge/libs").absolutePath());
- m_metacache->addBase("liteloader", QDir("mods/liteloader").absolutePath());
- m_metacache->addBase("general", QDir("cache").absolutePath());
- m_metacache->addBase("ATLauncherPacks", QDir("cache/ATLauncherPacks").absolutePath());
- m_metacache->addBase("FTBPacks", QDir("cache/FTBPacks").absolutePath());
- m_metacache->addBase("ModpacksCHPacks", QDir("cache/ModpacksCHPacks").absolutePath());
- m_metacache->addBase("TechnicPacks", QDir("cache/TechnicPacks").absolutePath());
- m_metacache->addBase("FlamePacks", QDir("cache/FlamePacks").absolutePath());
- m_metacache->addBase("root", QDir::currentPath());
- m_metacache->addBase("translations", QDir("translations").absolutePath());
- m_metacache->addBase("icons", QDir("cache/icons").absolutePath());
- m_metacache->addBase("meta", QDir("meta").absolutePath());
- m_metacache->Load();
-}
-
-void Env::updateProxySettings(QString proxyTypeStr, QString addr, int port, QString user, QString password)
-{
- // Set the application proxy settings.
- if (proxyTypeStr == "SOCKS5")
- {
- QNetworkProxy::setApplicationProxy(
- QNetworkProxy(QNetworkProxy::Socks5Proxy, addr, port, user, password));
- }
- else if (proxyTypeStr == "HTTP")
- {
- QNetworkProxy::setApplicationProxy(
- QNetworkProxy(QNetworkProxy::HttpProxy, addr, port, user, password));
- }
- else if (proxyTypeStr == "None")
- {
- // If we have no proxy set, set no proxy and return.
- QNetworkProxy::setApplicationProxy(QNetworkProxy(QNetworkProxy::NoProxy));
- }
- else
- {
- // If we have "Default" selected, set Qt to use the system proxy settings.
- QNetworkProxyFactory::setUseSystemConfiguration(true);
- }
-
- qDebug() << "Detecting proxy settings...";
- QNetworkProxy proxy = QNetworkProxy::applicationProxy();
- d->m_qnam.setProxy(proxy);
- QString proxyDesc;
- if (proxy.type() == QNetworkProxy::NoProxy)
- {
- qDebug() << "Using no proxy is an option!";
- return;
- }
- switch (proxy.type())
- {
- case QNetworkProxy::DefaultProxy:
- proxyDesc = "Default proxy: ";
- break;
- case QNetworkProxy::Socks5Proxy:
- proxyDesc = "Socks5 proxy: ";
- break;
- case QNetworkProxy::HttpProxy:
- proxyDesc = "HTTP proxy: ";
- break;
- case QNetworkProxy::HttpCachingProxy:
- proxyDesc = "HTTP caching: ";
- break;
- case QNetworkProxy::FtpCachingProxy:
- proxyDesc = "FTP caching: ";
- break;
- default:
- proxyDesc = "DERP proxy: ";
- break;
- }
- proxyDesc += QString("%1:%2")
- .arg(proxy.hostName())
- .arg(proxy.port());
- qDebug() << proxyDesc;
-}
-
-QString Env::getJarsPath()
-{
- if(d->m_jarsPath.isEmpty())
- {
- return FS::PathCombine(QCoreApplication::applicationDirPath(), "jars");
- }
- return d->m_jarsPath;
-}
-
-void Env::setJarsPath(const QString& path)
-{
- d->m_jarsPath = path;
-}
-
-void Env::enableFeature(const QString& featureName, bool state)
-{
- if(state)
- {
- d->m_features.insert(featureName);
- }
- else
- {
- d->m_features.remove(featureName);
- }
-}
-
-bool Env::isFeatureEnabled(const QString& featureName) const
-{
- return d->m_features.contains(featureName);
-}
-
-void Env::getEnabledFeatures(QSet<QString>& features) const
-{
- features = d->m_features;
-}
-
-void Env::setEnabledFeatures(const QSet<QString>& features) const
-{
- d->m_features = features;
-}
diff --git a/launcher/Env.h b/launcher/Env.h
deleted file mode 100644
index 52427696..00000000
--- a/launcher/Env.h
+++ /dev/null
@@ -1,63 +0,0 @@
-#pragma once
-
-#include <memory>
-#include "icons/IIconList.h"
-#include <QString>
-#include <QMap>
-
-#include "QObjectPtr.h"
-
-class QNetworkAccessManager;
-class HttpMetaCache;
-class BaseVersionList;
-class BaseVersion;
-
-namespace Meta
-{
-class Index;
-}
-
-#if defined(ENV)
- #undef ENV
-#endif
-#define ENV (Env::getInstance())
-
-
-class Env
-{
- friend class Launcher;
-private:
- struct Private;
- Env();
- ~Env();
- static void dispose();
-public:
- static Env& getInstance();
-
- QNetworkAccessManager &qnam() const;
-
- shared_qobject_ptr<HttpMetaCache> metacache();
-
- std::shared_ptr<IIconList> icons();
-
- /// init the cache. FIXME: possible future hook point
- void initHttpMetaCache();
-
- /// Updates the application proxy settings from the settings object.
- void updateProxySettings(QString proxyTypeStr, QString addr, int port, QString user, QString password);
-
- void registerIconList(std::shared_ptr<IIconList> iconlist);
-
- shared_qobject_ptr<Meta::Index> metadataIndex();
-
- QString getJarsPath();
- void setJarsPath(const QString & path);
-
- bool isFeatureEnabled(const QString & featureName) const;
- void enableFeature(const QString & featureName, bool state = true);
- void getEnabledFeatures(QSet<QString> & features) const;
- void setEnabledFeatures(const QSet<QString> & features) const;
-
-protected:
- Private * d;
-};
diff --git a/launcher/InstanceImportTask.cpp b/launcher/InstanceImportTask.cpp
index 3eac4d57..d0a63fe3 100644
--- a/launcher/InstanceImportTask.cpp
+++ b/launcher/InstanceImportTask.cpp
@@ -16,11 +16,10 @@
#include "InstanceImportTask.h"
#include "BaseInstance.h"
#include "FileSystem.h"
-#include "Env.h"
+#include "Application.h"
#include "MMCZip.h"
#include "NullInstance.h"
#include "settings/INISettingsObject.h"
-#include "icons/IIconList.h"
#include "icons/IconUtils.h"
#include <QtConcurrentRun>
@@ -33,6 +32,9 @@
#include <quazipdir.h>
#include "modplatform/technic/TechnicPackProcessor.h"
+#include "icons/IconList.h"
+#include "Application.h"
+
InstanceImportTask::InstanceImportTask(const QUrl sourceUrl)
{
m_sourceUrl = sourceUrl;
@@ -51,7 +53,7 @@ void InstanceImportTask::executeTask()
m_downloadRequired = true;
const QString path = m_sourceUrl.host() + '/' + m_sourceUrl.path();
- auto entry = ENV.metacache()->resolveEntry("general", path);
+ auto entry = APPLICATION->metacache()->resolveEntry("general", path);
entry->setStale(true);
m_filesNetJob.reset(new NetJob(tr("Modpack download")));
m_filesNetJob->addNetAction(Net::Download::makeCached(m_sourceUrl, entry));
@@ -60,7 +62,7 @@ void InstanceImportTask::executeTask()
connect(job, &NetJob::succeeded, this, &InstanceImportTask::downloadSucceeded);
connect(job, &NetJob::progress, this, &InstanceImportTask::downloadProgressChanged);
connect(job, &NetJob::failed, this, &InstanceImportTask::downloadFailed);
- m_filesNetJob->start();
+ m_filesNetJob->start(APPLICATION->network());
}
}
@@ -331,7 +333,7 @@ void InstanceImportTask::processFlame()
FS::deletePath(jarmodsPath);
}
instance.setName(m_instName);
- m_modIdResolver.reset(new Flame::FileResolvingTask(pack));
+ m_modIdResolver = new Flame::FileResolvingTask(APPLICATION->network(), pack);
connect(m_modIdResolver.get(), &Flame::FileResolvingTask::succeeded, [&]()
{
auto results = m_modIdResolver->getResults();
@@ -389,7 +391,7 @@ void InstanceImportTask::processFlame()
setProgress(current, total);
});
setStatus(tr("Downloading mods..."));
- m_filesNetJob->start();
+ m_filesNetJob->start(APPLICATION->network());
}
);
connect(m_modIdResolver.get(), &Flame::FileResolvingTask::failed, [&](QString reason)
@@ -418,7 +420,6 @@ void InstanceImportTask::processTechnic()
void InstanceImportTask::processMultiMC()
{
- // FIXME: copy from FolderInstanceProvider!!! FIX IT!!!
QString configPath = FS::PathCombine(m_stagingPath, "instance.cfg");
auto instanceSettings = std::make_shared<INISettingsObject>(configPath);
instanceSettings->registerSetting("InstanceType", "Legacy");
@@ -444,7 +445,7 @@ void InstanceImportTask::processMultiMC()
if (!importIconPath.isNull() && QFile::exists(importIconPath))
{
// import icon
- auto iconList = ENV.icons();
+ auto iconList = APPLICATION->icons();
if (iconList->iconFileExists(m_instIcon))
{
iconList->deleteIcon(m_instIcon);
diff --git a/launcher/InstanceImportTask.h b/launcher/InstanceImportTask.h
index 72ae6851..a1990647 100644
--- a/launcher/InstanceImportTask.h
+++ b/launcher/InstanceImportTask.h
@@ -55,7 +55,7 @@ private slots:
void extractAborted();
private: /* data */
- NetJobPtr m_filesNetJob;
+ NetJob::Ptr m_filesNetJob;
shared_qobject_ptr<Flame::FileResolvingTask> m_modIdResolver;
QUrl m_sourceUrl;
QString m_archivePath;
diff --git a/launcher/InstancePageProvider.h b/launcher/InstancePageProvider.h
index d45b3f2e..2af90b91 100644
--- a/launcher/InstancePageProvider.h
+++ b/launcher/InstancePageProvider.h
@@ -2,24 +2,22 @@
#include "minecraft/MinecraftInstance.h"
#include "minecraft/legacy/LegacyInstance.h"
#include <FileSystem.h>
-#include "pages/BasePage.h"
-#include "pages/BasePageProvider.h"
-#include "pages/instance/LogPage.h"
-#include "pages/instance/VersionPage.h"
-#include "pages/instance/ModFolderPage.h"
-#include "pages/instance/ResourcePackPage.h"
-#include "pages/instance/TexturePackPage.h"
-#include "pages/instance/ShaderPackPage.h"
-#include "pages/instance/NotesPage.h"
-#include "pages/instance/ScreenshotsPage.h"
-#include "pages/instance/InstanceSettingsPage.h"
-#include "pages/instance/OtherLogsPage.h"
-#include "pages/instance/LegacyUpgradePage.h"
-#include "pages/instance/WorldListPage.h"
-#include "pages/instance/ServersPage.h"
-#include "pages/instance/GameOptionsPage.h"
-
-#include "Env.h"
+#include "ui/pages/BasePage.h"
+#include "ui/pages/BasePageProvider.h"
+#include "ui/pages/instance/LogPage.h"
+#include "ui/pages/instance/VersionPage.h"
+#include "ui/pages/instance/ModFolderPage.h"
+#include "ui/pages/instance/ResourcePackPage.h"
+#include "ui/pages/instance/TexturePackPage.h"
+#include "ui/pages/instance/ShaderPackPage.h"
+#include "ui/pages/instance/NotesPage.h"
+#include "ui/pages/instance/ScreenshotsPage.h"
+#include "ui/pages/instance/InstanceSettingsPage.h"
+#include "ui/pages/instance/OtherLogsPage.h"
+#include "ui/pages/instance/LegacyUpgradePage.h"
+#include "ui/pages/instance/WorldListPage.h"
+#include "ui/pages/instance/ServersPage.h"
+#include "ui/pages/instance/GameOptionsPage.h"
class InstancePageProvider : public QObject, public BasePageProvider
{
diff --git a/launcher/JavaCommon.cpp b/launcher/JavaCommon.cpp
index 92a058f0..6fa5851b 100644
--- a/launcher/JavaCommon.cpp
+++ b/launcher/JavaCommon.cpp
@@ -1,5 +1,5 @@
#include "JavaCommon.h"
-#include "dialogs/CustomMessageBox.h"
+#include "ui/dialogs/CustomMessageBox.h"
#include <MMCStrings.h>
bool JavaCommon::checkJVMArgs(QString jvmargs, QWidget *parent)
diff --git a/launcher/LaunchController.cpp b/launcher/LaunchController.cpp
index 1c1e41e6..be12eb79 100644
--- a/launcher/LaunchController.cpp
+++ b/launcher/LaunchController.cpp
@@ -1,24 +1,28 @@
#include "LaunchController.h"
-#include "MainWindow.h"
-#include <minecraft/auth/AccountList.h>
-#include "Launcher.h"
-#include "dialogs/CustomMessageBox.h"
-#include "dialogs/ProfileSelectDialog.h"
-#include "dialogs/ProgressDialog.h"
-#include "dialogs/EditAccountDialog.h"
-#include "InstanceWindow.h"
-#include "BuildConfig.h"
-#include "JavaCommon.h"
+#include "minecraft/auth/AccountList.h"
+#include "Application.h"
+
+#include "ui/MainWindow.h"
+#include "ui/InstanceWindow.h"
+#include "ui/dialogs/CustomMessageBox.h"
+#include "ui/dialogs/ProfileSelectDialog.h"
+#include "ui/dialogs/ProgressDialog.h"
+#include "ui/dialogs/EditAccountDialog.h"
+#include "ui/dialogs/ProfileSetupDialog.h"
+
#include <QLineEdit>
#include <QInputDialog>
-#include <tasks/Task.h>
-#include <minecraft/auth/AccountTask.h>
-#include <launch/steps/TextPrint.h>
#include <QStringList>
#include <QHostInfo>
#include <QList>
#include <QHostAddress>
+#include "BuildConfig.h"
+#include "JavaCommon.h"
+#include "tasks/Task.h"
+#include "minecraft/auth/AccountTask.h"
+#include "launch/steps/TextPrint.h"
+
LaunchController::LaunchController(QObject *parent) : Task(parent)
{
}
@@ -31,6 +35,8 @@ void LaunchController::executeTask()
return;
}
+ JavaCommon::checkJVMArgs(m_instance->settings()->get("JvmArgs").toString(), m_parentWidget);
+
login();
}
@@ -41,7 +47,7 @@ void LaunchController::decideAccount()
}
// Find an account to use.
- std::shared_ptr<AccountList> accounts = LAUNCHER->accounts();
+ auto accounts = APPLICATION->accounts();
if (accounts->count() <= 0)
{
// Tell the user they need to log in at least one account in order to play.
@@ -58,12 +64,12 @@ void LaunchController::decideAccount()
if (reply == QMessageBox::Yes)
{
// Open the account manager.
- LAUNCHER->ShowGlobalSettings(m_parentWidget, "accounts");
+ APPLICATION->ShowGlobalSettings(m_parentWidget, "accounts");
}
}
- m_accountToUse = accounts->activeAccount();
- if (m_accountToUse == nullptr)
+ m_accountToUse = accounts->defaultAccount();
+ if (!m_accountToUse)
{
// If no default account is set, ask the user which one to use.
ProfileSelectDialog selectDialog(
@@ -79,15 +85,13 @@ void LaunchController::decideAccount()
// If the user said to use the account as default, do that.
if (selectDialog.useAsGlobalDefault() && m_accountToUse) {
- accounts->setActiveAccount(m_accountToUse->profileId());
+ accounts->setDefaultAccount(m_accountToUse);
}
}
}
void LaunchController::login() {
- JavaCommon::checkJVMArgs(m_instance->settings()->get("JvmArgs").toString(), m_parentWidget);
-
decideAccount();
// if no account is selected, we bail
@@ -109,132 +113,118 @@ void LaunchController::login() {
{
m_session = std::make_shared<AuthSession>();
m_session->wants_online = m_online;
- std::shared_ptr<AccountTask> task;
- if(!password.isNull()) {
- task = m_accountToUse->login(m_session, password);
- }
- else {
- task = m_accountToUse->refresh(m_session);
- }
- if (task)
- {
- // We'll need to validate the access token to make sure the account
- // is still logged in.
- ProgressDialog progDialog(m_parentWidget);
- if (m_online)
- {
- progDialog.setSkipButton(true, tr("Play Offline"));
+ m_accountToUse->fillSession(m_session);
+
+ switch(m_accountToUse->accountState()) {
+ case AccountState::Offline: {
+ m_session->wants_online = false;
+ // NOTE: fallthrough is intentional
}
- progDialog.execWithTask(task.get());
- if (!task->wasSuccessful())
- {
- auto failReasonNew = task->failReason();
- if(failReasonNew == "Invalid token." || failReasonNew == "Invalid Signature")
- {
- // account->invalidateClientToken();
- failReason = needLoginAgain;
+ case AccountState::Online: {
+ if(!m_session->wants_online) {
+ // we ask the user for a player name
+ bool ok = false;
+ QString usedname = m_session->player_name;
+ QString name = QInputDialog::getText(
+ m_parentWidget,
+ tr("Player name"),
+ tr("Choose your offline mode player name."),
+ QLineEdit::Normal,
+ m_session->player_name,
+ &ok
+ );
+ if (!ok)
+ {
+ tryagain = false;
+ break;
+ }
+ if (name.length())
+ {
+ usedname = name;
+ }
+ m_session->MakeOffline(usedname);
+ // offline flavored game from here :3
}
- else failReason = failReasonNew;
- }
- }
- switch (m_session->status)
- {
- case AuthSession::Undetermined: {
- qCritical() << "Received undetermined session status during login. Bye.";
- tryagain = false;
- emitFailed(tr("Received undetermined session status during login."));
- return;
- }
- case AuthSession::RequiresPassword: {
- // FIXME: this needs to understand MSA
- EditAccountDialog passDialog(failReason, m_parentWidget, EditAccountDialog::PasswordField);
- auto username = m_session->username;
- auto chopN = [](QString toChop, int N) -> QString
- {
- if(toChop.size() > N)
+ if(m_accountToUse->ownsMinecraft() && !m_accountToUse->hasProfile()) {
+ auto entitlement = m_accountToUse->accountData()->minecraftEntitlement;
+ QString errorString;
+ if(!entitlement.canPlayMinecraft) {
+ errorString = tr("The account does not own Minecraft. You need to purchase the game first to play it.");
+ QMessageBox::warning(
+ nullptr,
+ tr("Missing Minecraft profile"),
+ errorString,
+ QMessageBox::StandardButton::Ok,
+ QMessageBox::StandardButton::Ok
+ );
+ emitFailed(errorString);
+ return;
+ }
+ // Now handle setting up a profile name here...
+ ProfileSetupDialog dialog(m_accountToUse, m_parentWidget);
+ if (dialog.exec() == QDialog::Accepted)
{
- auto left = toChop.left(N);
- left += QString("\u25CF").repeated(toChop.size() - N);
- return left;
+ tryagain = true;
+ continue;
+ }
+ else
+ {
+ emitFailed(tr("Received undetermined session status during login."));
+ return;
}
- return toChop;
- };
-
- if(username.contains('@'))
- {
- auto parts = username.split('@');
- auto mailbox = chopN(parts[0],3);
- QString domain = chopN(parts[1], 3);
- username = mailbox + '@' + domain;
}
- passDialog.setUsername(username);
- if (passDialog.exec() == QDialog::Accepted)
- {
- password = passDialog.password();
+ else {
+ launchInstance();
}
- else
+ return;
+ }
+ case AccountState::Errored:
+ // This means some sort of soft error that we can fix with a refresh ... so let's refresh.
+ case AccountState::Unchecked: {
+ m_accountToUse->refresh();
+ // NOTE: fallthrough intentional
+ }
+ case AccountState::Working: {
+ // refresh is in progress, we need to wait for it to finish to proceed.
+ ProgressDialog progDialog(m_parentWidget);
+ if (m_online)
{
- tryagain = false;
- emitFailed(tr("Received undetermined session status during login."));
+ progDialog.setSkipButton(true, tr("Play Offline"));
}
- break;
+ auto task = m_accountToUse->currentTask();
+ progDialog.execWithTask(task.get());
+ continue;
}
- case AuthSession::RequiresOAuth: {
- auto errorString = tr("Microsoft account has expired and needs to be logged into manually again.");
+ // FIXME: this is missing - the meaning is that the account is queued for refresh and we should wait for that
+ /*
+ case AccountState::Queued: {
+ return;
+ }
+ */
+ case AccountState::Expired: {
+ auto errorString = tr("The account has expired and needs to be logged into manually again.");
QMessageBox::warning(
- nullptr,
- tr("Microsoft Account refresh failed"),
+ m_parentWidget,
+ tr("Account refresh failed"),
errorString,
QMessageBox::StandardButton::Ok,
QMessageBox::StandardButton::Ok
);
- tryagain = false;
emitFailed(errorString);
return;
}
- case AuthSession::GoneOrMigrated: {
+ case AccountState::Gone: {
auto errorString = tr("The account no longer exists on the servers. It may have been migrated, in which case please add the new account you migrated this one to.");
QMessageBox::warning(
- nullptr,
+ m_parentWidget,
tr("Account gone"),
errorString,
QMessageBox::StandardButton::Ok,
QMessageBox::StandardButton::Ok
);
- tryagain = false;
emitFailed(errorString);
return;
}
- case AuthSession::PlayableOffline: {
- // we ask the user for a player name
- bool ok = false;
- QString usedname = m_session->player_name;
- QString name = QInputDialog::getText(
- m_parentWidget,
- tr("Player name"),
- tr("Choose your offline mode player name."),
- QLineEdit::Normal,
- m_session->player_name,
- &ok
- );
- if (!ok)
- {
- tryagain = false;
- break;
- }
- if (name.length())
- {
- usedname = name;
- }
- m_session->MakeOffline(usedname);
- // offline flavored game from here :3
- }
- case AuthSession::PlayableOnline:
- {
- launchInstance();
- tryagain = false;
- return;
- }
}
}
emitFailed(tr("Failed to launch."));
@@ -263,7 +253,7 @@ void LaunchController::launchInstance()
auto showConsole = m_instance->settings()->get("ShowConsole").toBool();
if(!console && showConsole)
{
- LAUNCHER->showInstanceWindow(m_instance);
+ APPLICATION->showInstanceWindow(m_instance);
}
connect(m_launcher.get(), &LaunchTask::readyForLaunch, this, &LaunchController::readyForLaunch);
connect(m_launcher.get(), &LaunchTask::succeeded, this, &LaunchController::onSucceeded);
@@ -300,14 +290,7 @@ void LaunchController::launchInstance()
online_mode = "offline";
}
- QString auth_server_status;
- if(m_session->auth_server_online) {
- auth_server_status = "online";
- } else {
- auth_server_status = "offline";
- }
-
- m_launcher->prependStep(new TextPrint(m_launcher.get(), "Launched instance in " + online_mode + " mode\nAuthentication server is " + auth_server_status + "\n", MessageLevel::Launcher));
+ m_launcher->prependStep(new TextPrint(m_launcher.get(), "Launched instance in " + online_mode + " mode\n", MessageLevel::Launcher));
// Prepend Version
m_launcher->prependStep(new TextPrint(m_launcher.get(), BuildConfig.LAUNCHER_NAME + " version: " + BuildConfig.printableVersionString() + "\n\n", MessageLevel::Launcher));
@@ -369,7 +352,7 @@ void LaunchController::onFailed(QString reason)
{
if(m_instance->settings()->get("ShowConsoleOnError").toBool())
{
- LAUNCHER->showInstanceWindow(m_instance, "console");
+ APPLICATION->showInstanceWindow(m_instance, "console");
}
emitFailed(reason);
}
diff --git a/launcher/NullInstance.h b/launcher/NullInstance.h
index 94ed6c3a..ed421433 100644
--- a/launcher/NullInstance.h
+++ b/launcher/NullInstance.h
@@ -73,4 +73,7 @@ public:
out << "Null instance - placeholder.";
return out;
}
+ QString modsRoot() const override {
+ return QString();
+ }
};
diff --git a/launcher/QObjectPtr.h b/launcher/QObjectPtr.h
index 0ff51136..57974939 100644
--- a/launcher/QObjectPtr.h
+++ b/launcher/QObjectPtr.h
@@ -77,6 +77,12 @@ public:
{
return m_ptr;
}
+ bool operator==(const shared_qobject_ptr<T>& other) {
+ return m_ptr == other.m_ptr;
+ }
+ bool operator!=(const shared_qobject_ptr<T>& other) {
+ return m_ptr != other.m_ptr;
+ }
private:
std::shared_ptr <T> m_ptr;
diff --git a/launcher/SkinUtils.cpp b/launcher/SkinUtils.cpp
index a196173e..1fe0c896 100644
--- a/launcher/SkinUtils.cpp
+++ b/launcher/SkinUtils.cpp
@@ -15,7 +15,7 @@
#include "SkinUtils.h"
#include "net/HttpMetaCache.h"
-#include "Env.h"
+#include "Application.h"
#include <QFile>
#include <QPainter>
@@ -30,7 +30,7 @@ namespace SkinUtils
*/
QPixmap getFaceFromCache(QString username, int height, int width)
{
- QFile fskin(ENV.metacache()->resolveEntry("skins", username + ".png")->getFullPath());
+ QFile fskin(APPLICATION->metacache()->resolveEntry("skins", username + ".png")->getFullPath());
if (fskin.exists())
{
diff --git a/launcher/Usable.h b/launcher/Usable.h
index 83dd083d..a3e880f3 100644
--- a/launcher/Usable.h
+++ b/launcher/Usable.h
@@ -3,6 +3,8 @@
#include <cstddef>
#include <memory>
+#include "QObjectPtr.h"
+
class Usable;
/**
@@ -14,11 +16,11 @@ class Usable
{
friend class UseLock;
public:
- std::size_t useCount()
+ std::size_t useCount() const
{
return m_useCount;
}
- bool isInUse()
+ bool isInUse() const
{
return m_useCount > 0;
}
@@ -43,7 +45,7 @@ private:
class UseLock
{
public:
- UseLock(std::shared_ptr<Usable> usable)
+ UseLock(shared_qobject_ptr<Usable> usable)
: m_usable(usable)
{
// this doesn't use shared pointer use count, because that wouldn't be correct. this count is separate.
@@ -54,5 +56,5 @@ public:
m_usable->decrementUses();
}
private:
- std::shared_ptr<Usable> m_usable;
+ shared_qobject_ptr<Usable> m_usable;
};
diff --git a/launcher/VersionProxyModel.cpp b/launcher/VersionProxyModel.cpp
index 12f9bdd8..b9a87c9c 100644
--- a/launcher/VersionProxyModel.cpp
+++ b/launcher/VersionProxyModel.cpp
@@ -1,5 +1,5 @@
#include "VersionProxyModel.h"
-#include "Launcher.h"
+#include "Application.h"
#include <QSortFilterProxyModel>
#include <QPixmapCache>
#include <Version.h>
@@ -194,19 +194,19 @@ QVariant VersionProxyModel::data(const QModelIndex &index, int role) const
auto value = sourceModel()->data(parentIndex, BaseVersionList::RecommendedRole);
if(value.toBool())
{
- return LAUNCHER->getThemedIcon("star");
+ return APPLICATION->getThemedIcon("star");
}
else if(hasLatest)
{
auto value = sourceModel()->data(parentIndex, BaseVersionList::LatestRole);
if(value.toBool())
{
- return LAUNCHER->getThemedIcon("bug");
+ return APPLICATION->getThemedIcon("bug");
}
}
else if(index.row() == 0)
{
- return LAUNCHER->getThemedIcon("bug");
+ return APPLICATION->getThemedIcon("bug");
}
auto pixmap = QPixmapCache::find("placeholder");
if(!pixmap)
diff --git a/launcher/icons/IIconList.cpp b/launcher/icons/IIconList.cpp
deleted file mode 100644
index b3a8fb43..00000000
--- a/launcher/icons/IIconList.cpp
+++ /dev/null
@@ -1,7 +0,0 @@
-#include "IIconList.h"
-
-// blargh
-IIconList::~IIconList()
-{
-}
-
diff --git a/launcher/icons/IIconList.h b/launcher/icons/IIconList.h
deleted file mode 100644
index 15d7dd15..00000000
--- a/launcher/icons/IIconList.h
+++ /dev/null
@@ -1,25 +0,0 @@
-#pragma once
-
-#include <QString>
-#include <QStringList>
-
-enum IconType : unsigned
-{
- Builtin,
- Transient,
- FileBased,
- ICONS_TOTAL,
- ToBeDeleted
-};
-
-class IIconList
-{
-public:
- virtual ~IIconList();
- virtual bool addIcon(const QString &key, const QString &name, const QString &path, const IconType type) = 0;
- virtual bool deleteIcon(const QString &key) = 0;
- virtual void saveIcon(const QString &key, const QString &path, const char * format) const = 0;
- virtual bool iconFileExists(const QString &key) const = 0;
- virtual void installIcons(const QStringList &iconFiles) = 0;
- virtual void installIcon(const QString &file, const QString &name) = 0;
-};
diff --git a/launcher/icons/IconList.h b/launcher/icons/IconList.h
index 70266ebb..ebbb52e2 100644
--- a/launcher/icons/IconList.h
+++ b/launcher/icons/IconList.h
@@ -21,14 +21,15 @@
#include <QDir>
#include <QtGui/QIcon>
#include <memory>
+
#include "MMCIcon.h"
#include "settings/Setting.h"
-#include "Env.h" // there is a global icon list inside Env.
-#include <icons/IIconList.h>
+
+#include "QObjectPtr.h"
class QFileSystemWatcher;
-class IconList : public QAbstractListModel, public IIconList
+class IconList : public QAbstractListModel
{
Q_OBJECT
public:
@@ -42,19 +43,19 @@ public:
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override;
- bool addThemeIcon(const QString &key);
- bool addIcon(const QString &key, const QString &name, const QString &path, const IconType type) override;
- void saveIcon(const QString &key, const QString &path, const char * format) const override;
- bool deleteIcon(const QString &key) override;
- bool iconFileExists(const QString &key) const override;
-
virtual QStringList mimeTypes() const override;
virtual Qt::DropActions supportedDropActions() const override;
virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override;
virtual Qt::ItemFlags flags(const QModelIndex &index) const override;
- void installIcons(const QStringList &iconFiles) override;
- void installIcon(const QString &file, const QString &name) override;
+ bool addThemeIcon(const QString &key);
+ bool addIcon(const QString &key, const QString &name, const QString &path, const IconType type);
+ void saveIcon(const QString &key, const QString &path, const char * format) const;
+ bool deleteIcon(const QString &key);
+ bool iconFileExists(const QString &key) const;
+
+ void installIcons(const QStringList &iconFiles);
+ void installIcon(const QString &file, const QString &name);
const MMCIcon * icon(const QString &key) const;
diff --git a/launcher/icons/MMCIcon.h b/launcher/icons/MMCIcon.h
index 1f05f28e..13d99318 100644
--- a/launcher/icons/MMCIcon.h
+++ b/launcher/icons/MMCIcon.h
@@ -17,7 +17,15 @@
#include <QString>
#include <QDateTime>
#include <QIcon>
-#include <icons/IIconList.h>
+
+enum IconType : unsigned
+{
+ Builtin,
+ Transient,
+ FileBased,
+ ICONS_TOTAL,
+ ToBeDeleted
+};
struct MMCImage
{
diff --git a/launcher/java/JavaChecker.cpp b/launcher/java/JavaChecker.cpp
index 81c61ab0..80c599cc 100644
--- a/launcher/java/JavaChecker.cpp
+++ b/launcher/java/JavaChecker.cpp
@@ -1,14 +1,14 @@
#include "JavaChecker.h"
-#include "JavaUtils.h"
-#include <FileSystem.h>
-#include <Commandline.h>
+
#include <QFile>
#include <QProcess>
#include <QMap>
-#include <QCoreApplication>
#include <QDebug>
-#include "Env.h"
+#include "JavaUtils.h"
+#include "FileSystem.h"
+#include "Commandline.h"
+#include "Application.h"
JavaChecker::JavaChecker(QObject *parent) : QObject(parent)
{
@@ -16,7 +16,7 @@ JavaChecker::JavaChecker(QObject *parent) : QObject(parent)
void JavaChecker::performCheck()
{
- QString checkerJar = FS::PathCombine(ENV.getJarsPath(), "JavaCheck.jar");
+ QString checkerJar = FS::PathCombine(APPLICATION->getJarsPath(), "JavaCheck.jar");
QStringList args;
diff --git a/launcher/java/JavaInstallList.cpp b/launcher/java/JavaInstallList.cpp
index 0bded03c..07f2bd8c 100644
--- a/launcher/java/JavaInstallList.cpp
+++ b/launcher/java/JavaInstallList.cpp
@@ -29,13 +29,13 @@ JavaInstallList::JavaInstallList(QObject *parent) : BaseVersionList(parent)
{
}
-shared_qobject_ptr<Task> JavaInstallList::getLoadTask()
+Task::Ptr JavaInstallList::getLoadTask()
{
load();
return getCurrentTask();
}
-shared_qobject_ptr<Task> JavaInstallList::getCurrentTask()
+Task::Ptr JavaInstallList::getCurrentTask()
{
if(m_status == Status::InProgress)
{
diff --git a/launcher/java/JavaInstallList.h b/launcher/java/JavaInstallList.h
index e5c72b17..3c237edf 100644
--- a/launcher/java/JavaInstallList.h
+++ b/launcher/java/JavaInstallList.h
@@ -40,7 +40,7 @@ class JavaInstallList : public BaseVersionList
public:
explicit JavaInstallList(QObject *parent = 0);
- shared_qobject_ptr<Task> getLoadTask() override;
+ Task::Ptr getLoadTask() override;
bool isLoaded() override;
const BaseVersionPtr at(int i) const override;
int count() const override;
@@ -54,7 +54,7 @@ public slots:
protected:
void load();
- shared_qobject_ptr<Task> getCurrentTask();
+ Task::Ptr getCurrentTask();
protected:
Status m_status = Status::NotDone;
diff --git a/launcher/java/JavaUtils.cpp b/launcher/java/JavaUtils.cpp
index c00ee710..6b58db37 100644
--- a/launcher/java/JavaUtils.cpp
+++ b/launcher/java/JavaUtils.cpp
@@ -265,12 +265,18 @@ QList<QString> JavaUtils::FindJavaPaths()
QList<JavaInstallPtr> ADOPTOPENJDK64s = this->FindJavaFromRegistryKey(
KEY_WOW64_64KEY, "SOFTWARE\\AdoptOpenJDK\\JDK", "Path", "\\hotspot\\MSI");
- // Adoptium (Eclipse)
- QList<JavaInstallPtr> ECLIPSEJDK32s = this->FindJavaFromRegistryKey(
+ // Foundation (Eclipse)
+ QList<JavaInstallPtr> FOUNDATIONJDK32s = this->FindJavaFromRegistryKey(
KEY_WOW64_32KEY, "SOFTWARE\\Eclipse Foundation\\JDK", "Path", "\\hotspot\\MSI");
- QList<JavaInstallPtr> ECLIPSEJDK64s = this->FindJavaFromRegistryKey(
+ QList<JavaInstallPtr> FOUNDATIONJDK64s = this->FindJavaFromRegistryKey(
KEY_WOW64_64KEY, "SOFTWARE\\Eclipse Foundation\\JDK", "Path", "\\hotspot\\MSI");
+ // Adoptium (Eclipse)
+ QList<JavaInstallPtr> ADOPTIUMJDK32s = this->FindJavaFromRegistryKey(
+ KEY_WOW64_32KEY, "SOFTWARE\\Eclipse Adoptium\\JDK", "Path", "\\hotspot\\MSI");
+ QList<JavaInstallPtr> ADOPTIUMJDK64s = this->FindJavaFromRegistryKey(
+ KEY_WOW64_64KEY, "SOFTWARE\\Eclipse Adoptium\\JDK", "Path", "\\hotspot\\MSI");
+
// Microsoft
QList<JavaInstallPtr> MICROSOFTJDK64s = this->FindJavaFromRegistryKey(
KEY_WOW64_64KEY, "SOFTWARE\\Microsoft\\JDK", "Path", "\\hotspot\\MSI");
@@ -297,7 +303,8 @@ QList<QString> JavaUtils::FindJavaPaths()
java_candidates.append(JDK64s);
java_candidates.append(NEWJDK64s);
java_candidates.append(ADOPTOPENJDK64s);
- java_candidates.append(ECLIPSEJDK64s);
+ java_candidates.append(FOUNDATIONJDK64s);
+ java_candidates.append(ADOPTIUMJDK64s);
java_candidates.append(MICROSOFTJDK64s);
java_candidates.append(ZULU64s);
java_candidates.append(LIBERICA64s);
@@ -311,7 +318,8 @@ QList<QString> JavaUtils::FindJavaPaths()
java_candidates.append(JDK32s);
java_candidates.append(NEWJDK32s);
java_candidates.append(ADOPTOPENJDK32s);
- java_candidates.append(ECLIPSEJDK32s);
+ java_candidates.append(FOUNDATIONJDK32s);
+ java_candidates.append(ADOPTIUMJDK32s);
java_candidates.append(ZULU32s);
java_candidates.append(LIBERICA32s);
@@ -386,6 +394,7 @@ QList<QString> JavaUtils::FindJavaPaths()
scanJavaDir("/usr/java");
// general locations used by distro packaging
scanJavaDir("/usr/lib/jvm");
+ scanJavaDir("/usr/lib64/jvm");
scanJavaDir("/usr/lib32/jvm");
// javas stored in MultiMC's folder
scanJavaDir("java");
diff --git a/launcher/java/launch/CheckJava.cpp b/launcher/launch/steps/CheckJava.cpp
index fb338231..fb338231 100644
--- a/launcher/java/launch/CheckJava.cpp
+++ b/launcher/launch/steps/CheckJava.cpp
diff --git a/launcher/java/launch/CheckJava.h b/launcher/launch/steps/CheckJava.h
index 68cd618b..68cd618b 100644
--- a/launcher/java/launch/CheckJava.h
+++ b/launcher/launch/steps/CheckJava.h
diff --git a/launcher/launch/steps/Update.h b/launcher/launch/steps/Update.h
index 0c9d91e0..ce40611e 100644
--- a/launcher/launch/steps/Update.h
+++ b/launcher/launch/steps/Update.h
@@ -39,7 +39,7 @@ private slots:
void updateFinished();
private:
- shared_qobject_ptr<Task> m_updateTask;
+ Task::Ptr m_updateTask;
bool m_aborted = false;
Net::Mode m_mode = Net::Mode::Offline;
};
diff --git a/launcher/main.cpp b/launcher/main.cpp
index 3c2b9445..aabb5a06 100644
--- a/launcher/main.cpp
+++ b/launcher/main.cpp
@@ -1,8 +1,4 @@
-#include "Launcher.h"
-#include "MainWindow.h"
-#include "LaunchController.h"
-#include <InstanceList.h>
-#include <QDebug>
+#include "Application.h"
// #define BREAK_INFINITE_LOOP
// #define BREAK_EXCEPTION
@@ -34,12 +30,12 @@ int main(int argc, char *argv[])
#endif
// initialize Qt
- Launcher app(argc, argv);
+ Application app(argc, argv);
switch (app.status())
{
- case Launcher::StartingUp:
- case Launcher::Initialized:
+ case Application::StartingUp:
+ case Application::Initialized:
{
Q_INIT_RESOURCE(multimc);
Q_INIT_RESOURCE(backgrounds);
@@ -55,9 +51,9 @@ int main(int argc, char *argv[])
Q_INIT_RESOURCE(flat);
return app.exec();
}
- case Launcher::Failed:
+ case Application::Failed:
return 1;
- case Launcher::Succeeded:
+ case Application::Succeeded:
return 0;
}
}
diff --git a/launcher/meta/BaseEntity.cpp b/launcher/meta/BaseEntity.cpp
index 5ff7a59a..a9d62fcd 100644
--- a/launcher/meta/BaseEntity.cpp
+++ b/launcher/meta/BaseEntity.cpp
@@ -15,16 +15,13 @@
#include "BaseEntity.h"
-#include "Json.h"
-
#include "net/Download.h"
#include "net/HttpMetaCache.h"
#include "net/NetJob.h"
-
-#include "Env.h"
#include "Json.h"
#include "BuildConfig.h"
+#include "Application.h"
class ParsingValidator : public Net::Validator
{
@@ -120,9 +117,9 @@ void Meta::BaseEntity::load(Net::Mode loadType)
{
return;
}
- NetJob *job = new NetJob(QObject::tr("Download of meta file %1").arg(localFilename()));
+ m_updateTask = new NetJob(QObject::tr("Download of meta file %1").arg(localFilename()));
auto url = this->url();
- auto entry = ENV.metacache()->resolveEntry("meta", localFilename());
+ auto entry = APPLICATION->metacache()->resolveEntry("meta", localFilename());
entry->setStale(true);
auto dl = Net::Download::makeCached(url, entry);
/*
@@ -130,21 +127,20 @@ void Meta::BaseEntity::load(Net::Mode loadType)
* If that fails, the file is not written to storage.
*/
dl->addValidator(new ParsingValidator(this));
- job->addNetAction(dl);
+ m_updateTask->addNetAction(dl);
m_updateStatus = UpdateStatus::InProgress;
- m_updateTask.reset(job);
- QObject::connect(job, &NetJob::succeeded, [&]()
+ QObject::connect(m_updateTask.get(), &NetJob::succeeded, [&]()
{
m_loadStatus = LoadStatus::Remote;
m_updateStatus = UpdateStatus::Succeeded;
m_updateTask.reset();
});
- QObject::connect(job, &NetJob::failed, [&]()
+ QObject::connect(m_updateTask.get(), &NetJob::failed, [&]()
{
m_updateStatus = UpdateStatus::Failed;
m_updateTask.reset();
});
- m_updateTask->start();
+ m_updateTask->start(APPLICATION->network());
}
bool Meta::BaseEntity::isLoaded() const
@@ -158,7 +154,7 @@ bool Meta::BaseEntity::shouldStartRemoteUpdate() const
return m_updateStatus != UpdateStatus::InProgress;
}
-shared_qobject_ptr<Task> Meta::BaseEntity::getCurrentTask()
+Task::Ptr Meta::BaseEntity::getCurrentTask()
{
if(m_updateStatus == UpdateStatus::InProgress)
{
diff --git a/launcher/meta/BaseEntity.h b/launcher/meta/BaseEntity.h
index eff43879..75fa384a 100644
--- a/launcher/meta/BaseEntity.h
+++ b/launcher/meta/BaseEntity.h
@@ -20,8 +20,8 @@
#include "QObjectPtr.h"
#include "net/Mode.h"
+#include "net/NetJob.h"
-class Task;
namespace Meta
{
class BaseEntity
@@ -54,7 +54,7 @@ public:
bool shouldStartRemoteUpdate() const;
void load(Net::Mode loadType);
- shared_qobject_ptr<Task> getCurrentTask();
+ Task::Ptr getCurrentTask();
protected: /* methods */
bool loadLocalFile();
@@ -62,6 +62,6 @@ protected: /* methods */
private:
LoadStatus m_loadStatus = LoadStatus::NotLoaded;
UpdateStatus m_updateStatus = UpdateStatus::NotDone;
- shared_qobject_ptr<Task> m_updateTask;
+ NetJob::Ptr m_updateTask;
};
}
diff --git a/launcher/meta/Index_test.cpp b/launcher/meta/Index_test.cpp
index b0892070..5d3ddc50 100644
--- a/launcher/meta/Index_test.cpp
+++ b/launcher/meta/Index_test.cpp
@@ -3,19 +3,12 @@
#include "meta/Index.h"
#include "meta/VersionList.h"
-#include "Env.h"
class IndexTest : public QObject
{
Q_OBJECT
private
slots:
- void test_isProvidedByEnv()
- {
- QVERIFY(ENV.metadataIndex());
- QCOMPARE(ENV.metadataIndex(), ENV.metadataIndex());
- }
-
void test_hasUid_and_getList()
{
Meta::Index windex({std::make_shared<Meta::VersionList>("list1"), std::make_shared<Meta::VersionList>("list2"), std::make_shared<Meta::VersionList>("list3")});
diff --git a/launcher/meta/VersionList.cpp b/launcher/meta/VersionList.cpp
index 607007eb..6d23ce9a 100644
--- a/launcher/meta/VersionList.cpp
+++ b/launcher/meta/VersionList.cpp
@@ -29,7 +29,7 @@ VersionList::VersionList(const QString &uid, QObject *parent)
setObjectName("Version list: " + uid);
}
-shared_qobject_ptr<Task> VersionList::getLoadTask()
+Task::Ptr VersionList::getLoadTask()
{
load(Net::Mode::Online);
return getCurrentTask();
diff --git a/launcher/meta/VersionList.h b/launcher/meta/VersionList.h
index 58cdafe7..378255df 100644
--- a/launcher/meta/VersionList.h
+++ b/launcher/meta/VersionList.h
@@ -41,7 +41,7 @@ public:
VersionPtrRole
};
- shared_qobject_ptr<Task> getLoadTask() override;
+ Task::Ptr getLoadTask() override;
bool isLoaded() override;
const BaseVersionPtr at(int i) const override;
int count() const override;
diff --git a/launcher/minecraft/AssetsUtils.cpp b/launcher/minecraft/AssetsUtils.cpp
index c01733b6..1c65a212 100644
--- a/launcher/minecraft/AssetsUtils.cpp
+++ b/launcher/minecraft/AssetsUtils.cpp
@@ -284,7 +284,7 @@ bool reconstructAssets(QString assetsId, QString resourcesFolder)
}
-NetActionPtr AssetObject::getDownloadAction()
+NetAction::Ptr AssetObject::getDownloadAction()
{
QFileInfo objectFile(getLocalPath());
if ((!objectFile.isFile()) || (objectFile.size() != size))
@@ -316,7 +316,7 @@ QString AssetObject::getRelPath()
return hash.left(2) + "/" + hash;
}
-NetJobPtr AssetsIndex::getDownloadJob()
+NetJob::Ptr AssetsIndex::getDownloadJob()
{
auto job = new NetJob(QObject::tr("Assets for %1").arg(id));
for (auto &object : objects.values())
diff --git a/launcher/minecraft/AssetsUtils.h b/launcher/minecraft/AssetsUtils.h
index 32e57060..3dbf19ed 100644
--- a/launcher/minecraft/AssetsUtils.h
+++ b/launcher/minecraft/AssetsUtils.h
@@ -25,7 +25,7 @@ struct AssetObject
QString getRelPath();
QUrl getUrl();
QString getLocalPath();
- NetActionPtr getDownloadAction();
+ NetAction::Ptr getDownloadAction();
QString hash;
qint64 size;
@@ -33,7 +33,7 @@ struct AssetObject
struct AssetsIndex
{
- NetJobPtr getDownloadJob();
+ NetJob::Ptr getDownloadJob();
QString id;
QMap<QString, AssetObject> objects;
diff --git a/launcher/minecraft/Component.cpp b/launcher/minecraft/Component.cpp
index 92821065..c7dd5e36 100644
--- a/launcher/minecraft/Component.cpp
+++ b/launcher/minecraft/Component.cpp
@@ -1,14 +1,16 @@
#include <meta/VersionList.h>
#include <meta/Index.h>
-#include <Env.h>
#include "Component.h"
+#include <QSaveFile>
+
#include "meta/Version.h"
#include "VersionFile.h"
#include "minecraft/PackProfile.h"
-#include <FileSystem.h>
-#include <QSaveFile>
+#include "FileSystem.h"
#include "OneSixVersionFormat.h"
+#include "Application.h"
+
#include <assert.h>
Component::Component(PackProfile * parent, const QString& uid)
@@ -85,9 +87,9 @@ std::shared_ptr<class VersionFile> Component::getVersionFile() const
std::shared_ptr<class Meta::VersionList> Component::getVersionList() const
{
// FIXME: what if the metadata index isn't loaded yet?
- if(ENV.metadataIndex()->hasUid(m_uid))
+ if(APPLICATION->metadataIndex()->hasUid(m_uid))
{
- return ENV.metadataIndex()->get(m_uid);
+ return APPLICATION->metadataIndex()->get(m_uid);
}
return nullptr;
}
@@ -192,7 +194,7 @@ bool Component::isRevertible()
{
if (isCustom())
{
- if(ENV.metadataIndex()->hasUid(m_uid))
+ if(APPLICATION->metadataIndex()->hasUid(m_uid))
{
return true;
}
@@ -266,7 +268,7 @@ void Component::setVersion(const QString& version)
// we don't have a file, therefore we are loaded with metadata
m_cachedVersion = version;
// see if the meta version is loaded
- auto metaVersion = ENV.metadataIndex()->get(m_uid, version);
+ auto metaVersion = APPLICATION->metadataIndex()->get(m_uid, version);
if(metaVersion->isLoaded())
{
// if yes, we can continue with that.
@@ -350,7 +352,7 @@ bool Component::revert()
m_file.reset();
// check local cache for metadata...
- auto version = ENV.metadataIndex()->get(m_uid, m_version);
+ auto version = APPLICATION->metadataIndex()->get(m_uid, m_version);
if(version->isLoaded())
{
m_metaVersion = version;
diff --git a/launcher/minecraft/ComponentUpdateTask.cpp b/launcher/minecraft/ComponentUpdateTask.cpp
index 241d9a49..8bc05a1b 100644
--- a/launcher/minecraft/ComponentUpdateTask.cpp
+++ b/launcher/minecraft/ComponentUpdateTask.cpp
@@ -3,16 +3,17 @@
#include "PackProfile_p.h"
#include "PackProfile.h"
#include "Component.h"
-#include <Env.h>
-#include <meta/Index.h>
-#include <meta/VersionList.h>
-#include <meta/Version.h>
+#include "meta/Index.h"
+#include "meta/VersionList.h"
+#include "meta/Version.h"
#include "ComponentUpdateTask_p.h"
-#include <cassert>
-#include <Version.h>
+#include "cassert"
+#include "Version.h"
#include "net/Mode.h"
#include "OneSixVersionFormat.h"
+#include "Application.h"
+
/*
* This is responsible for loading the components of a component list AND resolving dependency issues between them
*/
@@ -68,7 +69,7 @@ LoadResult composeLoadResult(LoadResult a, LoadResult b)
return a;
}
-static LoadResult loadComponent(ComponentPtr component, shared_qobject_ptr<Task>& loadTask, Net::Mode netmode)
+static LoadResult loadComponent(ComponentPtr component, Task::Ptr& loadTask, Net::Mode netmode)
{
if(component->m_loaded)
{
@@ -102,7 +103,7 @@ static LoadResult loadComponent(ComponentPtr component, shared_qobject_ptr<Task>
}
else
{
- auto metaVersion = ENV.metadataIndex()->get(component->m_uid, component->m_version);
+ auto metaVersion = APPLICATION->metadataIndex()->get(component->m_uid, component->m_version);
component->m_metaVersion = metaVersion;
if(metaVersion->isLoaded())
{
@@ -126,7 +127,7 @@ static LoadResult loadComponent(ComponentPtr component, shared_qobject_ptr<Task>
// FIXME: dead code. determine if this can still be useful?
/*
-static LoadResult loadPackProfile(ComponentPtr component, shared_qobject_ptr<Task>& loadTask, Net::Mode netmode)
+static LoadResult loadPackProfile(ComponentPtr component, Task::Ptr& loadTask, Net::Mode netmode)
{
if(component->m_loaded)
{
@@ -135,7 +136,7 @@ static LoadResult loadPackProfile(ComponentPtr component, shared_qobject_ptr<Tas
}
LoadResult result = LoadResult::Failed;
- auto metaList = ENV.metadataIndex()->get(component->m_uid);
+ auto metaList = APPLICATION->metadataIndex()->get(component->m_uid);
if(metaList->isLoaded())
{
component->m_loaded = true;
@@ -151,16 +152,16 @@ static LoadResult loadPackProfile(ComponentPtr component, shared_qobject_ptr<Tas
}
*/
-static LoadResult loadIndex(shared_qobject_ptr<Task>& loadTask, Net::Mode netmode)
+static LoadResult loadIndex(Task::Ptr& loadTask, Net::Mode netmode)
{
// FIXME: DECIDE. do we want to run the update task anyway?
- if(ENV.metadataIndex()->isLoaded())
+ if(APPLICATION->metadataIndex()->isLoaded())
{
qDebug() << "Index is already loaded";
return LoadResult::LoadedLocal;
}
- ENV.metadataIndex()->load(netmode);
- loadTask = ENV.metadataIndex()->getCurrentTask();
+ APPLICATION->metadataIndex()->load(netmode);
+ loadTask = APPLICATION->metadataIndex()->getCurrentTask();
if(loadTask)
{
return LoadResult::RequiresRemote;
@@ -179,7 +180,7 @@ void ComponentUpdateTask::loadComponents()
// load the main index (it is needed to determine if components can revert)
{
// FIXME: tear out as a method? or lambda?
- shared_qobject_ptr<Task> indexLoadTask;
+ Task::Ptr indexLoadTask;
auto singleResult = loadIndex(indexLoadTask, d->netmode);
result = composeLoadResult(result, singleResult);
if(indexLoadTask)
@@ -202,7 +203,7 @@ void ComponentUpdateTask::loadComponents()
// load all the components OR their lists...
for (auto component: d->m_list->d->components)
{
- shared_qobject_ptr<Task> loadTask;
+ Task::Ptr loadTask;
LoadResult singleResult;
RemoteLoadStatus::Type loadType;
// FIXME: to do this right, we need to load the lists and decide on which versions to use during dependency resolution. For now, ignore all that...
diff --git a/launcher/minecraft/Library.cpp b/launcher/minecraft/Library.cpp
index f2293679..c7982705 100644
--- a/launcher/minecraft/Library.cpp
+++ b/launcher/minecraft/Library.cpp
@@ -3,7 +3,6 @@
#include <net/Download.h>
#include <net/ChecksumValidator.h>
-#include <Env.h>
#include <FileSystem.h>
#include <BuildConfig.h>
@@ -45,14 +44,14 @@ void Library::getApplicableFiles(OpSys system, QStringList& jar, QStringList& na
}
}
-QList< std::shared_ptr< NetAction > > Library::getDownloads(
+QList<NetAction::Ptr> Library::getDownloads(
OpSys system,
class HttpMetaCache* cache,
QStringList& failedLocalFiles,
const QString & overridePath
) const
{
- QList<NetActionPtr> out;
+ QList<NetAction::Ptr> out;
bool stale = isAlwaysStale();
bool local = isLocal();
diff --git a/launcher/minecraft/Library.h b/launcher/minecraft/Library.h
index 119b4a86..41d41a8b 100644
--- a/launcher/minecraft/Library.h
+++ b/launcher/minecraft/Library.h
@@ -152,7 +152,7 @@ public: /* methods */
bool isForge() const;
// Get a list of downloads for this library
- QList<NetActionPtr> getDownloads(OpSys system, class HttpMetaCache * cache,
+ QList<NetAction::Ptr> getDownloads(OpSys system, class HttpMetaCache * cache,
QStringList & failedLocalFiles, const QString & overridePath) const;
private: /* methods */
diff --git a/launcher/minecraft/Library_test.cpp b/launcher/minecraft/Library_test.cpp
index 75bb4db1..47531ad6 100644
--- a/launcher/minecraft/Library_test.cpp
+++ b/launcher/minecraft/Library_test.cpp
@@ -55,7 +55,7 @@ slots:
auto downloads = test.getDownloads(currentSystem, cache.get(), failedFiles, QString());
QCOMPARE(downloads.size(), 1);
QCOMPARE(failedFiles, {});
- NetActionPtr dl = downloads[0];
+ NetAction::Ptr dl = downloads[0];
QCOMPARE(dl->m_url, QUrl("file://foo/bar/test/package/testname/testversion/testname-testversion.jar"));
}
void test_legacy_url_local_broken()
diff --git a/launcher/minecraft/MinecraftInstance.cpp b/launcher/minecraft/MinecraftInstance.cpp
index 2982a340..2526e620 100644
--- a/launcher/minecraft/MinecraftInstance.cpp
+++ b/launcher/minecraft/MinecraftInstance.cpp
@@ -1,15 +1,16 @@
#include "MinecraftInstance.h"
-#include <minecraft/launch/CreateGameFolders.h>
-#include <minecraft/launch/ExtractNatives.h>
-#include <minecraft/launch/PrintInstanceInfo.h>
-#include <settings/Setting.h>
+#include "minecraft/launch/CreateGameFolders.h"
+#include "minecraft/launch/ExtractNatives.h"
+#include "minecraft/launch/PrintInstanceInfo.h"
+#include "settings/Setting.h"
#include "settings/SettingsObject.h"
-#include "Env.h"
-#include <MMCStrings.h>
-#include <pathmatcher/RegexpMatcher.h>
-#include <pathmatcher/MultiMatcher.h>
-#include <FileSystem.h>
-#include <java/JavaVersion.h>
+#include "Application.h"
+
+#include "MMCStrings.h"
+#include "pathmatcher/RegexpMatcher.h"
+#include "pathmatcher/MultiMatcher.h"
+#include "FileSystem.h"
+#include "java/JavaVersion.h"
#include "MMCTime.h"
#include "launch/LaunchTask.h"
@@ -18,6 +19,8 @@
#include "launch/steps/Update.h"
#include "launch/steps/PreLaunchCommand.h"
#include "launch/steps/TextPrint.h"
+#include "launch/steps/CheckJava.h"
+
#include "minecraft/launch/LauncherPartLaunch.h"
#include "minecraft/launch/DirectJavaLaunch.h"
#include "minecraft/launch/ModMinecraftJar.h"
@@ -25,25 +28,26 @@
#include "minecraft/launch/ReconstructAssets.h"
#include "minecraft/launch/ScanModFolders.h"
#include "minecraft/launch/VerifyJavaInstall.h"
-#include "java/launch/CheckJava.h"
+
#include "java/JavaUtils.h"
+
#include "meta/Index.h"
#include "meta/VersionList.h"
+#include "icons/IconList.h"
+
#include "mod/ModFolderModel.h"
#include "mod/ResourcePackFolderModel.h"
#include "mod/TexturePackFolderModel.h"
-#include "WorldList.h"
-#include "icons/IIconList.h"
+#include "WorldList.h"
-#include <QCoreApplication>
#include "PackProfile.h"
#include "AssetsUtils.h"
#include "MinecraftUpdate.h"
#include "MinecraftLoadAndCheck.h"
-#include <minecraft/gameoptions/GameOptions.h>
-#include <minecraft/update/FoldersTask.h>
+#include "minecraft/gameoptions/GameOptions.h"
+#include "minecraft/update/FoldersTask.h"
#define IBUS "@im=ibus"
@@ -198,7 +202,7 @@ QString MinecraftInstance::jarModsDir() const
return jarmods_dir.absolutePath();
}
-QString MinecraftInstance::loaderModsDir() const
+QString MinecraftInstance::modsRoot() const
{
return FS::PathCombine(gameRoot(), "mods");
}
@@ -794,17 +798,17 @@ QString MinecraftInstance::getStatusbarDescription()
return description;
}
-shared_qobject_ptr<Task> MinecraftInstance::createUpdateTask(Net::Mode mode)
+Task::Ptr MinecraftInstance::createUpdateTask(Net::Mode mode)
{
switch (mode)
{
case Net::Mode::Offline:
{
- return shared_qobject_ptr<Task>(new MinecraftLoadAndCheck(this));
+ return Task::Ptr(new MinecraftLoadAndCheck(this));
}
case Net::Mode::Online:
{
- return shared_qobject_ptr<Task>(new MinecraftUpdate(this));
+ return Task::Ptr(new MinecraftUpdate(this));
}
}
return nullptr;
@@ -816,7 +820,7 @@ shared_qobject_ptr<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPt
auto process = LaunchTask::create(std::dynamic_pointer_cast<MinecraftInstance>(shared_from_this()));
auto pptr = process.get();
- ENV.icons()->saveIcon(iconKey(), FS::PathCombine(gameRoot(), "icon.png"), "PNG");
+ APPLICATION->icons()->saveIcon(iconKey(), FS::PathCombine(gameRoot(), "icon.png"), "PNG");
// print a header
{
@@ -957,7 +961,7 @@ std::shared_ptr<ModFolderModel> MinecraftInstance::loaderModList() const
{
if (!m_loader_mod_list)
{
- m_loader_mod_list.reset(new ModFolderModel(loaderModsDir()));
+ m_loader_mod_list.reset(new ModFolderModel(modsRoot()));
m_loader_mod_list->disableInteraction(isRunning());
connect(this, &BaseInstance::runningStatusChanged, m_loader_mod_list.get(), &ModFolderModel::disableInteraction);
}
diff --git a/launcher/minecraft/MinecraftInstance.h b/launcher/minecraft/MinecraftInstance.h
index b11270e6..fda58aa7 100644
--- a/launcher/minecraft/MinecraftInstance.h
+++ b/launcher/minecraft/MinecraftInstance.h
@@ -40,7 +40,7 @@ public:
QString resourcePacksDir() const;
QString texturePacksDir() const;
QString shaderPacksDir() const;
- QString loaderModsDir() const;
+ QString modsRoot() const override;
QString coreModsDir() const;
QString modsCacheLocation() const;
QString libDir() const;
@@ -77,7 +77,7 @@ public:
std::shared_ptr<GameOptions> gameOptionsModel() const;
////// Launch stuff //////
- shared_qobject_ptr<Task> createUpdateTask(Net::Mode mode) override;
+ Task::Ptr createUpdateTask(Net::Mode mode) override;
shared_qobject_ptr<LaunchTask> createLaunchTask(AuthSessionPtr account, MinecraftServerTargetPtr serverToJoin) override;
QStringList extraArguments() const override;
QStringList verboseDescription(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) override;
diff --git a/launcher/minecraft/MinecraftLoadAndCheck.h b/launcher/minecraft/MinecraftLoadAndCheck.h
index 3435b52b..bfeae46b 100644
--- a/launcher/minecraft/MinecraftLoadAndCheck.h
+++ b/launcher/minecraft/MinecraftLoadAndCheck.h
@@ -41,7 +41,7 @@ private slots:
private:
MinecraftInstance *m_inst = nullptr;
- shared_qobject_ptr<Task> m_task;
+ Task::Ptr m_task;
QString m_preFailure;
QString m_fail_reason;
};
diff --git a/launcher/minecraft/MinecraftUpdate.cpp b/launcher/minecraft/MinecraftUpdate.cpp
index 8f1565b0..32e9cbb6 100644
--- a/launcher/minecraft/MinecraftUpdate.cpp
+++ b/launcher/minecraft/MinecraftUpdate.cpp
@@ -13,7 +13,6 @@
* limitations under the License.
*/
-#include "Env.h"
#include "MinecraftUpdate.h"
#include "MinecraftInstance.h"
diff --git a/launcher/minecraft/PackProfile.cpp b/launcher/minecraft/PackProfile.cpp
index f6918116..59a8f133 100644
--- a/launcher/minecraft/PackProfile.cpp
+++ b/launcher/minecraft/PackProfile.cpp
@@ -20,22 +20,23 @@
#include <QJsonDocument>
#include <QJsonArray>
#include <QDebug>
-
-#include "Exception.h"
-#include <minecraft/OneSixVersionFormat.h>
-#include <FileSystem.h>
#include <QSaveFile>
-#include <Env.h>
-#include <meta/Index.h>
-#include <minecraft/MinecraftInstance.h>
#include <QUuid>
#include <QTimer>
-#include <Json.h>
+
+#include "Exception.h"
+#include "minecraft/OneSixVersionFormat.h"
+#include "FileSystem.h"
+#include "meta/Index.h"
+#include "minecraft/MinecraftInstance.h"
+#include "Json.h"
#include "PackProfile.h"
#include "PackProfile_p.h"
#include "ComponentUpdateTask.h"
+#include "Application.h"
+
PackProfile::PackProfile(MinecraftInstance * instance)
: QAbstractListModel()
{
@@ -339,7 +340,7 @@ void PackProfile::reload(Net::Mode netmode)
}
}
-shared_qobject_ptr<Task> PackProfile::getCurrentTask()
+Task::Ptr PackProfile::getCurrentTask()
{
return d->m_updateTask;
}
@@ -481,7 +482,7 @@ bool PackProfile::migratePreComponentConfig()
}
else if(!intendedVersion.isEmpty())
{
- auto metaVersion = ENV.metadataIndex()->get(uid, intendedVersion);
+ auto metaVersion = APPLICATION->metadataIndex()->get(uid, intendedVersion);
component = new Component(this, metaVersion);
}
else
@@ -546,7 +547,7 @@ bool PackProfile::migratePreComponentConfig()
auto patchVersion = d->getOldConfigVersion(uid);
if(!patchVersion.isEmpty() && !loadedComponents.contains(uid))
{
- auto patch = new Component(this, ENV.metadataIndex()->get(uid, patchVersion));
+ auto patch = new Component(this, APPLICATION->metadataIndex()->get(uid, patchVersion));
patch->setOrder(order);
loadedComponents[uid] = patch;
}
diff --git a/launcher/minecraft/PackProfile.h b/launcher/minecraft/PackProfile.h
index 3d6cc6c3..f30deb5a 100644
--- a/launcher/minecraft/PackProfile.h
+++ b/launcher/minecraft/PackProfile.h
@@ -85,7 +85,7 @@ public:
void resolve(Net::Mode netmode);
/// get current running task...
- shared_qobject_ptr<Task> getCurrentTask();
+ Task::Ptr getCurrentTask();
std::shared_ptr<LaunchProfile> getProfile() const;
diff --git a/launcher/minecraft/PackProfile_p.h b/launcher/minecraft/PackProfile_p.h
index 6cd2a4e5..fce921bb 100644
--- a/launcher/minecraft/PackProfile_p.h
+++ b/launcher/minecraft/PackProfile_p.h
@@ -35,7 +35,7 @@ struct PackProfileData
ComponentIndex componentIndex;
bool dirty = false;
QTimer m_saveTimer;
- shared_qobject_ptr<Task> m_updateTask;
+ Task::Ptr m_updateTask;
bool loaded = false;
bool interactionDisabled = true;
};
diff --git a/launcher/minecraft/VersionFilterData.cpp b/launcher/minecraft/VersionFilterData.cpp
index 38e7b60c..c286d266 100644
--- a/launcher/minecraft/VersionFilterData.cpp
+++ b/launcher/minecraft/VersionFilterData.cpp
@@ -68,4 +68,5 @@ VersionFilterData::VersionFilterData()
java8BeginsDate = timeFromS3Time("2017-03-30T09:32:19+00:00");
java16BeginsDate = timeFromS3Time("2021-05-12T11:19:15+00:00");
+ java17BeginsDate = timeFromS3Time("2021-11-16T17:04:48+00:00");
}
diff --git a/launcher/minecraft/VersionFilterData.h b/launcher/minecraft/VersionFilterData.h
index 79756c3f..13445a51 100644
--- a/launcher/minecraft/VersionFilterData.h
+++ b/launcher/minecraft/VersionFilterData.h
@@ -25,5 +25,7 @@ struct VersionFilterData
QDateTime java8BeginsDate;
// release data of first version to require Java 16 (21w19a)
QDateTime java16BeginsDate;
+ // release data of first version to require Java 17 (1.18 Pre Release 2)
+ QDateTime java17BeginsDate;
};
extern VersionFilterData g_VersionFilterData;
diff --git a/launcher/minecraft/auth/AccountData.cpp b/launcher/minecraft/auth/AccountData.cpp
index 5c6de9df..7526c951 100644
--- a/launcher/minecraft/auth/AccountData.cpp
+++ b/launcher/minecraft/auth/AccountData.cpp
@@ -207,6 +207,35 @@ MinecraftProfile profileFromJSONV3(const QJsonObject &parent, const char * token
return out;
}
+void entitlementToJSONV3(QJsonObject &parent, MinecraftEntitlement p) {
+ if(p.validity == Katabasis::Validity::None) {
+ return;
+ }
+ QJsonObject out;
+ out["ownsMinecraft"] = QJsonValue(p.ownsMinecraft);
+ out["canPlayMinecraft"] = QJsonValue(p.canPlayMinecraft);
+ parent["entitlement"] = out;
+}
+
+bool entitlementFromJSONV3(const QJsonObject &parent, MinecraftEntitlement & out) {
+ auto entitlementObject = parent.value("entitlement").toObject();
+ if(entitlementObject.isEmpty()) {
+ return false;
+ }
+ {
+ auto ownsMinecraftV = entitlementObject.value("ownsMinecraft");
+ auto canPlayMinecraftV = entitlementObject.value("canPlayMinecraft");
+ if(!ownsMinecraftV.isBool() || !canPlayMinecraftV.isBool()) {
+ qWarning() << "mandatory attributes are missing or of unexpected type";
+ return false;
+ }
+ out.canPlayMinecraft = canPlayMinecraftV.toBool(false);
+ out.ownsMinecraft = ownsMinecraftV.toBool(false);
+ out.validity = Katabasis::Validity::Assumed;
+ }
+ return true;
+}
+
}
bool AccountData::resumeStateFromV2(QJsonObject data) {
@@ -304,9 +333,15 @@ bool AccountData::resumeStateFromV3(QJsonObject data) {
yggdrasilToken = tokenFromJSONV3(data, "ygg");
minecraftProfile = profileFromJSONV3(data, "profile");
+ if(!entitlementFromJSONV3(data, minecraftEntitlement)) {
+ if(minecraftProfile.validity != Katabasis::Validity::None) {
+ minecraftEntitlement.canPlayMinecraft = true;
+ minecraftEntitlement.ownsMinecraft = true;
+ minecraftEntitlement.validity = Katabasis::Validity::Assumed;
+ }
+ }
validity_ = minecraftProfile.validity;
-
return true;
}
@@ -331,6 +366,7 @@ QJsonObject AccountData::saveState() const {
tokenToJSONV3(output, yggdrasilToken, "ygg");
profileToJSONV3(output, minecraftProfile, "profile");
+ entitlementToJSONV3(output, minecraftEntitlement);
return output;
}
@@ -378,7 +414,12 @@ QString AccountData::profileId() const {
}
QString AccountData::profileName() const {
- return minecraftProfile.name;
+ if(minecraftProfile.name.size() == 0) {
+ return QObject::tr("No profile (%1)").arg(accountDisplayString());
+ }
+ else {
+ return minecraftProfile.name;
+ }
}
QString AccountData::accountDisplayString() const {
@@ -397,3 +438,7 @@ QString AccountData::accountDisplayString() const {
}
}
}
+
+QString AccountData::lastError() const {
+ return errorString;
+}
diff --git a/launcher/minecraft/auth/AccountData.h b/launcher/minecraft/auth/AccountData.h
index cf58fb76..abf84e43 100644
--- a/launcher/minecraft/auth/AccountData.h
+++ b/launcher/minecraft/auth/AccountData.h
@@ -21,6 +21,12 @@ struct Cape {
QByteArray data;
};
+struct MinecraftEntitlement {
+ bool ownsMinecraft = false;
+ bool canPlayMinecraft = false;
+ Katabasis::Validity validity = Katabasis::Validity::None;
+};
+
struct MinecraftProfile {
QString id;
QString name;
@@ -35,6 +41,16 @@ enum class AccountType {
Mojang
};
+enum class AccountState {
+ Unchecked,
+ Offline,
+ Working,
+ Online,
+ Errored,
+ Expired,
+ Gone
+};
+
struct AccountData {
QJsonObject saveState() const;
bool resumeStateFromV2(QJsonObject data);
@@ -58,6 +74,8 @@ struct AccountData {
QString profileId() const;
QString profileName() const;
+ QString lastError() const;
+
AccountType type = AccountType::MSA;
bool legacy = false;
bool canMigrateToMSA = false;
@@ -69,5 +87,11 @@ struct AccountData {
Katabasis::Token yggdrasilToken;
MinecraftProfile minecraftProfile;
+ MinecraftEntitlement minecraftEntitlement;
Katabasis::Validity validity_ = Katabasis::Validity::None;
+
+ // runtime only information (not saved with the account)
+ QString internalId;
+ QString errorString;
+ AccountState accountState = AccountState::Unchecked;
};
diff --git a/launcher/minecraft/auth/AccountList.cpp b/launcher/minecraft/auth/AccountList.cpp
index a76cac55..ef8b435d 100644
--- a/launcher/minecraft/auth/AccountList.cpp
+++ b/launcher/minecraft/auth/AccountList.cpp
@@ -15,6 +15,7 @@
#include "AccountList.h"
#include "AccountData.h"
+#include "AccountTask.h"
#include <QIODevice>
#include <QFile>
@@ -24,18 +25,30 @@
#include <QJsonObject>
#include <QJsonParseError>
#include <QDir>
+#include <QTimer>
#include <QDebug>
#include <FileSystem.h>
#include <QSaveFile>
+#include <chrono>
+
enum AccountListVersion {
MojangOnly = 2,
MojangMSA = 3
};
-AccountList::AccountList(QObject *parent) : QAbstractListModel(parent) { }
+AccountList::AccountList(QObject *parent) : QAbstractListModel(parent) {
+ m_refreshTimer = new QTimer(this);
+ m_refreshTimer->setSingleShot(true);
+ connect(m_refreshTimer, &QTimer::timeout, this, &AccountList::fillQueue);
+ m_nextTimer = new QTimer(this);
+ m_nextTimer->setSingleShot(true);
+ connect(m_nextTimer, &QTimer::timeout, this, &AccountList::tryNext);
+}
+
+AccountList::~AccountList() noexcept {}
int AccountList::findAccountByProfileId(const QString& profileId) const {
for (int i = 0; i < count(); i++) {
@@ -62,28 +75,50 @@ const MinecraftAccountPtr AccountList::at(int i) const
return MinecraftAccountPtr(m_accounts.at(i));
}
+QStringList AccountList::profileNames() const {
+ QStringList out;
+ for(auto & account: m_accounts) {
+ auto profileName = account->profileName();
+ if(profileName.isEmpty()) {
+ continue;
+ }
+ out.append(profileName);
+ }
+ return out;
+}
+
void AccountList::addAccount(const MinecraftAccountPtr account)
{
- // We only ever want accounts with valid profiles.
- // Keeping profile-less accounts is pointless and serves no purpose.
- auto profileId = account->profileId();
- if(!profileId.size()) {
+ // NOTE: Do not allow adding something that's already there
+ if(m_accounts.contains(account)) {
return;
}
+ // hook up notifications for changes in the account
+ connect(account.get(), &MinecraftAccount::changed, this, &AccountList::accountChanged);
+ connect(account.get(), &MinecraftAccount::activityChanged, this, &AccountList::accountActivityChanged);
+
// override/replace existing account with the same profileId
- auto existingAccount = findAccountByProfileId(profileId);
- if(existingAccount != -1) {
- m_accounts[existingAccount] = account;
- emit dataChanged(index(existingAccount), index(existingAccount, columnCount(QModelIndex()) - 1));
- onListChanged();
- return;
+ auto profileId = account->profileId();
+ if(profileId.size()) {
+ auto existingAccount = findAccountByProfileId(profileId);
+ if(existingAccount != -1) {
+ MinecraftAccountPtr existingAccountPtr = m_accounts[existingAccount];
+ m_accounts[existingAccount] = account;
+ if(m_defaultAccount == existingAccountPtr) {
+ m_defaultAccount = account;
+ }
+ // disconnect notifications for changes in the account being replaced
+ existingAccountPtr->disconnect(this);
+ emit dataChanged(index(existingAccount), index(existingAccount, columnCount(QModelIndex()) - 1));
+ onListChanged();
+ return;
+ }
}
- // if we don't have this porfileId yet, add the account to the end
+ // if we don't have this profileId yet, add the account to the end
int row = m_accounts.count();
beginInsertRows(QModelIndex(), row, row);
- connect(account.get(), SIGNAL(changed()), SLOT(accountChanged()));
m_accounts.append(account);
endInsertRows();
onListChanged();
@@ -95,11 +130,13 @@ void AccountList::removeAccount(QModelIndex index)
if(index.isValid() && row >= 0 && row < m_accounts.size())
{
auto & account = m_accounts[row];
- if(account == m_activeAccount)
+ if(account == m_defaultAccount)
{
- m_activeAccount = nullptr;
- onActiveChanged();
+ m_defaultAccount = nullptr;
+ onDefaultAccountChanged();
}
+ account->disconnect(this);
+
beginRemoveRows(QModelIndex(), row, row);
m_accounts.removeAt(index.row());
endRemoveRows();
@@ -107,54 +144,54 @@ void AccountList::removeAccount(QModelIndex index)
}
}
-MinecraftAccountPtr AccountList::activeAccount() const
+MinecraftAccountPtr AccountList::defaultAccount() const
{
- return m_activeAccount;
+ return m_defaultAccount;
}
-void AccountList::setActiveAccount(const QString &profileId)
+void AccountList::setDefaultAccount(MinecraftAccountPtr newAccount)
{
- if (profileId.isEmpty() && m_activeAccount)
+ if (!newAccount && m_defaultAccount)
{
int idx = 0;
- auto prevActiveAcc = m_activeAccount;
- m_activeAccount = nullptr;
+ auto previousDefaultAccount = m_defaultAccount;
+ m_defaultAccount = nullptr;
for (MinecraftAccountPtr account : m_accounts)
{
- if (account == prevActiveAcc)
+ if (account == previousDefaultAccount)
{
- emit dataChanged(index(idx), index(idx));
+ emit dataChanged(index(idx), index(idx, columnCount(QModelIndex()) - 1));
}
idx ++;
}
- onActiveChanged();
+ onDefaultAccountChanged();
}
else
{
- auto currentActiveAccount = m_activeAccount;
- int currentActiveAccountIdx = -1;
- auto newActiveAccount = m_activeAccount;
- int newActiveAccountIdx = -1;
+ auto currentDefaultAccount = m_defaultAccount;
+ int currentDefaultAccountIdx = -1;
+ auto newDefaultAccount = m_defaultAccount;
+ int newDefaultAccountIdx = -1;
int idx = 0;
for (MinecraftAccountPtr account : m_accounts)
{
- if (account->profileId() == profileId)
+ if (account == newAccount)
{
- newActiveAccount = account;
- newActiveAccountIdx = idx;
+ newDefaultAccount = account;
+ newDefaultAccountIdx = idx;
}
- if(currentActiveAccount == account)
+ if(currentDefaultAccount == account)
{
- currentActiveAccountIdx = idx;
+ currentDefaultAccountIdx = idx;
}
idx++;
}
- if(currentActiveAccount != newActiveAccount)
+ if(currentDefaultAccount != newDefaultAccount)
{
- emit dataChanged(index(currentActiveAccountIdx), index(currentActiveAccountIdx));
- emit dataChanged(index(newActiveAccountIdx), index(newActiveAccountIdx));
- m_activeAccount = newActiveAccount;
- onActiveChanged();
+ emit dataChanged(index(currentDefaultAccountIdx), index(currentDefaultAccountIdx, columnCount(QModelIndex()) - 1));
+ emit dataChanged(index(newDefaultAccountIdx), index(newDefaultAccountIdx, columnCount(QModelIndex()) - 1));
+ m_defaultAccount = newDefaultAccount;
+ onDefaultAccountChanged();
}
}
}
@@ -165,6 +202,29 @@ void AccountList::accountChanged()
onListChanged();
}
+void AccountList::accountActivityChanged(bool active)
+{
+ MinecraftAccount *account = qobject_cast<MinecraftAccount *>(sender());
+ bool found = false;
+ for (int i = 0; i < count(); i++) {
+ if (at(i).get() == account) {
+ emit dataChanged(index(i), index(i, columnCount(QModelIndex()) - 1));
+ found = true;
+ break;
+ }
+ }
+ if(found) {
+ emit listActivityChanged();
+ if(active) {
+ beginActivity();
+ }
+ else {
+ endActivity();
+ }
+ }
+}
+
+
void AccountList::onListChanged()
{
if (m_autosave)
@@ -174,12 +234,12 @@ void AccountList::onListChanged()
emit listChanged();
}
-void AccountList::onActiveChanged()
+void AccountList::onDefaultAccountChanged()
{
if (m_autosave)
saveList();
- emit activeAccountChanged();
+ emit defaultAccountChanged();
}
int AccountList::count() const
@@ -211,6 +271,32 @@ QVariant AccountList::data(const QModelIndex &index, int role) const
return typeStr;
}
+ case StatusColumn: {
+ switch(account->accountState()) {
+ case AccountState::Unchecked: {
+ return tr("Unchecked", "Account status");
+ }
+ case AccountState::Offline: {
+ return tr("Offline", "Account status");
+ }
+ case AccountState::Online: {
+ return tr("Online", "Account status");
+ }
+ case AccountState::Working: {
+ return tr("Working", "Account status");
+ }
+ case AccountState::Errored: {
+ return tr("Errored", "Account status");
+ }
+ case AccountState::Expired: {
+ return tr("Expired", "Account status");
+ }
+ case AccountState::Gone: {
+ return tr("Gone", "Account status");
+ }
+ }
+ }
+
case ProfileNameColumn: {
return account->profileName();
}
@@ -235,13 +321,13 @@ QVariant AccountList::data(const QModelIndex &index, int role) const
return account->accountDisplayString();
case PointerRole:
- return qVariantFromValue(account);
+ return QVariant::fromValue(account);
case Qt::CheckStateRole:
switch (index.column())
{
case NameColumn:
- return account == m_activeAccount ? Qt::Checked : Qt::Unchecked;
+ return account == m_defaultAccount ? Qt::Checked : Qt::Unchecked;
}
default:
@@ -260,6 +346,8 @@ QVariant AccountList::headerData(int section, Qt::Orientation orientation, int r
return tr("Account");
case TypeColumn:
return tr("Type");
+ case StatusColumn:
+ return tr("Status");
case MigrationColumn:
return tr("Can Migrate?");
case ProfileNameColumn:
@@ -275,6 +363,8 @@ QVariant AccountList::headerData(int section, Qt::Orientation orientation, int r
return tr("User name of the account.");
case TypeColumn:
return tr("Type of the account - Mojang or MSA.");
+ case StatusColumn:
+ return tr("Current status of the account.");
case MigrationColumn:
return tr("Can this account migrate to Microsoft account?");
case ProfileNameColumn:
@@ -309,9 +399,9 @@ Qt::ItemFlags AccountList::flags(const QModelIndex &index) const
return Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}
-bool AccountList::setData(const QModelIndex &index, const QVariant &value, int role)
+bool AccountList::setData(const QModelIndex &idx, const QVariant &value, int role)
{
- if (index.row() < 0 || index.row() >= rowCount(index) || !index.isValid())
+ if (idx.row() < 0 || idx.row() >= rowCount(idx) || !idx.isValid())
{
return false;
}
@@ -320,12 +410,12 @@ bool AccountList::setData(const QModelIndex &index, const QVariant &value, int r
{
if(value == Qt::Checked)
{
- MinecraftAccountPtr account = at(index.row());
- setActiveAccount(account->profileId());
+ MinecraftAccountPtr account = at(idx.row());
+ setDefaultAccount(account);
}
}
- emit dataChanged(index, index);
+ emit dataChanged(idx, index(idx.row(), columnCount(QModelIndex()) - 1));
return true;
}
@@ -395,7 +485,7 @@ bool AccountList::loadList()
bool AccountList::loadV2(QJsonObject& root) {
beginResetModel();
- auto activeUserName = root.value("activeAccount").toString("");
+ auto defaultUserName = root.value("activeAccount").toString("");
QJsonArray accounts = root.value("accounts").toArray();
for (QJsonValue accountVal : accounts)
{
@@ -411,9 +501,10 @@ bool AccountList::loadV2(QJsonObject& root) {
continue;
}
connect(account.get(), &MinecraftAccount::changed, this, &AccountList::accountChanged);
+ connect(account.get(), &MinecraftAccount::activityChanged, this, &AccountList::accountActivityChanged);
m_accounts.append(account);
- if (activeUserName.size() && account->mojangUserName() == activeUserName) {
- m_activeAccount = account;
+ if (defaultUserName.size() && account->mojangUserName() == defaultUserName) {
+ m_defaultAccount = account;
}
}
else
@@ -435,16 +526,16 @@ bool AccountList::loadV3(QJsonObject& root) {
if (account.get() != nullptr)
{
auto profileId = account->profileId();
- if(!profileId.size()) {
- continue;
- }
- if(findAccountByProfileId(profileId) != -1) {
- continue;
+ if(profileId.size()) {
+ if(findAccountByProfileId(profileId) != -1) {
+ continue;
+ }
}
connect(account.get(), &MinecraftAccount::changed, this, &AccountList::accountChanged);
+ connect(account.get(), &MinecraftAccount::activityChanged, this, &AccountList::accountActivityChanged);
m_accounts.append(account);
if(accountObj.value("active").toBool(false)) {
- m_activeAccount = account;
+ m_defaultAccount = account;
}
}
else
@@ -491,7 +582,7 @@ bool AccountList::saveList()
for (MinecraftAccountPtr account : m_accounts)
{
QJsonObject accountObj = account->saveToJson();
- if(m_activeAccount == account) {
+ if(m_defaultAccount == account) {
accountObj["active"] = true;
}
accounts.append(accountObj);
@@ -536,10 +627,113 @@ void AccountList::setListFilePath(QString path, bool autosave)
bool AccountList::anyAccountIsValid()
{
- for(auto account:m_accounts)
+ for(auto account: m_accounts)
{
- if(account->accountStatus() != NotVerified)
+ if(account->ownsMinecraft()) {
return true;
+ }
}
return false;
}
+
+void AccountList::fillQueue() {
+
+ if(m_defaultAccount && m_defaultAccount->shouldRefresh()) {
+ auto idToRefresh = m_defaultAccount->internalId();
+ m_refreshQueue.push_back(idToRefresh);
+ qDebug() << "AccountList: Queued default account with internal ID " << idToRefresh << " to refresh first";
+ }
+
+ for(int i = 0; i < count(); i++) {
+ auto account = at(i);
+ if(account == m_defaultAccount) {
+ continue;
+ }
+
+ if(account->shouldRefresh()) {
+ auto idToRefresh = account->internalId();
+ queueRefresh(idToRefresh);
+ }
+ }
+ tryNext();
+}
+
+void AccountList::requestRefresh(QString accountId) {
+ auto index = m_refreshQueue.indexOf(accountId);
+ if(index != -1) {
+ m_refreshQueue.removeAt(index);
+ }
+ m_refreshQueue.push_front(accountId);
+ qDebug() << "AccountList: Pushed account with internal ID " << accountId << " to the front of the queue";
+ if(!isActive()) {
+ tryNext();
+ }
+}
+
+void AccountList::queueRefresh(QString accountId) {
+ if(m_refreshQueue.indexOf(accountId) != -1) {
+ return;
+ }
+ m_refreshQueue.push_back(accountId);
+ qDebug() << "AccountList: Queued account with internal ID " << accountId << " to refresh";
+}
+
+
+void AccountList::tryNext() {
+ while (m_refreshQueue.length()) {
+ auto accountId = m_refreshQueue.front();
+ m_refreshQueue.pop_front();
+ for(int i = 0; i < count(); i++) {
+ auto account = at(i);
+ if(account->internalId() == accountId) {
+ m_currentTask = account->refresh();
+ if(m_currentTask) {
+ connect(m_currentTask.get(), &AccountTask::succeeded, this, &AccountList::authSucceeded);
+ connect(m_currentTask.get(), &AccountTask::failed, this, &AccountList::authFailed);
+ m_currentTask->start();
+ qDebug() << "RefreshSchedule: Processing account " << account->accountDisplayString() << " with internal ID " << accountId;
+ return;
+ }
+ }
+ }
+ qDebug() << "RefreshSchedule: Account with with internal ID " << accountId << " not found.";
+ }
+ // if we get here, no account needed refreshing. Schedule refresh in an hour.
+ m_refreshTimer->start(1000 * 3600);
+}
+
+void AccountList::authSucceeded() {
+ qDebug() << "RefreshSchedule: Background account refresh succeeded";
+ m_currentTask.reset();
+ m_nextTimer->start(1000 * 20);
+}
+
+void AccountList::authFailed(QString reason) {
+ qDebug() << "RefreshSchedule: Background account refresh failed: " << reason;
+ m_currentTask.reset();
+ m_nextTimer->start(1000 * 20);
+}
+
+bool AccountList::isActive() const {
+ return m_activityCount != 0;
+}
+
+void AccountList::beginActivity() {
+ bool activating = m_activityCount == 0;
+ m_activityCount++;
+ if(activating) {
+ emit activityChanged(true);
+ }
+}
+
+void AccountList::endActivity() {
+ if(m_activityCount == 0) {
+ qWarning() << m_name << " - Activity count would become below zero";
+ return;
+ }
+ bool deactivating = m_activityCount == 1;
+ m_activityCount--;
+ if(deactivating) {
+ emit activityChanged(false);
+ }
+}
diff --git a/launcher/minecraft/auth/AccountList.h b/launcher/minecraft/auth/AccountList.h
index e275eb17..fa1e7431 100644
--- a/launcher/minecraft/auth/AccountList.h
+++ b/launcher/minecraft/auth/AccountList.h
@@ -42,11 +42,13 @@ public:
ProfileNameColumn,
MigrationColumn,
TypeColumn,
+ StatusColumn,
NUM_COLUMNS
};
explicit AccountList(QObject *parent = 0);
+ virtual ~AccountList() noexcept;
const MinecraftAccountPtr at(int i) const;
int count() const;
@@ -63,6 +65,12 @@ public:
void removeAccount(QModelIndex index);
int findAccountByProfileId(const QString &profileId) const;
MinecraftAccountPtr getAccountByProfileName(const QString &profileName) const;
+ QStringList profileNames() const;
+
+ // requesting a refresh pushes it to the front of the queue
+ void requestRefresh(QString accountId);
+ // queuing a refresh will let it go to the back of the queue (unless it's somewhere inside the queue already)
+ void queueRefresh(QString accountId);
/*!
* Sets the path to load/save the list file from/to.
@@ -78,13 +86,24 @@ public:
bool loadV3(QJsonObject &root);
bool saveList();
- MinecraftAccountPtr activeAccount() const;
- void setActiveAccount(const QString &profileId);
+ MinecraftAccountPtr defaultAccount() const;
+ void setDefaultAccount(MinecraftAccountPtr profileId);
bool anyAccountIsValid();
+ bool isActive() const;
+
+protected:
+ void beginActivity();
+ void endActivity();
+
+private:
+ const char* m_name;
+ uint32_t m_activityCount = 0;
signals:
void listChanged();
- void activeAccountChanged();
+ void listActivityChanged();
+ void defaultAccountChanged();
+ void activityChanged(bool active);
public slots:
/**
@@ -92,7 +111,28 @@ public slots:
*/
void accountChanged();
+ /**
+ * This is called when a (refresh/login) task involving the account starts or ends
+ */
+ void accountActivityChanged(bool active);
+
+ /**
+ * This is initially to run background account refresh tasks, or on a hourly timer
+ */
+ void fillQueue();
+
+private slots:
+ void tryNext();
+
+ void authSucceeded();
+ void authFailed(QString reason);
+
protected:
+ QList<QString> m_refreshQueue;
+ QTimer *m_refreshTimer;
+ QTimer *m_nextTimer;
+ shared_qobject_ptr<AccountTask> m_currentTask;
+
/*!
* Called whenever the list changes.
* This emits the listChanged() signal and autosaves the list (if autosave is enabled).
@@ -101,13 +141,13 @@ protected:
/*!
* Called whenever the active account changes.
- * Emits the activeAccountChanged() signal and autosaves the list if enabled.
+ * Emits the defaultAccountChanged() signal and autosaves the list if enabled.
*/
- void onActiveChanged();
+ void onDefaultAccountChanged();
QList<MinecraftAccountPtr> m_accounts;
- MinecraftAccountPtr m_activeAccount;
+ MinecraftAccountPtr m_defaultAccount;
//! Path to the account list file. Empty string if there isn't one.
QString m_listFilePath;
diff --git a/launcher/minecraft/auth/AccountTask.cpp b/launcher/minecraft/auth/AccountTask.cpp
index d400ce8d..98d8d94d 100644
--- a/launcher/minecraft/auth/AccountTask.cpp
+++ b/launcher/minecraft/auth/AccountTask.cpp
@@ -23,49 +23,84 @@
#include <QNetworkReply>
#include <QByteArray>
-#include <Env.h>
-
-#include <BuildConfig.h>
-
#include <QDebug>
AccountTask::AccountTask(AccountData *data, QObject *parent)
: Task(parent), m_data(data)
{
- changeState(STATE_CREATED);
+ changeState(AccountTaskState::STATE_CREATED);
}
QString AccountTask::getStateMessage() const
{
- switch (m_accountState)
+ switch (m_taskState)
{
- case STATE_CREATED:
+ case AccountTaskState::STATE_CREATED:
return "Waiting...";
- case STATE_WORKING:
+ case AccountTaskState::STATE_WORKING:
return tr("Sending request to auth servers...");
- case STATE_SUCCEEDED:
+ case AccountTaskState::STATE_SUCCEEDED:
return tr("Authentication task succeeded.");
- case STATE_FAILED_SOFT:
+ case AccountTaskState::STATE_OFFLINE:
return tr("Failed to contact the authentication server.");
- case STATE_FAILED_HARD:
- return tr("Failed to authenticate.");
- case STATE_FAILED_GONE:
+ case AccountTaskState::STATE_FAILED_SOFT:
+ return tr("Encountered an error during authentication.");
+ case AccountTaskState::STATE_FAILED_HARD:
+ return tr("Failed to authenticate. The session has expired.");
+ case AccountTaskState::STATE_FAILED_GONE:
return tr("Failed to authenticate. The account no longer exists.");
default:
return tr("...");
}
}
-void AccountTask::changeState(AccountTask::State newState, QString reason)
+bool AccountTask::changeState(AccountTaskState newState, QString reason)
{
- m_accountState = newState;
+ m_taskState = newState;
setStatus(getStateMessage());
- if (newState == STATE_SUCCEEDED)
- {
- emitSucceeded();
- }
- else if (newState == STATE_FAILED_HARD || newState == STATE_FAILED_SOFT || newState == STATE_FAILED_GONE)
- {
- emitFailed(reason);
+ switch(newState) {
+ case AccountTaskState::STATE_CREATED: {
+ m_data->errorString.clear();
+ return true;
+ }
+ case AccountTaskState::STATE_WORKING: {
+ m_data->accountState = AccountState::Working;
+ return true;
+ }
+ case AccountTaskState::STATE_SUCCEEDED: {
+ m_data->accountState = AccountState::Online;
+ emitSucceeded();
+ return false;
+ }
+ case AccountTaskState::STATE_OFFLINE: {
+ m_data->errorString = reason;
+ m_data->accountState = AccountState::Offline;
+ emitFailed(reason);
+ return false;
+ }
+ case AccountTaskState::STATE_FAILED_SOFT: {
+ m_data->errorString = reason;
+ m_data->accountState = AccountState::Errored;
+ emitFailed(reason);
+ return false;
+ }
+ case AccountTaskState::STATE_FAILED_HARD: {
+ m_data->errorString = reason;
+ m_data->accountState = AccountState::Expired;
+ emitFailed(reason);
+ return false;
+ }
+ case AccountTaskState::STATE_FAILED_GONE: {
+ m_data->errorString = reason;
+ m_data->accountState = AccountState::Gone;
+ emitFailed(reason);
+ return false;
+ }
+ default: {
+ QString error = tr("Unknown account task state: %1").arg(int(newState));
+ m_data->accountState = AccountState::Errored;
+ emitFailed(error);
+ return false;
+ }
}
}
diff --git a/launcher/minecraft/auth/AccountTask.h b/launcher/minecraft/auth/AccountTask.h
index 4f3bd52a..dac3f1b5 100644
--- a/launcher/minecraft/auth/AccountTask.h
+++ b/launcher/minecraft/auth/AccountTask.h
@@ -26,62 +26,32 @@
class QNetworkReply;
+/**
+ * Enum for describing the state of the current task.
+ * Used by the getStateMessage function to determine what the status message should be.
+ */
+enum class AccountTaskState
+{
+ STATE_CREATED,
+ STATE_WORKING,
+ STATE_SUCCEEDED,
+ STATE_FAILED_SOFT, //!< soft failure. authentication went through partially
+ STATE_FAILED_HARD, //!< hard failure. main tokens are invalid
+ STATE_FAILED_GONE, //!< hard failure. main tokens are invalid, and the account no longer exists
+ STATE_OFFLINE //!< soft failure. authentication failed in the first step in a 'soft' way
+};
+
class AccountTask : public Task
{
- friend class AuthContext;
Q_OBJECT
public:
explicit AccountTask(AccountData * data, QObject *parent = 0);
virtual ~AccountTask() {};
- /**
- * assign a session to this task. the session will be filled with required infomration
- * upon completion
- */
- void assignSession(AuthSessionPtr session)
- {
- m_session = session;
- }
-
- /// get the assigned session for filling with information.
- AuthSessionPtr getAssignedSession()
- {
- return m_session;
- }
-
- /**
- * Class describing a Account error response.
- */
- struct Error
- {
- QString m_errorMessageShort;
- QString m_errorMessageVerbose;
- QString m_cause;
- };
-
- enum AbortedBy
- {
- BY_NOTHING,
- BY_USER,
- BY_TIMEOUT
- } m_aborted = BY_NOTHING;
-
- /**
- * Enum for describing the state of the current task.
- * Used by the getStateMessage function to determine what the status message should be.
- */
- enum State
- {
- STATE_CREATED,
- STATE_WORKING,
- STATE_FAILED_SOFT, //!< soft failure. this generally means the user auth details haven't been invalidated
- STATE_FAILED_HARD, //!< hard failure. auth is invalid
- STATE_FAILED_GONE, //!< hard failure. auth is invalid, and the account no longer exists
- STATE_SUCCEEDED
- } m_accountState = STATE_CREATED;
+ AccountTaskState m_taskState = AccountTaskState::STATE_CREATED;
- State accountState() {
- return m_accountState;
+ AccountTaskState taskState() {
+ return m_taskState;
}
signals:
@@ -98,11 +68,9 @@ protected:
virtual QString getStateMessage() const;
protected slots:
- void changeState(State newState, QString reason=QString());
+ // NOTE: true -> non-terminal state, false -> terminal state
+ bool changeState(AccountTaskState newState, QString reason = QString());
protected:
- // FIXME: segfault disaster waiting to happen
AccountData *m_data = nullptr;
- std::shared_ptr<Error> m_error;
- AuthSessionPtr m_session;
};
diff --git a/launcher/minecraft/auth/flows/AuthRequest.cpp b/launcher/minecraft/auth/AuthRequest.cpp
index 77558fd3..459d2354 100644
--- a/launcher/minecraft/auth/flows/AuthRequest.cpp
+++ b/launcher/minecraft/auth/AuthRequest.cpp
@@ -5,9 +5,9 @@
#include <QBuffer>
#include <QUrlQuery>
+#include "Application.h"
#include "AuthRequest.h"
#include "katabasis/Globals.h"
-#include "Env.h"
AuthRequest::AuthRequest(QObject *parent): QObject(parent) {
}
@@ -17,7 +17,7 @@ AuthRequest::~AuthRequest() {
void AuthRequest::get(const QNetworkRequest &req, int timeout/* = 60*1000*/) {
setup(req, QNetworkAccessManager::GetOperation);
- reply_ = ENV.qnam().get(request_);
+ reply_ = APPLICATION->network()->get(request_);
status_ = Requesting;
timedReplies_.add(new Katabasis::Reply(reply_, timeout));
connect(reply_, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)));
@@ -29,7 +29,7 @@ void AuthRequest::post(const QNetworkRequest &req, const QByteArray &data, int t
setup(req, QNetworkAccessManager::PostOperation);
data_ = data;
status_ = Requesting;
- reply_ = ENV.qnam().post(request_, data_);
+ reply_ = APPLICATION->network()->post(request_, data_);
timedReplies_.add(new Katabasis::Reply(reply_, timeout));
connect(reply_, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)));
connect(reply_, SIGNAL(finished()), this, SLOT(onRequestFinished()));
@@ -44,6 +44,7 @@ void AuthRequest::onRequestFinished() {
if (reply_ != qobject_cast<QNetworkReply *>(sender())) {
return;
}
+ httpStatus_ = 200;
finish();
}
@@ -55,10 +56,11 @@ void AuthRequest::onRequestError(QNetworkReply::NetworkError error) {
if (reply_ != qobject_cast<QNetworkReply *>(sender())) {
return;
}
- qWarning() << "AuthRequest::onRequestError: Error string: " << reply_->errorString();
- int httpStatus = reply_->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
- qWarning() << "AuthRequest::onRequestError: HTTP status" << httpStatus << reply_->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString();
+ errorString_ = reply_->errorString();
+ httpStatus_ = reply_->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
error_ = error;
+ qWarning() << "AuthRequest::onRequestError: Error string: " << errorString_;
+ qWarning() << "AuthRequest::onRequestError: HTTP status" << httpStatus_ << reply_->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString();
// QTimer::singleShot(10, this, SLOT(finish()));
}
@@ -103,6 +105,8 @@ void AuthRequest::setup(const QNetworkRequest &req, QNetworkAccessManager::Opera
status_ = Requesting;
error_ = QNetworkReply::NoError;
+ errorString_.clear();
+ httpStatus_ = 0;
}
void AuthRequest::finish() {
diff --git a/launcher/minecraft/auth/flows/AuthRequest.h b/launcher/minecraft/auth/AuthRequest.h
index 6a45a0bd..89f7a123 100644
--- a/launcher/minecraft/auth/flows/AuthRequest.h
+++ b/launcher/minecraft/auth/AuthRequest.h
@@ -5,7 +5,6 @@
#include <QNetworkAccessManager>
#include <QUrl>
#include <QByteArray>
-#include <QHttpMultiPart>
#include "katabasis/Reply.h"
@@ -47,6 +46,11 @@ protected slots:
/// Handle upload progress.
void onUploadProgress(qint64 uploaded, qint64 total);
+public:
+ QNetworkReply::NetworkError error_;
+ int httpStatus_ = 0;
+ QString errorString_;
+
protected:
void setup(const QNetworkRequest &request, QNetworkAccessManager::Operation operation, const QByteArray &verb = QByteArray());
@@ -61,5 +65,6 @@ protected:
QNetworkAccessManager::Operation operation_;
QUrl url_;
Katabasis::ReplyList timedReplies_;
- QNetworkReply::NetworkError error_;
+
+ QTimer *timer_;
};
diff --git a/launcher/minecraft/auth/AuthSession.h b/launcher/minecraft/auth/AuthSession.h
index f609d5d3..55fbdf39 100644
--- a/launcher/minecraft/auth/AuthSession.h
+++ b/launcher/minecraft/auth/AuthSession.h
@@ -3,8 +3,10 @@
#include <QString>
#include <QMultiMap>
#include <memory>
+#include "QObjectPtr.h"
class MinecraftAccount;
+class QNetworkAccessManager;
struct AuthSession
{
@@ -17,6 +19,7 @@ struct AuthSession
Undetermined,
RequiresOAuth,
RequiresPassword,
+ RequiresProfileSetup,
PlayableOffline,
PlayableOnline,
GoneOrMigrated
@@ -40,7 +43,6 @@ struct AuthSession
bool auth_server_online = false;
// Did the user request online mode?
bool wants_online = true;
- std::shared_ptr<MinecraftAccount> m_accountPtr;
};
typedef std::shared_ptr<AuthSession> AuthSessionPtr;
diff --git a/launcher/minecraft/auth/AuthStep.cpp b/launcher/minecraft/auth/AuthStep.cpp
new file mode 100644
index 00000000..ffa2581b
--- /dev/null
+++ b/launcher/minecraft/auth/AuthStep.cpp
@@ -0,0 +1,7 @@
+#include "AuthStep.h"
+
+AuthStep::AuthStep(AccountData *data) : QObject(nullptr), m_data(data) {
+}
+
+AuthStep::~AuthStep() noexcept = default;
+
diff --git a/launcher/minecraft/auth/AuthStep.h b/launcher/minecraft/auth/AuthStep.h
new file mode 100644
index 00000000..2a8dc2ca
--- /dev/null
+++ b/launcher/minecraft/auth/AuthStep.h
@@ -0,0 +1,33 @@
+#pragma once
+#include <QObject>
+#include <QList>
+#include <QNetworkReply>
+
+#include "QObjectPtr.h"
+#include "minecraft/auth/AccountData.h"
+#include "AccountTask.h"
+
+class AuthStep : public QObject {
+ Q_OBJECT
+
+public:
+ using Ptr = shared_qobject_ptr<AuthStep>;
+
+public:
+ explicit AuthStep(AccountData *data);
+ virtual ~AuthStep() noexcept;
+
+ virtual QString describe() = 0;
+
+public slots:
+ virtual void perform() = 0;
+ virtual void rehydrate() = 0;
+
+signals:
+ void finished(AccountTaskState resultingState, QString message);
+ void showVerificationUriAndCode(const QUrl &uri, const QString &code, int expiresIn);
+ void hideVerificationUriAndCode();
+
+protected:
+ AccountData *m_data;
+};
diff --git a/launcher/minecraft/auth/MinecraftAccount.cpp b/launcher/minecraft/auth/MinecraftAccount.cpp
index 2d76f9ac..ed9e945e 100644
--- a/launcher/minecraft/auth/MinecraftAccount.cpp
+++ b/launcher/minecraft/auth/MinecraftAccount.cpp
@@ -16,7 +16,6 @@
*/
#include "MinecraftAccount.h"
-#include "flows/AuthContext.h"
#include <QUuid>
#include <QJsonObject>
@@ -28,11 +27,14 @@
#include <QDebug>
#include <QPainter>
-#include <minecraft/auth/flows/MSASilent.h>
-#include <minecraft/auth/flows/MSAInteractive.h>
-#include <minecraft/auth/flows/MojangRefresh.h>
-#include <minecraft/auth/flows/MojangLogin.h>
+#include "flows/MSA.h"
+#include "flows/Mojang.h"
+
+MinecraftAccount::MinecraftAccount(QObject* parent) : QObject(parent) {
+ data.internalId = QUuid::createUuid().toString().remove(QRegExp("[{}-]"));
+}
+
MinecraftAccountPtr MinecraftAccount::loadFromJsonV2(const QJsonObject& json) {
MinecraftAccountPtr account(new MinecraftAccount());
@@ -52,7 +54,7 @@ MinecraftAccountPtr MinecraftAccount::loadFromJsonV3(const QJsonObject& json) {
MinecraftAccountPtr MinecraftAccount::createFromUsername(const QString &username)
{
- MinecraftAccountPtr account(new MinecraftAccount());
+ MinecraftAccountPtr account = new MinecraftAccount();
account->data.type = AccountType::Mojang;
account->data.yggdrasilToken.extra["userName"] = username;
account->data.yggdrasilToken.extra["clientToken"] = QUuid::createUuid().toString().remove(QRegExp("[{}-]"));
@@ -72,23 +74,8 @@ QJsonObject MinecraftAccount::saveToJson() const
return data.saveState();
}
-AccountStatus MinecraftAccount::accountStatus() const {
- if(data.type == AccountType::Mojang) {
- if (data.accessToken().isEmpty()) {
- return NotVerified;
- }
- else {
- return Verified;
- }
- }
- // MSA
- // FIXME: this is extremely crude and probably wrong
- if(data.msaToken.token.isEmpty()) {
- return NotVerified;
- }
- else {
- return Verified;
- }
+AccountState MinecraftAccount::accountState() const {
+ return data.accountState;
}
QPixmap MinecraftAccount::getFace() const {
@@ -104,190 +91,146 @@ QPixmap MinecraftAccount::getFace() const {
}
-std::shared_ptr<AccountTask> MinecraftAccount::login(AuthSessionPtr session, QString password)
-{
+shared_qobject_ptr<AccountTask> MinecraftAccount::login(QString password) {
Q_ASSERT(m_currentTask.get() == nullptr);
- // take care of the true offline status
- if (accountStatus() == NotVerified && password.isEmpty())
- {
- if (session)
- {
- session->status = AuthSession::RequiresPassword;
- fillSession(session);
- }
- return nullptr;
- }
-
- if(accountStatus() == Verified && !session->wants_online)
- {
- session->status = AuthSession::PlayableOffline;
- session->auth_server_online = false;
- fillSession(session);
- return nullptr;
- }
- else
- {
- if (password.isEmpty())
- {
- m_currentTask.reset(new MojangRefresh(&data));
- }
- else
- {
- m_currentTask.reset(new MojangLogin(&data, password));
- }
- m_currentTask->assignSession(session);
-
- connect(m_currentTask.get(), SIGNAL(succeeded()), SLOT(authSucceeded()));
- connect(m_currentTask.get(), SIGNAL(failed(QString)), SLOT(authFailed(QString)));
- }
+ m_currentTask.reset(new MojangLogin(&data, password));
+ connect(m_currentTask.get(), SIGNAL(succeeded()), SLOT(authSucceeded()));
+ connect(m_currentTask.get(), SIGNAL(failed(QString)), SLOT(authFailed(QString)));
+ emit activityChanged(true);
return m_currentTask;
}
-std::shared_ptr<AccountTask> MinecraftAccount::loginMSA(AuthSessionPtr session) {
+shared_qobject_ptr<AccountTask> MinecraftAccount::loginMSA() {
Q_ASSERT(m_currentTask.get() == nullptr);
- if(accountStatus() == Verified && !session->wants_online)
- {
- session->status = AuthSession::PlayableOffline;
- session->auth_server_online = false;
- fillSession(session);
- return nullptr;
- }
- else
- {
- m_currentTask.reset(new MSAInteractive(&data));
- m_currentTask->assignSession(session);
-
- connect(m_currentTask.get(), SIGNAL(succeeded()), SLOT(authSucceeded()));
- connect(m_currentTask.get(), SIGNAL(failed(QString)), SLOT(authFailed(QString)));
- }
+ m_currentTask.reset(new MSAInteractive(&data));
+ connect(m_currentTask.get(), SIGNAL(succeeded()), SLOT(authSucceeded()));
+ connect(m_currentTask.get(), SIGNAL(failed(QString)), SLOT(authFailed(QString)));
+ emit activityChanged(true);
return m_currentTask;
}
-std::shared_ptr<AccountTask> MinecraftAccount::refresh(AuthSessionPtr session) {
- Q_ASSERT(m_currentTask.get() == nullptr);
-
- // take care of the true offline status
- if (accountStatus() == NotVerified)
- {
- if (session)
- {
- if(data.type == AccountType::MSA) {
- session->status = AuthSession::RequiresOAuth;
- }
- else {
- session->status = AuthSession::RequiresPassword;
- }
- fillSession(session);
- }
- return nullptr;
+shared_qobject_ptr<AccountTask> MinecraftAccount::refresh() {
+ if(m_currentTask) {
+ return m_currentTask;
}
- if(accountStatus() == Verified && !session->wants_online)
- {
- session->status = AuthSession::PlayableOffline;
- session->auth_server_online = false;
- fillSession(session);
- return nullptr;
+ if(data.type == AccountType::MSA) {
+ m_currentTask.reset(new MSASilent(&data));
}
- else
- {
- if(data.type == AccountType::MSA) {
- m_currentTask.reset(new MSASilent(&data));
- }
- else {
- m_currentTask.reset(new MojangRefresh(&data));
- }
- m_currentTask->assignSession(session);
-
- connect(m_currentTask.get(), SIGNAL(succeeded()), SLOT(authSucceeded()));
- connect(m_currentTask.get(), SIGNAL(failed(QString)), SLOT(authFailed(QString)));
+ else {
+ m_currentTask.reset(new MojangRefresh(&data));
}
+
+ connect(m_currentTask.get(), SIGNAL(succeeded()), SLOT(authSucceeded()));
+ connect(m_currentTask.get(), SIGNAL(failed(QString)), SLOT(authFailed(QString)));
+ emit activityChanged(true);
+ return m_currentTask;
+}
+
+shared_qobject_ptr<AccountTask> MinecraftAccount::currentTask() {
return m_currentTask;
}
void MinecraftAccount::authSucceeded()
{
- auto session = m_currentTask->getAssignedSession();
- if (session)
- {
- session->status =
- session->wants_online ? AuthSession::PlayableOnline : AuthSession::PlayableOffline;
- fillSession(session);
- session->auth_server_online = true;
- }
m_currentTask.reset();
emit changed();
+ emit activityChanged(false);
}
void MinecraftAccount::authFailed(QString reason)
{
- auto session = m_currentTask->getAssignedSession();
- // This is emitted when the yggdrasil tasks time out or are cancelled.
- // -> we treat the error as no-op
- switch (m_currentTask->accountState()) {
- case AccountTask::STATE_FAILED_SOFT: {
- if (session)
- {
- if(accountStatus() == Verified) {
- session->status = AuthSession::PlayableOffline;
- }
- else {
- if(data.type == AccountType::MSA) {
- session->status = AuthSession::RequiresOAuth;
- }
- else {
- session->status = AuthSession::RequiresPassword;
- }
- }
- session->auth_server_online = false;
- fillSession(session);
- }
+ switch (m_currentTask->taskState()) {
+ case AccountTaskState::STATE_OFFLINE:
+ case AccountTaskState::STATE_FAILED_SOFT: {
+ // NOTE: this doesn't do much. There was an error of some sort.
}
break;
- case AccountTask::STATE_FAILED_HARD: {
- // FIXME: MSA data clearing
- data.yggdrasilToken.token = QString();
- data.yggdrasilToken.validity = Katabasis::Validity::None;
- data.validity_ = Katabasis::Validity::None;
- emit changed();
- if (session)
- {
- if(data.type == AccountType::MSA) {
- session->status = AuthSession::RequiresOAuth;
- }
- else {
- session->status = AuthSession::RequiresPassword;
- }
- session->auth_server_online = true;
- fillSession(session);
+ case AccountTaskState::STATE_FAILED_HARD: {
+ if(isMSA()) {
+ data.msaToken.token = QString();
+ data.msaToken.refresh_token = QString();
+ data.msaToken.validity = Katabasis::Validity::None;
+ data.validity_ = Katabasis::Validity::None;
}
+ else {
+ data.yggdrasilToken.token = QString();
+ data.yggdrasilToken.validity = Katabasis::Validity::None;
+ data.validity_ = Katabasis::Validity::None;
+ }
+ emit changed();
}
break;
- case AccountTask::STATE_FAILED_GONE: {
+ case AccountTaskState::STATE_FAILED_GONE: {
data.validity_ = Katabasis::Validity::None;
emit changed();
- if (session)
- {
- session->status = AuthSession::GoneOrMigrated;
- session->auth_server_online = true;
- fillSession(session);
- }
}
break;
- case AccountTask::STATE_CREATED:
- case AccountTask::STATE_WORKING:
- case AccountTask::STATE_SUCCEEDED: {
+ case AccountTaskState::STATE_CREATED:
+ case AccountTaskState::STATE_WORKING:
+ case AccountTaskState::STATE_SUCCEEDED: {
// Not reachable here, as they are not failures.
}
}
m_currentTask.reset();
+ emit activityChanged(false);
+}
+
+bool MinecraftAccount::isActive() const {
+ return m_currentTask;
+}
+
+bool MinecraftAccount::shouldRefresh() const {
+ /*
+ * Never refresh accounts that are being used by the game, it breaks the game session.
+ * Always refresh accounts that have not been refreshed yet during this session.
+ * Don't refresh broken accounts.
+ * Refresh accounts that would expire in the next 12 hours (fresh token validity is 24 hours).
+ */
+ if(isInUse()) {
+ return false;
+ }
+ switch(data.validity_) {
+ case Katabasis::Validity::Certain: {
+ break;
+ }
+ case Katabasis::Validity::None: {
+ return false;
+ }
+ case Katabasis::Validity::Assumed: {
+ return true;
+ }
+ }
+ auto now = QDateTime::currentDateTimeUtc();
+ auto issuedTimestamp = data.yggdrasilToken.issueInstant;
+ auto expiresTimestamp = data.yggdrasilToken.notAfter;
+
+ if(!expiresTimestamp.isValid()) {
+ expiresTimestamp = issuedTimestamp.addSecs(24 * 3600);
+ }
+ if (now.secsTo(expiresTimestamp) < (12 * 3600)) {
+ return true;
+ }
+ return false;
}
void MinecraftAccount::fillSession(AuthSessionPtr session)
{
+ if(ownsMinecraft() && !hasProfile()) {
+ session->status = AuthSession::RequiresProfileSetup;
+ }
+ else {
+ if(session->wants_online) {
+ session->status = AuthSession::PlayableOnline;
+ }
+ else {
+ session->status = AuthSession::PlayableOffline;
+ }
+ }
+
// the user name. you have to have an user name
// FIXME: not with MSA
session->username = data.userName();
@@ -309,7 +252,6 @@ void MinecraftAccount::fillSession(AuthSessionPtr session)
{
session->session = "-";
}
- session->m_accountPtr = shared_from_this();
}
void MinecraftAccount::decrementUses()
diff --git a/launcher/minecraft/auth/MinecraftAccount.h b/launcher/minecraft/auth/MinecraftAccount.h
index 5b0c1ec7..4ac0a3e5 100644
--- a/launcher/minecraft/auth/MinecraftAccount.h
+++ b/launcher/minecraft/auth/MinecraftAccount.h
@@ -24,15 +24,17 @@
#include <QPixmap>
#include <memory>
+
#include "AuthSession.h"
#include "Usable.h"
#include "AccountData.h"
+#include "QObjectPtr.h"
class Task;
class AccountTask;
class MinecraftAccount;
-typedef std::shared_ptr<MinecraftAccount> MinecraftAccountPtr;
+typedef shared_qobject_ptr<MinecraftAccount> MinecraftAccountPtr;
Q_DECLARE_METATYPE(MinecraftAccountPtr)
/**
@@ -49,12 +51,6 @@ struct AccountProfile
bool legacy;
};
-enum AccountStatus
-{
- NotVerified,
- Verified
-};
-
/**
* Object that stores information about a certain Mojang account.
*
@@ -63,8 +59,7 @@ enum AccountStatus
*/
class MinecraftAccount :
public QObject,
- public Usable,
- public std::enable_shared_from_this<MinecraftAccount>
+ public Usable
{
Q_OBJECT
public: /* construction */
@@ -72,7 +67,7 @@ public: /* construction */
explicit MinecraftAccount(const MinecraftAccount &other, QObject *parent) = delete;
//! Default constructor
- explicit MinecraftAccount(QObject *parent = 0) : QObject(parent) {};
+ explicit MinecraftAccount(QObject *parent = 0);
static MinecraftAccountPtr createFromUsername(const QString &username);
@@ -90,13 +85,19 @@ public: /* manipulation */
* Attempt to login. Empty password means we use the token.
* If the attempt fails because we already are performing some task, it returns false.
*/
- std::shared_ptr<AccountTask> login(AuthSessionPtr session, QString password = QString());
+ shared_qobject_ptr<AccountTask> login(QString password);
+
+ shared_qobject_ptr<AccountTask> loginMSA();
- std::shared_ptr<AccountTask> loginMSA(AuthSessionPtr session);
+ shared_qobject_ptr<AccountTask> refresh();
- std::shared_ptr<AccountTask> refresh(AuthSessionPtr session);
+ shared_qobject_ptr<AccountTask> currentTask();
public: /* queries */
+ QString internalId() const {
+ return data.internalId;
+ }
+
QString accountDisplayString() const {
return data.accountDisplayString();
}
@@ -117,6 +118,8 @@ public: /* queries */
return data.profileName();
}
+ bool isActive() const;
+
bool canMigrate() const {
return data.canMigrateToMSA;
}
@@ -125,6 +128,14 @@ public: /* queries */
return data.type == AccountType::MSA;
}
+ bool ownsMinecraft() const {
+ return data.minecraftEntitlement.ownsMinecraft;
+ }
+
+ bool hasProfile() const {
+ return data.profileId().size() != 0;
+ }
+
QString typeString() const {
switch(data.type) {
case AccountType::Mojang: {
@@ -146,26 +157,36 @@ public: /* queries */
QPixmap getFace() const;
- //! Returns whether the account is NotVerified, Verified or Online
- AccountStatus accountStatus() const;
+ //! Returns the current state of the account
+ AccountState accountState() const;
AccountData * accountData() {
return &data;
}
+ bool shouldRefresh() const;
+
+ void fillSession(AuthSessionPtr session);
+
+ QString lastError() const {
+ return data.lastError();
+ }
+
signals:
/**
* This signal is emitted when the account changes
*/
void changed();
+ void activityChanged(bool active);
+
// TODO: better signalling for the various possible state changes - especially errors
protected: /* variables */
AccountData data;
// current task we are executing here
- std::shared_ptr<AccountTask> m_currentTask;
+ shared_qobject_ptr<AccountTask> m_currentTask;
protected: /* methods */
@@ -176,7 +197,4 @@ private
slots:
void authSucceeded();
void authFailed(QString reason);
-
-private:
- void fillSession(AuthSessionPtr session);
};
diff --git a/launcher/minecraft/auth/Parsers.cpp b/launcher/minecraft/auth/Parsers.cpp
new file mode 100644
index 00000000..4cab78ef
--- /dev/null
+++ b/launcher/minecraft/auth/Parsers.cpp
@@ -0,0 +1,316 @@
+#include "Parsers.h"
+
+#include <QJsonDocument>
+#include <QJsonArray>
+#include <QDebug>
+
+namespace Parsers {
+
+bool getDateTime(QJsonValue value, QDateTime & out) {
+ if(!value.isString()) {
+ return false;
+ }
+ out = QDateTime::fromString(value.toString(), Qt::ISODate);
+ return out.isValid();
+}
+
+bool getString(QJsonValue value, QString & out) {
+ if(!value.isString()) {
+ return false;
+ }
+ out = value.toString();
+ return true;
+}
+
+bool getNumber(QJsonValue value, double & out) {
+ if(!value.isDouble()) {
+ return false;
+ }
+ out = value.toDouble();
+ return true;
+}
+
+bool getNumber(QJsonValue value, int64_t & out) {
+ if(!value.isDouble()) {
+ return false;
+ }
+ out = (int64_t) value.toDouble();
+ return true;
+}
+
+bool getBool(QJsonValue value, bool & out) {
+ if(!value.isBool()) {
+ return false;
+ }
+ out = value.toBool();
+ return true;
+}
+
+/*
+{
+ "IssueInstant":"2020-12-07T19:52:08.4463796Z",
+ "NotAfter":"2020-12-21T19:52:08.4463796Z",
+ "Token":"token",
+ "DisplayClaims":{
+ "xui":[
+ {
+ "uhs":"userhash"
+ }
+ ]
+ }
+ }
+*/
+// TODO: handle error responses ...
+/*
+{
+ "Identity":"0",
+ "XErr":2148916238,
+ "Message":"",
+ "Redirect":"https://start.ui.xboxlive.com/AddChildToFamily"
+}
+// 2148916233 = missing XBox account
+// 2148916238 = child account not linked to a family
+*/
+
+bool parseXTokenResponse(QByteArray & data, Katabasis::Token &output, QString name) {
+ qDebug() << "Parsing" << name <<":";
+#ifndef NDEBUG
+ qDebug() << data;
+#endif
+ QJsonParseError jsonError;
+ QJsonDocument doc = QJsonDocument::fromJson(data, &jsonError);
+ if(jsonError.error) {
+ qWarning() << "Failed to parse response from user.auth.xboxlive.com as JSON: " << jsonError.errorString();
+ return false;
+ }
+
+ auto obj = doc.object();
+ if(!getDateTime(obj.value("IssueInstant"), output.issueInstant)) {
+ qWarning() << "User IssueInstant is not a timestamp";
+ return false;
+ }
+ if(!getDateTime(obj.value("NotAfter"), output.notAfter)) {
+ qWarning() << "User NotAfter is not a timestamp";
+ return false;
+ }
+ if(!getString(obj.value("Token"), output.token)) {
+ qWarning() << "User Token is not a timestamp";
+ return false;
+ }
+ auto arrayVal = obj.value("DisplayClaims").toObject().value("xui");
+ if(!arrayVal.isArray()) {
+ qWarning() << "Missing xui claims array";
+ return false;
+ }
+ bool foundUHS = false;
+ for(auto item: arrayVal.toArray()) {
+ if(!item.isObject()) {
+ continue;
+ }
+ auto obj = item.toObject();
+ if(obj.contains("uhs")) {
+ foundUHS = true;
+ } else {
+ continue;
+ }
+ // consume all 'display claims' ... whatever that means
+ for(auto iter = obj.begin(); iter != obj.end(); iter++) {
+ QString claim;
+ if(!getString(obj.value(iter.key()), claim)) {
+ qWarning() << "display claim " << iter.key() << " is not a string...";
+ return false;
+ }
+ output.extra[iter.key()] = claim;
+ }
+
+ break;
+ }
+ if(!foundUHS) {
+ qWarning() << "Missing uhs";
+ return false;
+ }
+ output.validity = Katabasis::Validity::Certain;
+ qDebug() << name << "is valid.";
+ return true;
+}
+
+bool parseMinecraftProfile(QByteArray & data, MinecraftProfile &output) {
+ qDebug() << "Parsing Minecraft profile...";
+#ifndef NDEBUG
+ qDebug() << data;
+#endif
+
+ QJsonParseError jsonError;
+ QJsonDocument doc = QJsonDocument::fromJson(data, &jsonError);
+ if(jsonError.error) {
+ qWarning() << "Failed to parse response from user.auth.xboxlive.com as JSON: " << jsonError.errorString();
+ return false;
+ }
+
+ auto obj = doc.object();
+ if(!getString(obj.value("id"), output.id)) {
+ qWarning() << "Minecraft profile id is not a string";
+ return false;
+ }
+
+ if(!getString(obj.value("name"), output.name)) {
+ qWarning() << "Minecraft profile name is not a string";
+ return false;
+ }
+
+ auto skinsArray = obj.value("skins").toArray();
+ for(auto skin: skinsArray) {
+ auto skinObj = skin.toObject();
+ Skin skinOut;
+ if(!getString(skinObj.value("id"), skinOut.id)) {
+ continue;
+ }
+ QString state;
+ if(!getString(skinObj.value("state"), state)) {
+ continue;
+ }
+ if(state != "ACTIVE") {
+ continue;
+ }
+ if(!getString(skinObj.value("url"), skinOut.url)) {
+ continue;
+ }
+ if(!getString(skinObj.value("variant"), skinOut.variant)) {
+ continue;
+ }
+ // we deal with only the active skin
+ output.skin = skinOut;
+ break;
+ }
+ auto capesArray = obj.value("capes").toArray();
+
+ QString currentCape;
+ for(auto cape: capesArray) {
+ auto capeObj = cape.toObject();
+ Cape capeOut;
+ if(!getString(capeObj.value("id"), capeOut.id)) {
+ continue;
+ }
+ QString state;
+ if(!getString(capeObj.value("state"), state)) {
+ continue;
+ }
+ if(state == "ACTIVE") {
+ currentCape = capeOut.id;
+ }
+ if(!getString(capeObj.value("url"), capeOut.url)) {
+ continue;
+ }
+ if(!getString(capeObj.value("alias"), capeOut.alias)) {
+ continue;
+ }
+
+ output.capes[capeOut.id] = capeOut;
+ }
+ output.currentCape = currentCape;
+ output.validity = Katabasis::Validity::Certain;
+ return true;
+}
+
+bool parseMinecraftEntitlements(QByteArray & data, MinecraftEntitlement &output) {
+ qDebug() << "Parsing Minecraft entitlements...";
+#ifndef NDEBUG
+ qDebug() << data;
+#endif
+
+ QJsonParseError jsonError;
+ QJsonDocument doc = QJsonDocument::fromJson(data, &jsonError);
+ if(jsonError.error) {
+ qWarning() << "Failed to parse response from user.auth.xboxlive.com as JSON: " << jsonError.errorString();
+ return false;
+ }
+
+ auto obj = doc.object();
+
+ auto itemsArray = obj.value("items").toArray();
+ for(auto item: itemsArray) {
+ auto itemObj = item.toObject();
+ QString name;
+ if(!getString(itemObj.value("name"), name)) {
+ continue;
+ }
+ if(name == "game_minecraft") {
+ output.canPlayMinecraft = true;
+ }
+ if(name == "product_minecraft") {
+ output.ownsMinecraft = true;
+ }
+ }
+ output.validity = Katabasis::Validity::Certain;
+ return true;
+}
+
+bool parseRolloutResponse(QByteArray & data, bool& result) {
+ qDebug() << "Parsing Rollout response...";
+#ifndef NDEBUG
+ qDebug() << data;
+#endif
+
+ QJsonParseError jsonError;
+ QJsonDocument doc = QJsonDocument::fromJson(data, &jsonError);
+ if(jsonError.error) {
+ qWarning() << "Failed to parse response from https://api.minecraftservices.com/rollout/v1/msamigration as JSON: " << jsonError.errorString();
+ return false;
+ }
+
+ auto obj = doc.object();
+ QString feature;
+ if(!getString(obj.value("feature"), feature)) {
+ qWarning() << "Rollout feature is not a string";
+ return false;
+ }
+ if(feature != "msamigration") {
+ qWarning() << "Rollout feature is not what we expected (msamigration), but is instead \"" << feature << "\"";
+ return false;
+ }
+ if(!getBool(obj.value("rollout"), result)) {
+ qWarning() << "Rollout feature is not a string";
+ return false;
+ }
+ return true;
+}
+
+bool parseMojangResponse(QByteArray & data, Katabasis::Token &output) {
+ QJsonParseError jsonError;
+ qDebug() << "Parsing Mojang response...";
+#ifndef NDEBUG
+ qDebug() << data;
+#endif
+ QJsonDocument doc = QJsonDocument::fromJson(data, &jsonError);
+ if(jsonError.error) {
+ qWarning() << "Failed to parse response from api.minecraftservices.com/launcher/login as JSON: " << jsonError.errorString();
+ return false;
+ }
+
+ auto obj = doc.object();
+ double expires_in = 0;
+ if(!getNumber(obj.value("expires_in"), expires_in)) {
+ qWarning() << "expires_in is not a valid number";
+ return false;
+ }
+ auto currentTime = QDateTime::currentDateTimeUtc();
+ output.issueInstant = currentTime;
+ output.notAfter = currentTime.addSecs(expires_in);
+
+ QString username;
+ if(!getString(obj.value("username"), username)) {
+ qWarning() << "username is not valid";
+ return false;
+ }
+
+ // TODO: it's a JWT... validate it?
+ if(!getString(obj.value("access_token"), output.token)) {
+ qWarning() << "access_token is not valid";
+ return false;
+ }
+ output.validity = Katabasis::Validity::Certain;
+ qDebug() << "Mojang response is valid.";
+ return true;
+}
+
+}
diff --git a/launcher/minecraft/auth/Parsers.h b/launcher/minecraft/auth/Parsers.h
new file mode 100644
index 00000000..dac7f69b
--- /dev/null
+++ b/launcher/minecraft/auth/Parsers.h
@@ -0,0 +1,19 @@
+#pragma once
+
+#include "AccountData.h"
+
+namespace Parsers
+{
+ bool getDateTime(QJsonValue value, QDateTime & out);
+ bool getString(QJsonValue value, QString & out);
+ bool getNumber(QJsonValue value, double & out);
+ bool getNumber(QJsonValue value, int64_t & out);
+ bool getBool(QJsonValue value, bool & out);
+
+ bool parseXTokenResponse(QByteArray &data, Katabasis::Token &output, QString name);
+ bool parseMojangResponse(QByteArray &data, Katabasis::Token &output);
+
+ bool parseMinecraftProfile(QByteArray &data, MinecraftProfile &output);
+ bool parseMinecraftEntitlements(QByteArray &data, MinecraftEntitlement &output);
+ bool parseRolloutResponse(QByteArray &data, bool& result);
+}
diff --git a/launcher/minecraft/auth/flows/Yggdrasil.cpp b/launcher/minecraft/auth/Yggdrasil.cpp
index 20ca63d0..7ac842a6 100644
--- a/launcher/minecraft/auth/flows/Yggdrasil.cpp
+++ b/launcher/minecraft/auth/Yggdrasil.cpp
@@ -14,7 +14,7 @@
*/
#include "Yggdrasil.h"
-#include "../AccountData.h"
+#include "AccountData.h"
#include <QObject>
#include <QString>
@@ -23,24 +23,22 @@
#include <QNetworkReply>
#include <QByteArray>
-#include <Env.h>
-
-#include <BuildConfig.h>
-
#include <QDebug>
+#include "Application.h"
+
Yggdrasil::Yggdrasil(AccountData *data, QObject *parent)
: AccountTask(data, parent)
{
- changeState(STATE_CREATED);
+ changeState(AccountTaskState::STATE_CREATED);
}
void Yggdrasil::sendRequest(QUrl endpoint, QByteArray content) {
- changeState(STATE_WORKING);
+ changeState(AccountTaskState::STATE_WORKING);
QNetworkRequest netRequest(endpoint);
netRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
- m_netReply = ENV.qnam().post(netRequest, content);
+ m_netReply = APPLICATION->network()->post(netRequest, content);
connect(m_netReply, &QNetworkReply::finished, this, &Yggdrasil::processReply);
connect(m_netReply, &QNetworkReply::uploadProgress, this, &Yggdrasil::refreshTimers);
connect(m_netReply, &QNetworkReply::downloadProgress, this, &Yggdrasil::refreshTimers);
@@ -86,7 +84,7 @@ void Yggdrasil::refresh() {
req.insert("requestUser", false);
QJsonDocument doc(req);
- QUrl reqUrl(BuildConfig.AUTH_BASE + "refresh");
+ QUrl reqUrl("https://authserver.mojang.com/refresh");
QByteArray requestData = doc.toJson();
sendRequest(reqUrl, requestData);
@@ -131,7 +129,7 @@ void Yggdrasil::login(QString password) {
QJsonDocument doc(req);
- QUrl reqUrl(BuildConfig.AUTH_BASE + "authenticate");
+ QUrl reqUrl("https://authserver.mojang.com/authenticate");
QNetworkRequest netRequest(reqUrl);
QByteArray requestData = doc.toJson();
@@ -140,20 +138,18 @@ void Yggdrasil::login(QString password) {
-void Yggdrasil::refreshTimers(qint64, qint64)
-{
+void Yggdrasil::refreshTimers(qint64, qint64) {
timeout_keeper.stop();
timeout_keeper.start(timeout_max);
progress(count = 0, timeout_max);
}
-void Yggdrasil::heartbeat()
-{
+
+void Yggdrasil::heartbeat() {
count += time_step;
progress(count, timeout_max);
}
-bool Yggdrasil::abort()
-{
+bool Yggdrasil::abort() {
progress(timeout_max, timeout_max);
// TODO: actually use this in a meaningful way
m_aborted = Yggdrasil::BY_USER;
@@ -161,19 +157,16 @@ bool Yggdrasil::abort()
return true;
}
-void Yggdrasil::abortByTimeout()
-{
+void Yggdrasil::abortByTimeout() {
progress(timeout_max, timeout_max);
// TODO: actually use this in a meaningful way
m_aborted = Yggdrasil::BY_TIMEOUT;
m_netReply->abort();
}
-void Yggdrasil::sslErrors(QList<QSslError> errors)
-{
+void Yggdrasil::sslErrors(QList<QSslError> errors) {
int i = 1;
- for (auto error : errors)
- {
+ for (auto error : errors) {
qCritical() << "LOGIN SSL Error #" << i << " : " << error.errorString();
auto cert = error.certificate();
qCritical() << "Certificate in question:\n" << cert.toText();
@@ -181,8 +174,7 @@ void Yggdrasil::sslErrors(QList<QSslError> errors)
}
}
-void Yggdrasil::processResponse(QJsonObject responseData)
-{
+void Yggdrasil::processResponse(QJsonObject responseData) {
// Read the response data. We need to get the client token, access token, and the selected
// profile.
qDebug() << "Processing authentication response.";
@@ -191,65 +183,63 @@ void Yggdrasil::processResponse(QJsonObject responseData)
// If we already have a client token, make sure the one the server gave us matches our
// existing one.
QString clientToken = responseData.value("clientToken").toString("");
- if (clientToken.isEmpty())
- {
+ if (clientToken.isEmpty()) {
// Fail if the server gave us an empty client token
- changeState(STATE_FAILED_HARD, tr("Authentication server didn't send a client token."));
+ changeState(AccountTaskState::STATE_FAILED_HARD, tr("Authentication server didn't send a client token."));
return;
}
if(m_data->clientToken().isEmpty()) {
m_data->setClientToken(clientToken);
}
else if(clientToken != m_data->clientToken()) {
- changeState(STATE_FAILED_HARD, tr("Authentication server attempted to change the client token. This isn't supported."));
+ changeState(AccountTaskState::STATE_FAILED_HARD, tr("Authentication server attempted to change the client token. This isn't supported."));
return;
}
// Now, we set the access token.
qDebug() << "Getting access token.";
QString accessToken = responseData.value("accessToken").toString("");
- if (accessToken.isEmpty())
- {
+ if (accessToken.isEmpty()) {
// Fail if the server didn't give us an access token.
- changeState(STATE_FAILED_HARD, tr("Authentication server didn't send an access token."));
+ changeState(AccountTaskState::STATE_FAILED_HARD, tr("Authentication server didn't send an access token."));
return;
}
// Set the access token.
m_data->yggdrasilToken.token = accessToken;
m_data->yggdrasilToken.validity = Katabasis::Validity::Certain;
+ m_data->yggdrasilToken.issueInstant = QDateTime::currentDateTimeUtc();
// We've made it through the minefield of possible errors. Return true to indicate that
// we've succeeded.
qDebug() << "Finished reading authentication response.";
- changeState(STATE_SUCCEEDED);
+ changeState(AccountTaskState::STATE_SUCCEEDED);
}
-void Yggdrasil::processReply()
-{
- changeState(STATE_WORKING);
+void Yggdrasil::processReply() {
+ changeState(AccountTaskState::STATE_WORKING);
switch (m_netReply->error())
{
case QNetworkReply::NoError:
break;
case QNetworkReply::TimeoutError:
- changeState(STATE_FAILED_SOFT, tr("Authentication operation timed out."));
+ changeState(AccountTaskState::STATE_FAILED_SOFT, tr("Authentication operation timed out."));
return;
case QNetworkReply::OperationCanceledError:
- changeState(STATE_FAILED_SOFT, tr("Authentication operation cancelled."));
+ changeState(AccountTaskState::STATE_FAILED_SOFT, tr("Authentication operation cancelled."));
return;
case QNetworkReply::SslHandshakeFailedError:
changeState(
- STATE_FAILED_SOFT,
+ AccountTaskState::STATE_FAILED_SOFT,
tr(
"<b>SSL Handshake failed.</b><br/>There might be a few causes for it:<br/>"
"<ul>"
"<li>You use Windows and need to update your root certificates, please install any outstanding updates.</li>"
"<li>Some device on your network is interfering with SSL traffic. In that case, "
"you have bigger worries than Minecraft not starting.</li>"
- "<li>Possibly something else. Check the %1 log file for details</li>"
+ "<li>Possibly something else. Check the log file for details</li>"
"</ul>"
- ).arg(BuildConfig.LAUNCHER_NAME)
+ )
);
return;
// used for invalid credentials and similar errors. Fall through.
@@ -258,13 +248,13 @@ void Yggdrasil::processReply()
break;
case QNetworkReply::ContentGoneError: {
changeState(
- STATE_FAILED_GONE,
+ AccountTaskState::STATE_FAILED_GONE,
tr("The Mojang account no longer exists. It may have been migrated to a Microsoft account.")
);
}
default:
changeState(
- STATE_FAILED_SOFT,
+ AccountTaskState::STATE_FAILED_SOFT,
tr("Authentication operation failed due to a network error: %1 (%2)").arg(m_netReply->errorString()).arg(m_netReply->error())
);
return;
@@ -278,21 +268,18 @@ void Yggdrasil::processReply()
// Check the response code.
int responseCode = m_netReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
- if (responseCode == 200)
- {
+ if (responseCode == 200) {
// If the response code was 200, then there shouldn't be an error. Make sure
// anyways.
// Also, sometimes an empty reply indicates success. If there was no data received,
// pass an empty json object to the processResponse function.
- if (jsonError.error == QJsonParseError::NoError || replyData.size() == 0)
- {
+ if (jsonError.error == QJsonParseError::NoError || replyData.size() == 0) {
processResponse(replyData.size() > 0 ? doc.object() : QJsonObject());
return;
}
- else
- {
+ else {
changeState(
- STATE_FAILED_SOFT,
+ AccountTaskState::STATE_FAILED_SOFT,
tr("Failed to parse authentication server response JSON response: %1 at offset %2.").arg(jsonError.errorString()).arg(jsonError.offset)
);
qCritical() << replyData;
@@ -304,34 +291,30 @@ void Yggdrasil::processReply()
// about the error.
// If we can parse the response, then get information from it. Otherwise just say
// there was an unknown error.
- if (jsonError.error == QJsonParseError::NoError)
- {
+ if (jsonError.error == QJsonParseError::NoError) {
// We were able to parse the server's response. Woo!
// Call processError. If a subclass has overridden it then they'll handle their
// stuff there.
qDebug() << "The request failed, but the server gave us an error message. Processing error.";
processError(doc.object());
}
- else
- {
+ else {
// The server didn't say anything regarding the error. Give the user an unknown
// error.
qDebug() << "The request failed and the server gave no error message. Unknown error.";
changeState(
- STATE_FAILED_SOFT,
+ AccountTaskState::STATE_FAILED_SOFT,
tr("An unknown error occurred when trying to communicate with the authentication server: %1").arg(m_netReply->errorString())
);
}
}
-void Yggdrasil::processError(QJsonObject responseData)
-{
+void Yggdrasil::processError(QJsonObject responseData) {
QJsonValue errorVal = responseData.value("error");
QJsonValue errorMessageValue = responseData.value("errorMessage");
QJsonValue causeVal = responseData.value("cause");
- if (errorVal.isString() && errorMessageValue.isString())
- {
+ if (errorVal.isString() && errorMessageValue.isString()) {
m_error = std::shared_ptr<Error>(
new Error {
errorVal.toString(""),
@@ -339,11 +322,10 @@ void Yggdrasil::processError(QJsonObject responseData)
causeVal.toString("")
}
);
- changeState(STATE_FAILED_HARD, m_error->m_errorMessageVerbose);
+ changeState(AccountTaskState::STATE_FAILED_HARD, m_error->m_errorMessageVerbose);
}
- else
- {
+ else {
// Error is not in standard format. Don't set m_error and return unknown error.
- changeState(STATE_FAILED_HARD, tr("An unknown Yggdrasil error occurred."));
+ changeState(AccountTaskState::STATE_FAILED_HARD, tr("An unknown Yggdrasil error occurred."));
}
}
diff --git a/launcher/minecraft/auth/flows/Yggdrasil.h b/launcher/minecraft/auth/Yggdrasil.h
index e709cb9f..4f52a04c 100644
--- a/launcher/minecraft/auth/flows/Yggdrasil.h
+++ b/launcher/minecraft/auth/Yggdrasil.h
@@ -15,15 +15,16 @@
#pragma once
-#include "../AccountTask.h"
+#include "AccountTask.h"
#include <QString>
#include <QJsonObject>
#include <QTimer>
#include <qsslerror.h>
-#include "../MinecraftAccount.h"
+#include "MinecraftAccount.h"
+class QNetworkAccessManager;
class QNetworkReply;
/**
@@ -33,11 +34,30 @@ class Yggdrasil : public AccountTask
{
Q_OBJECT
public:
- explicit Yggdrasil(AccountData * data, QObject *parent = 0);
- virtual ~Yggdrasil() {};
+ explicit Yggdrasil(
+ AccountData *data,
+ QObject *parent = 0
+ );
+ virtual ~Yggdrasil() = default;
void refresh();
void login(QString password);
+
+ struct Error
+ {
+ QString m_errorMessageShort;
+ QString m_errorMessageVerbose;
+ QString m_cause;
+ };
+ std::shared_ptr<Error> m_error;
+
+ enum AbortedBy
+ {
+ BY_NOTHING,
+ BY_USER,
+ BY_TIMEOUT
+ } m_aborted = BY_NOTHING;
+
protected:
void executeTask() override;
diff --git a/launcher/minecraft/auth/flows/AuthContext.cpp b/launcher/minecraft/auth/flows/AuthContext.cpp
deleted file mode 100644
index 9fb3ec48..00000000
--- a/launcher/minecraft/auth/flows/AuthContext.cpp
+++ /dev/null
@@ -1,911 +0,0 @@
-#include <QNetworkAccessManager>
-#include <QNetworkRequest>
-#include <QNetworkReply>
-#include <QDesktopServices>
-#include <QMetaEnum>
-#include <QDebug>
-
-#include <QJsonDocument>
-#include <QJsonObject>
-#include <QJsonArray>
-
-#include <QUrlQuery>
-
-#include <QPixmap>
-#include <QPainter>
-
-#include "AuthContext.h"
-#include "katabasis/Globals.h"
-#include "AuthRequest.h"
-
-#include "Secrets.h"
-
-#include "Env.h"
-
-using OAuth2 = Katabasis::OAuth2;
-using Activity = Katabasis::Activity;
-
-AuthContext::AuthContext(AccountData * data, QObject *parent) :
- AccountTask(data, parent)
-{
-}
-
-void AuthContext::beginActivity(Activity activity) {
- if(isBusy()) {
- throw 0;
- }
- m_activity = activity;
- changeState(STATE_WORKING, "Initializing");
- emit activityChanged(m_activity);
-}
-
-void AuthContext::finishActivity() {
- if(!isBusy()) {
- throw 0;
- }
- m_activity = Katabasis::Activity::Idle;
- setStage(AuthStage::Complete);
- m_data->validity_ = m_data->minecraftProfile.validity;
- emit activityChanged(m_activity);
-}
-
-void AuthContext::initMSA() {
- if(m_oauth2) {
- return;
- }
-
- auto clientId = Secrets::getMSAClientID('-');
- if(clientId.isEmpty()) {
- return;
- }
-
- Katabasis::OAuth2::Options opts;
- opts.scope = "XboxLive.signin offline_access";
- opts.clientIdentifier = clientId;
- opts.authorizationUrl = "https://login.microsoftonline.com/consumers/oauth2/v2.0/devicecode";
- opts.accessTokenUrl = "https://login.microsoftonline.com/consumers/oauth2/v2.0/token";
- opts.listenerPorts = {28562, 28563, 28564, 28565, 28566};
-
- m_oauth2 = new OAuth2(opts, m_data->msaToken, this, &ENV.qnam());
- m_oauth2->setGrantFlow(Katabasis::OAuth2::GrantFlowDevice);
-
- connect(m_oauth2, &OAuth2::linkingFailed, this, &AuthContext::onOAuthLinkingFailed);
- connect(m_oauth2, &OAuth2::linkingSucceeded, this, &AuthContext::onOAuthLinkingSucceeded);
- connect(m_oauth2, &OAuth2::showVerificationUriAndCode, this, &AuthContext::showVerificationUriAndCode);
- connect(m_oauth2, &OAuth2::activityChanged, this, &AuthContext::onOAuthActivityChanged);
-}
-
-void AuthContext::initMojang() {
- if(m_yggdrasil) {
- return;
- }
- m_yggdrasil = new Yggdrasil(m_data, this);
-
- connect(m_yggdrasil, &Task::failed, this, &AuthContext::onMojangFailed);
- connect(m_yggdrasil, &Task::succeeded, this, &AuthContext::onMojangSucceeded);
-}
-
-void AuthContext::onMojangSucceeded() {
- doMinecraftProfile();
-}
-
-
-void AuthContext::onMojangFailed() {
- finishActivity();
- m_error = m_yggdrasil->m_error;
- m_aborted = m_yggdrasil->m_aborted;
- changeState(m_yggdrasil->accountState(), tr("Mojang user authentication failed."));
-}
-
-/*
-bool AuthContext::signOut() {
- if(isBusy()) {
- return false;
- }
-
- start();
-
- beginActivity(Activity::LoggingOut);
- m_oauth2->unlink();
- m_account = AccountData();
- finishActivity();
- return true;
-}
-*/
-
-void AuthContext::onOAuthLinkingFailed() {
- emit hideVerificationUriAndCode();
- finishActivity();
- changeState(STATE_FAILED_HARD, tr("Microsoft user authentication failed."));
-}
-
-void AuthContext::onOAuthLinkingSucceeded() {
- emit hideVerificationUriAndCode();
- auto *o2t = qobject_cast<OAuth2 *>(sender());
- if (!o2t->linked()) {
- finishActivity();
- changeState(STATE_FAILED_HARD, tr("Microsoft user authentication ended with an impossible state (succeeded, but not succeeded at the same time)."));
- return;
- }
- QVariantMap extraTokens = o2t->extraTokens();
-#ifndef NDEBUG
- if (!extraTokens.isEmpty()) {
- qDebug() << "Extra tokens in response:";
- foreach (QString key, extraTokens.keys()) {
- qDebug() << "\t" << key << ":" << extraTokens.value(key);
- }
- }
-#endif
- doUserAuth();
-}
-
-void AuthContext::onOAuthActivityChanged(Katabasis::Activity activity) {
- // respond to activity change here
-}
-
-void AuthContext::doUserAuth() {
- setStage(AuthStage::UserAuth);
- changeState(STATE_WORKING, tr("Starting user authentication"));
-
- QString xbox_auth_template = R"XXX(
-{
- "Properties": {
- "AuthMethod": "RPS",
- "SiteName": "user.auth.xboxlive.com",
- "RpsTicket": "d=%1"
- },
- "RelyingParty": "http://auth.xboxlive.com",
- "TokenType": "JWT"
-}
-)XXX";
- auto xbox_auth_data = xbox_auth_template.arg(m_data->msaToken.token);
-
- QNetworkRequest request = QNetworkRequest(QUrl("https://user.auth.xboxlive.com/user/authenticate"));
- request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
- request.setRawHeader("Accept", "application/json");
- auto *requestor = new AuthRequest(this);
- connect(requestor, &AuthRequest::finished, this, &AuthContext::onUserAuthDone);
- requestor->post(request, xbox_auth_data.toUtf8());
- qDebug() << "First layer of XBox auth ... commencing.";
-}
-
-namespace {
-bool getDateTime(QJsonValue value, QDateTime & out) {
- if(!value.isString()) {
- return false;
- }
- out = QDateTime::fromString(value.toString(), Qt::ISODate);
- return out.isValid();
-}
-
-bool getString(QJsonValue value, QString & out) {
- if(!value.isString()) {
- return false;
- }
- out = value.toString();
- return true;
-}
-
-bool getNumber(QJsonValue value, double & out) {
- if(!value.isDouble()) {
- return false;
- }
- out = value.toDouble();
- return true;
-}
-
-bool getNumber(QJsonValue value, int64_t & out) {
- if(!value.isDouble()) {
- return false;
- }
- out = (int64_t) value.toDouble();
- return true;
-}
-
-bool getBool(QJsonValue value, bool & out) {
- if(!value.isBool()) {
- return false;
- }
- out = value.toBool();
- return true;
-}
-
-/*
-{
- "IssueInstant":"2020-12-07T19:52:08.4463796Z",
- "NotAfter":"2020-12-21T19:52:08.4463796Z",
- "Token":"token",
- "DisplayClaims":{
- "xui":[
- {
- "uhs":"userhash"
- }
- ]
- }
- }
-*/
-// TODO: handle error responses ...
-/*
-{
- "Identity":"0",
- "XErr":2148916238,
- "Message":"",
- "Redirect":"https://start.ui.xboxlive.com/AddChildToFamily"
-}
-// 2148916233 = missing XBox account
-// 2148916238 = child account not linked to a family
-*/
-
-bool parseXTokenResponse(QByteArray & data, Katabasis::Token &output, const char * name) {
- qDebug() << "Parsing" << name <<":";
-#ifndef NDEBUG
- qDebug() << data;
-#endif
- QJsonParseError jsonError;
- QJsonDocument doc = QJsonDocument::fromJson(data, &jsonError);
- if(jsonError.error) {
- qWarning() << "Failed to parse response from user.auth.xboxlive.com as JSON: " << jsonError.errorString();
- return false;
- }
-
- auto obj = doc.object();
- if(!getDateTime(obj.value("IssueInstant"), output.issueInstant)) {
- qWarning() << "User IssueInstant is not a timestamp";
- return false;
- }
- if(!getDateTime(obj.value("NotAfter"), output.notAfter)) {
- qWarning() << "User NotAfter is not a timestamp";
- return false;
- }
- if(!getString(obj.value("Token"), output.token)) {
- qWarning() << "User Token is not a timestamp";
- return false;
- }
- auto arrayVal = obj.value("DisplayClaims").toObject().value("xui");
- if(!arrayVal.isArray()) {
- qWarning() << "Missing xui claims array";
- return false;
- }
- bool foundUHS = false;
- for(auto item: arrayVal.toArray()) {
- if(!item.isObject()) {
- continue;
- }
- auto obj = item.toObject();
- if(obj.contains("uhs")) {
- foundUHS = true;
- } else {
- continue;
- }
- // consume all 'display claims' ... whatever that means
- for(auto iter = obj.begin(); iter != obj.end(); iter++) {
- QString claim;
- if(!getString(obj.value(iter.key()), claim)) {
- qWarning() << "display claim " << iter.key() << " is not a string...";
- return false;
- }
- output.extra[iter.key()] = claim;
- }
-
- break;
- }
- if(!foundUHS) {
- qWarning() << "Missing uhs";
- return false;
- }
- output.validity = Katabasis::Validity::Certain;
- qDebug() << name << "is valid.";
- return true;
-}
-
-}
-
-void AuthContext::onUserAuthDone(
- QNetworkReply::NetworkError error,
- QByteArray replyData,
- QList<QNetworkReply::RawHeaderPair> headers
-) {
- if (error != QNetworkReply::NoError) {
- qWarning() << "Reply error:" << error;
- finishActivity();
- changeState(STATE_FAILED_HARD, tr("XBox user authentication failed."));
- return;
- }
-
- Katabasis::Token temp;
- if(!parseXTokenResponse(replyData, temp, "UToken")) {
- qWarning() << "Could not parse user authentication response...";
- finishActivity();
- changeState(STATE_FAILED_HARD, tr("XBox user authentication response could not be understood."));
- return;
- }
- m_data->userToken = temp;
-
- setStage(AuthStage::XboxAuth);
- changeState(STATE_WORKING, tr("Starting XBox authentication"));
-
- doSTSAuthMinecraft();
- doSTSAuthGeneric();
-}
-/*
- url = "https://xsts.auth.xboxlive.com/xsts/authorize"
- headers = {"x-xbl-contract-version": "1"}
- data = {
- "RelyingParty": relying_party,
- "TokenType": "JWT",
- "Properties": {
- "UserTokens": [self.user_token.token],
- "SandboxId": "RETAIL",
- },
- }
-*/
-void AuthContext::doSTSAuthMinecraft() {
- QString xbox_auth_template = R"XXX(
-{
- "Properties": {
- "SandboxId": "RETAIL",
- "UserTokens": [
- "%1"
- ]
- },
- "RelyingParty": "rp://api.minecraftservices.com/",
- "TokenType": "JWT"
-}
-)XXX";
- auto xbox_auth_data = xbox_auth_template.arg(m_data->userToken.token);
-
- QNetworkRequest request = QNetworkRequest(QUrl("https://xsts.auth.xboxlive.com/xsts/authorize"));
- request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
- request.setRawHeader("Accept", "application/json");
- AuthRequest *requestor = new AuthRequest(this);
- connect(requestor, &AuthRequest::finished, this, &AuthContext::onSTSAuthMinecraftDone);
- requestor->post(request, xbox_auth_data.toUtf8());
- qDebug() << "Getting Minecraft services STS token...";
-}
-
-void AuthContext::processSTSError(QNetworkReply::NetworkError error, QByteArray data, QList<QNetworkReply::RawHeaderPair> headers) {
- if(error == QNetworkReply::AuthenticationRequiredError) {
- QJsonParseError jsonError;
- QJsonDocument doc = QJsonDocument::fromJson(data, &jsonError);
- if(jsonError.error) {
- qWarning() << "Cannot parse error XSTS response as JSON: " << jsonError.errorString();
- return;
- }
-
- int64_t errorCode = -1;
- auto obj = doc.object();
- if(!getNumber(obj.value("XErr"), errorCode)) {
- qWarning() << "XErr is not a number";
- return;
- }
- stsErrors.insert(errorCode);
- stsFailed = true;
- }
-}
-
-
-void AuthContext::onSTSAuthMinecraftDone(
- QNetworkReply::NetworkError error,
- QByteArray replyData,
- QList<QNetworkReply::RawHeaderPair> headers
-) {
-#ifndef NDEBUG
- qDebug() << replyData;
-#endif
- if (error != QNetworkReply::NoError) {
- qWarning() << "Reply error:" << error;
- processSTSError(error, replyData, headers);
- failResult(m_mcAuthSucceeded);
- return;
- }
-
- Katabasis::Token temp;
- if(!parseXTokenResponse(replyData, temp, "STSAuthMinecraft")) {
- qWarning() << "Could not parse authorization response for access to mojang services...";
- failResult(m_mcAuthSucceeded);
- return;
- }
-
- if(temp.extra["uhs"] != m_data->userToken.extra["uhs"]) {
- qWarning() << "Server has changed user hash in the reply... something is wrong. ABORTING";
- failResult(m_mcAuthSucceeded);
- return;
- }
- m_data->mojangservicesToken = temp;
-
- doMinecraftAuth();
-}
-
-void AuthContext::doMinecraftAuth() {
- QString mc_auth_template = R"XXX(
-{
- "identityToken": "XBL3.0 x=%1;%2"
-}
-)XXX";
- auto data = mc_auth_template.arg(m_data->mojangservicesToken.extra["uhs"].toString(), m_data->mojangservicesToken.token);
-
- QNetworkRequest request = QNetworkRequest(QUrl("https://api.minecraftservices.com/authentication/login_with_xbox"));
- request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
- request.setRawHeader("Accept", "application/json");
- AuthRequest *requestor = new AuthRequest(this);
- connect(requestor, &AuthRequest::finished, this, &AuthContext::onMinecraftAuthDone);
- requestor->post(request, data.toUtf8());
- qDebug() << "Getting Minecraft access token...";
-}
-
-namespace {
-bool parseMojangResponse(QByteArray & data, Katabasis::Token &output) {
- QJsonParseError jsonError;
- qDebug() << "Parsing Mojang response...";
-#ifndef NDEBUG
- qDebug() << data;
-#endif
- QJsonDocument doc = QJsonDocument::fromJson(data, &jsonError);
- if(jsonError.error) {
- qWarning() << "Failed to parse response from api.minecraftservices.com/authentication/login_with_xbox as JSON: " << jsonError.errorString();
- return false;
- }
-
- auto obj = doc.object();
- double expires_in = 0;
- if(!getNumber(obj.value("expires_in"), expires_in)) {
- qWarning() << "expires_in is not a valid number";
- return false;
- }
- auto currentTime = QDateTime::currentDateTimeUtc();
- output.issueInstant = currentTime;
- output.notAfter = currentTime.addSecs(expires_in);
-
- QString username;
- if(!getString(obj.value("username"), username)) {
- qWarning() << "username is not valid";
- return false;
- }
-
- // TODO: it's a JWT... validate it?
- if(!getString(obj.value("access_token"), output.token)) {
- qWarning() << "access_token is not valid";
- return false;
- }
- output.validity = Katabasis::Validity::Certain;
- qDebug() << "Mojang response is valid.";
- return true;
-}
-}
-
-void AuthContext::onMinecraftAuthDone(
- QNetworkReply::NetworkError error,
- QByteArray replyData,
- QList<QNetworkReply::RawHeaderPair> headers
-) {
- if (error != QNetworkReply::NoError) {
- qWarning() << "Reply error:" << error;
-#ifndef NDEBUG
- qDebug() << replyData;
-#endif
- failResult(m_mcAuthSucceeded);
- return;
- }
-
- if(!parseMojangResponse(replyData, m_data->yggdrasilToken)) {
- qWarning() << "Could not parse login_with_xbox response...";
-#ifndef NDEBUG
- qDebug() << replyData;
-#endif
- failResult(m_mcAuthSucceeded);
- return;
- }
-
- succeedResult(m_mcAuthSucceeded);
-}
-
-void AuthContext::doSTSAuthGeneric() {
- QString xbox_auth_template = R"XXX(
-{
- "Properties": {
- "SandboxId": "RETAIL",
- "UserTokens": [
- "%1"
- ]
- },
- "RelyingParty": "http://xboxlive.com",
- "TokenType": "JWT"
-}
-)XXX";
- auto xbox_auth_data = xbox_auth_template.arg(m_data->userToken.token);
-
- QNetworkRequest request = QNetworkRequest(QUrl("https://xsts.auth.xboxlive.com/xsts/authorize"));
- request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
- request.setRawHeader("Accept", "application/json");
- AuthRequest *requestor = new AuthRequest(this);
- connect(requestor, &AuthRequest::finished, this, &AuthContext::onSTSAuthGenericDone);
- requestor->post(request, xbox_auth_data.toUtf8());
- qDebug() << "Getting generic STS token...";
-}
-
-void AuthContext::onSTSAuthGenericDone(
- QNetworkReply::NetworkError error,
- QByteArray replyData,
- QList<QNetworkReply::RawHeaderPair> headers
-) {
-#ifndef NDEBUG
- qDebug() << replyData;
-#endif
- if (error != QNetworkReply::NoError) {
- qWarning() << "Reply error:" << error;
- processSTSError(error, replyData, headers);
- failResult(m_xboxProfileSucceeded);
- return;
- }
-
- Katabasis::Token temp;
- if(!parseXTokenResponse(replyData, temp, "STSAuthGeneric")) {
- qWarning() << "Could not parse authorization response for access to xbox API...";
- failResult(m_xboxProfileSucceeded);
- return;
- }
-
- if(temp.extra["uhs"] != m_data->userToken.extra["uhs"]) {
- qWarning() << "Server has changed user hash in the reply... something is wrong. ABORTING";
- failResult(m_xboxProfileSucceeded);
- return;
- }
- m_data->xboxApiToken = temp;
-
- doXBoxProfile();
-}
-
-void AuthContext::doXBoxProfile() {
- auto url = QUrl("https://profile.xboxlive.com/users/me/profile/settings");
- QUrlQuery q;
- q.addQueryItem(
- "settings",
- "GameDisplayName,AppDisplayName,AppDisplayPicRaw,GameDisplayPicRaw,"
- "PublicGamerpic,ShowUserAsAvatar,Gamerscore,Gamertag,ModernGamertag,ModernGamertagSuffix,"
- "UniqueModernGamertag,AccountTier,TenureLevel,XboxOneRep,"
- "PreferredColor,Location,Bio,Watermarks,"
- "RealName,RealNameOverride,IsQuarantined"
- );
- url.setQuery(q);
-
- QNetworkRequest request = QNetworkRequest(url);
- request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
- request.setRawHeader("Accept", "application/json");
- request.setRawHeader("x-xbl-contract-version", "3");
- request.setRawHeader("Authorization", QString("XBL3.0 x=%1;%2").arg(m_data->userToken.extra["uhs"].toString(), m_data->xboxApiToken.token).toUtf8());
- AuthRequest *requestor = new AuthRequest(this);
- connect(requestor, &AuthRequest::finished, this, &AuthContext::onXBoxProfileDone);
- requestor->get(request);
- qDebug() << "Getting Xbox profile...";
-}
-
-void AuthContext::onXBoxProfileDone(
- QNetworkReply::NetworkError error,
- QByteArray replyData,
- QList<QNetworkReply::RawHeaderPair> headers
-) {
- if (error != QNetworkReply::NoError) {
- qWarning() << "Reply error:" << error;
-#ifndef NDEBUG
- qDebug() << replyData;
-#endif
- failResult(m_xboxProfileSucceeded);
- return;
- }
-
-#ifndef NDEBUG
- qDebug() << "XBox profile: " << replyData;
-#endif
-
- succeedResult(m_xboxProfileSucceeded);
-}
-
-void AuthContext::succeedResult(bool& flag) {
- m_requestsDone ++;
- flag = true;
- checkResult();
-}
-
-void AuthContext::failResult(bool& flag) {
- m_requestsDone ++;
- flag = false;
- checkResult();
-}
-
-void AuthContext::checkResult() {
- qDebug() << "AuthContext::checkResult called";
- if(m_requestsDone != 2) {
- qDebug() << "Number of ready results:" << m_requestsDone;
- return;
- }
- if(m_mcAuthSucceeded && m_xboxProfileSucceeded) {
- doMinecraftProfile();
- }
- else {
- finishActivity();
- if(stsFailed) {
- if(stsErrors.contains(2148916233)) {
- changeState(
- STATE_FAILED_HARD,
- tr("This Microsoft account does not have an XBox Live profile. Buy the game on %1 first.")
- .arg("<a href=\"https://www.minecraft.net/en-us/store/minecraft-java-edition\">minecraft.net</a>")
- );
- }
- else if (stsErrors.contains(2148916235)){
- // NOTE: this is the Grulovia error
- changeState(
- STATE_FAILED_HARD,
- tr("XBox Live is not available in your country. You've been blocked.")
- );
- }
- else if (stsErrors.contains(2148916238)){
- changeState(
- STATE_FAILED_HARD,
- tr("This Microsoft account is underaged and is not linked to a family.\n\nPlease set up your account according to %1.")
- .arg("<a href=\"https://help.minecraft.net/hc/en-us/articles/4403181904525\">help.minecraft.net</a>")
- );
- }
- else {
- QStringList errorList;
- for(auto & error: stsErrors) {
- errorList.append(QString::number(error));
- }
- changeState(
- STATE_FAILED_HARD,
- tr("XSTS authentication ended with unrecognized error(s):\n\n%1").arg(errorList.join("\n"))
- );
- }
- }
- else {
- changeState(STATE_FAILED_HARD, tr("XBox and/or Mojang authentication steps did not succeed"));
- }
- }
-}
-
-namespace {
-bool parseMinecraftProfile(QByteArray & data, MinecraftProfile &output) {
- qDebug() << "Parsing Minecraft profile...";
-#ifndef NDEBUG
- qDebug() << data;
-#endif
-
- QJsonParseError jsonError;
- QJsonDocument doc = QJsonDocument::fromJson(data, &jsonError);
- if(jsonError.error) {
- qWarning() << "Failed to parse response from user.auth.xboxlive.com as JSON: " << jsonError.errorString();
- return false;
- }
-
- auto obj = doc.object();
- if(!getString(obj.value("id"), output.id)) {
- qWarning() << "Minecraft profile id is not a string";
- return false;
- }
-
- if(!getString(obj.value("name"), output.name)) {
- qWarning() << "Minecraft profile name is not a string";
- return false;
- }
-
- auto skinsArray = obj.value("skins").toArray();
- for(auto skin: skinsArray) {
- auto skinObj = skin.toObject();
- Skin skinOut;
- if(!getString(skinObj.value("id"), skinOut.id)) {
- continue;
- }
- QString state;
- if(!getString(skinObj.value("state"), state)) {
- continue;
- }
- if(state != "ACTIVE") {
- continue;
- }
- if(!getString(skinObj.value("url"), skinOut.url)) {
- continue;
- }
- if(!getString(skinObj.value("variant"), skinOut.variant)) {
- continue;
- }
- // we deal with only the active skin
- output.skin = skinOut;
- break;
- }
- auto capesArray = obj.value("capes").toArray();
-
- QString currentCape;
- for(auto cape: capesArray) {
- auto capeObj = cape.toObject();
- Cape capeOut;
- if(!getString(capeObj.value("id"), capeOut.id)) {
- continue;
- }
- QString state;
- if(!getString(capeObj.value("state"), state)) {
- continue;
- }
- if(state == "ACTIVE") {
- currentCape = capeOut.id;
- }
- if(!getString(capeObj.value("url"), capeOut.url)) {
- continue;
- }
- if(!getString(capeObj.value("alias"), capeOut.alias)) {
- continue;
- }
-
- output.capes[capeOut.id] = capeOut;
- }
- output.currentCape = currentCape;
- output.validity = Katabasis::Validity::Certain;
- return true;
-}
-}
-
-void AuthContext::doMinecraftProfile() {
- setStage(AuthStage::MinecraftProfile);
- changeState(STATE_WORKING, tr("Starting minecraft profile acquisition"));
-
- auto url = QUrl("https://api.minecraftservices.com/minecraft/profile");
- QNetworkRequest request = QNetworkRequest(url);
- request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
- // request.setRawHeader("Accept", "application/json");
- request.setRawHeader("Authorization", QString("Bearer %1").arg(m_data->yggdrasilToken.token).toUtf8());
-
- AuthRequest *requestor = new AuthRequest(this);
- connect(requestor, &AuthRequest::finished, this, &AuthContext::onMinecraftProfileDone);
- requestor->get(request);
-}
-
-void AuthContext::onMinecraftProfileDone(
- QNetworkReply::NetworkError error,
- QByteArray data,
- QList<QNetworkReply::RawHeaderPair> headers
-) {
-#ifndef NDEBUG
- qDebug() << data;
-#endif
- if (error == QNetworkReply::ContentNotFoundError) {
- m_data->minecraftProfile = MinecraftProfile();
- finishActivity();
- changeState(STATE_FAILED_HARD, tr("Account is missing a Minecraft Java profile.\n\nWhile the Microsoft account is valid, it does not own the game.\n\nYou might own Bedrock on this account, but that does not give you access to Java currently."));
- return;
- }
- if (error != QNetworkReply::NoError) {
- finishActivity();
- changeState(STATE_FAILED_HARD, tr("Minecraft Java profile acquisition failed."));
- return;
- }
- if(!parseMinecraftProfile(data, m_data->minecraftProfile)) {
- m_data->minecraftProfile = MinecraftProfile();
- finishActivity();
- changeState(STATE_FAILED_HARD, tr("Minecraft Java profile response could not be parsed"));
- return;
- }
-
- if(m_data->type == AccountType::Mojang) {
- doMigrationEligibilityCheck();
- }
- else {
- doGetSkin();
- }
-}
-
-void AuthContext::doMigrationEligibilityCheck() {
- setStage(AuthStage::MigrationEligibility);
- changeState(STATE_WORKING, tr("Starting check for migration eligibility"));
-
- auto url = QUrl("https://api.minecraftservices.com/rollout/v1/msamigration");
- QNetworkRequest request = QNetworkRequest(url);
- request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
- request.setRawHeader("Authorization", QString("Bearer %1").arg(m_data->yggdrasilToken.token).toUtf8());
-
- AuthRequest *requestor = new AuthRequest(this);
- connect(requestor, &AuthRequest::finished, this, &AuthContext::onMigrationEligibilityCheckDone);
- requestor->get(request);
-}
-
-bool parseRolloutResponse(QByteArray & data, bool& result) {
- qDebug() << "Parsing Rollout response...";
-#ifndef NDEBUG
- qDebug() << data;
-#endif
-
- QJsonParseError jsonError;
- QJsonDocument doc = QJsonDocument::fromJson(data, &jsonError);
- if(jsonError.error) {
- qWarning() << "Failed to parse response from https://api.minecraftservices.com/rollout/v1/msamigration as JSON: " << jsonError.errorString();
- return false;
- }
-
- auto obj = doc.object();
- QString feature;
- if(!getString(obj.value("feature"), feature)) {
- qWarning() << "Rollout feature is not a string";
- return false;
- }
- if(feature != "msamigration") {
- qWarning() << "Rollout feature is not what we expected (msamigration), but is instead \"" << feature << "\"";
- return false;
- }
- if(!getBool(obj.value("rollout"), result)) {
- qWarning() << "Rollout feature is not a string";
- return false;
- }
- return true;
-}
-
-void AuthContext::onMigrationEligibilityCheckDone(
- QNetworkReply::NetworkError error,
- QByteArray data,
- QList<QNetworkReply::RawHeaderPair> headers
-) {
- if (error == QNetworkReply::NoError) {
- parseRolloutResponse(data, m_data->canMigrateToMSA);
- }
- doGetSkin();
-}
-
-void AuthContext::doGetSkin() {
- setStage(AuthStage::Skin);
- changeState(STATE_WORKING, tr("Fetching player skin"));
-
- auto url = QUrl(m_data->minecraftProfile.skin.url);
- QNetworkRequest request = QNetworkRequest(url);
- AuthRequest *requestor = new AuthRequest(this);
- connect(requestor, &AuthRequest::finished, this, &AuthContext::onSkinDone);
- requestor->get(request);
-}
-
-void AuthContext::onSkinDone(
- QNetworkReply::NetworkError error,
- QByteArray data,
- QList<QNetworkReply::RawHeaderPair>
-) {
- if (error == QNetworkReply::NoError) {
- m_data->minecraftProfile.skin.data = data;
- }
- m_data->validity_ = Katabasis::Validity::Certain;
- finishActivity();
- changeState(STATE_SUCCEEDED, tr("Finished all authentication steps"));
-}
-
-void AuthContext::setStage(AuthContext::AuthStage stage) {
- m_stage = stage;
- emit progress((int)m_stage, (int)AuthStage::Complete);
-}
-
-
-QString AuthContext::getStateMessage() const {
- switch (m_accountState)
- {
- case STATE_WORKING:
- switch(m_stage) {
- case AuthStage::Initial: {
- QString loginMessage = tr("Logging in as %1 user");
- if(m_data->type == AccountType::MSA) {
- return loginMessage.arg("Microsoft");
- }
- else {
- return loginMessage.arg("Mojang");
- }
- }
- case AuthStage::UserAuth:
- return tr("Logging in as XBox user");
- case AuthStage::XboxAuth:
- return tr("Logging in with XBox and Mojang services");
- case AuthStage::MinecraftProfile:
- return tr("Getting Minecraft profile");
- case AuthStage::MigrationEligibility:
- return tr("Checking for migration eligibility");
- case AuthStage::Skin:
- return tr("Getting Minecraft skin");
- case AuthStage::Complete:
- return tr("Finished");
- default:
- break;
- }
- default:
- return AccountTask::getStateMessage();
- }
-}
diff --git a/launcher/minecraft/auth/flows/AuthContext.h b/launcher/minecraft/auth/flows/AuthContext.h
deleted file mode 100644
index dc7552ac..00000000
--- a/launcher/minecraft/auth/flows/AuthContext.h
+++ /dev/null
@@ -1,107 +0,0 @@
-#pragma once
-
-#include <QObject>
-#include <QList>
-#include <QVector>
-#include <QSet>
-#include <QNetworkReply>
-#include <QImage>
-
-#include <katabasis/OAuth2.h>
-#include "Yggdrasil.h"
-#include "../AccountData.h"
-#include "../AccountTask.h"
-
-class AuthContext : public AccountTask
-{
- Q_OBJECT
-
-public:
- explicit AuthContext(AccountData * data, QObject *parent = 0);
-
- bool isBusy() {
- return m_activity != Katabasis::Activity::Idle;
- };
- Katabasis::Validity validity() {
- return m_data->validity_;
- };
-
- //bool signOut();
-
- QString getStateMessage() const override;
-
-signals:
- void activityChanged(Katabasis::Activity activity);
-
-private slots:
-// OAuth-specific callbacks
- void onOAuthLinkingSucceeded();
- void onOAuthLinkingFailed();
-
- void onOAuthActivityChanged(Katabasis::Activity activity);
-
-// Yggdrasil specific callbacks
- void onMojangSucceeded();
- void onMojangFailed();
-
-protected:
- void initMSA();
- void initMojang();
-
- void doUserAuth();
- Q_SLOT void onUserAuthDone(QNetworkReply::NetworkError, QByteArray, QList<QNetworkReply::RawHeaderPair>);
-
- void processSTSError(QNetworkReply::NetworkError, QByteArray, QList<QNetworkReply::RawHeaderPair>);
-
- void doSTSAuthMinecraft();
- Q_SLOT void onSTSAuthMinecraftDone(QNetworkReply::NetworkError, QByteArray, QList<QNetworkReply::RawHeaderPair>);
- void doMinecraftAuth();
- Q_SLOT void onMinecraftAuthDone(QNetworkReply::NetworkError, QByteArray, QList<QNetworkReply::RawHeaderPair>);
-
- void doSTSAuthGeneric();
- Q_SLOT void onSTSAuthGenericDone(QNetworkReply::NetworkError, QByteArray, QList<QNetworkReply::RawHeaderPair>);
- void doXBoxProfile();
- Q_SLOT void onXBoxProfileDone(QNetworkReply::NetworkError, QByteArray, QList<QNetworkReply::RawHeaderPair>);
-
- void doMinecraftProfile();
- Q_SLOT void onMinecraftProfileDone(QNetworkReply::NetworkError, QByteArray, QList<QNetworkReply::RawHeaderPair>);
-
- void doMigrationEligibilityCheck();
- Q_SLOT void onMigrationEligibilityCheckDone(QNetworkReply::NetworkError, QByteArray, QList<QNetworkReply::RawHeaderPair>);
-
- void doGetSkin();
- Q_SLOT void onSkinDone(QNetworkReply::NetworkError, QByteArray, QList<QNetworkReply::RawHeaderPair>);
-
- void failResult(bool & flag);
- void succeedResult(bool & flag);
- void checkResult();
-
-protected:
- void beginActivity(Katabasis::Activity activity);
- void finishActivity();
- void clearTokens();
-
-protected:
- Katabasis::OAuth2 *m_oauth2 = nullptr;
- Yggdrasil *m_yggdrasil = nullptr;
-
- int m_requestsDone = 0;
- bool m_xboxProfileSucceeded = false;
- bool m_mcAuthSucceeded = false;
-
- QSet<int64_t> stsErrors;
- bool stsFailed = false;
-
- Katabasis::Activity m_activity = Katabasis::Activity::Idle;
- enum class AuthStage {
- Initial,
- UserAuth,
- XboxAuth,
- MinecraftProfile,
- MigrationEligibility,
- Skin,
- Complete
- } m_stage = AuthStage::Initial;
-
- void setStage(AuthStage stage);
-};
diff --git a/launcher/minecraft/auth/flows/AuthFlow.cpp b/launcher/minecraft/auth/flows/AuthFlow.cpp
new file mode 100644
index 00000000..4f78e8c3
--- /dev/null
+++ b/launcher/minecraft/auth/flows/AuthFlow.cpp
@@ -0,0 +1,71 @@
+#include <QNetworkAccessManager>
+#include <QNetworkRequest>
+#include <QNetworkReply>
+#include <QDebug>
+
+#include "AuthFlow.h"
+#include "katabasis/Globals.h"
+
+#include <Application.h>
+
+AuthFlow::AuthFlow(AccountData * data, QObject *parent) :
+ AccountTask(data, parent)
+{
+}
+
+void AuthFlow::succeed() {
+ m_data->validity_ = Katabasis::Validity::Certain;
+ changeState(
+ AccountTaskState::STATE_SUCCEEDED,
+ tr("Finished all authentication steps")
+ );
+}
+
+void AuthFlow::executeTask() {
+ if(m_currentStep) {
+ return;
+ }
+ changeState(AccountTaskState::STATE_WORKING, tr("Initializing"));
+ nextStep();
+}
+
+void AuthFlow::nextStep() {
+ if(m_steps.size() == 0) {
+ // we got to the end without an incident... assume this is all.
+ m_currentStep.reset();
+ succeed();
+ return;
+ }
+ m_currentStep = m_steps.front();
+ qDebug() << "AuthFlow:" << m_currentStep->describe();
+ m_steps.pop_front();
+ connect(m_currentStep.get(), &AuthStep::finished, this, &AuthFlow::stepFinished);
+ connect(m_currentStep.get(), &AuthStep::showVerificationUriAndCode, this, &AuthFlow::showVerificationUriAndCode);
+ connect(m_currentStep.get(), &AuthStep::hideVerificationUriAndCode, this, &AuthFlow::hideVerificationUriAndCode);
+
+ m_currentStep->perform();
+}
+
+
+QString AuthFlow::getStateMessage() const {
+ switch (m_taskState)
+ {
+ case AccountTaskState::STATE_WORKING: {
+ if(m_currentStep) {
+ return m_currentStep->describe();
+ }
+ else {
+ return tr("Working...");
+ }
+ }
+ default: {
+ return AccountTask::getStateMessage();
+ }
+ }
+}
+
+void AuthFlow::stepFinished(AccountTaskState resultingState, QString message) {
+ if(changeState(resultingState, message)) {
+ nextStep();
+ }
+}
diff --git a/launcher/minecraft/auth/flows/AuthFlow.h b/launcher/minecraft/auth/flows/AuthFlow.h
new file mode 100644
index 00000000..e067cc99
--- /dev/null
+++ b/launcher/minecraft/auth/flows/AuthFlow.h
@@ -0,0 +1,45 @@
+#pragma once
+
+#include <QObject>
+#include <QList>
+#include <QVector>
+#include <QSet>
+#include <QNetworkReply>
+#include <QImage>
+
+#include <katabasis/DeviceFlow.h>
+
+#include "minecraft/auth/Yggdrasil.h"
+#include "minecraft/auth/AccountData.h"
+#include "minecraft/auth/AccountTask.h"
+#include "minecraft/auth/AuthStep.h"
+
+class AuthFlow : public AccountTask
+{
+ Q_OBJECT
+
+public:
+ explicit AuthFlow(AccountData * data, QObject *parent = 0);
+
+ Katabasis::Validity validity() {
+ return m_data->validity_;
+ };
+
+ QString getStateMessage() const override;
+
+ void executeTask() override;
+
+signals:
+ void activityChanged(Katabasis::Activity activity);
+
+private slots:
+ void stepFinished(AccountTaskState resultingState, QString message);
+
+protected:
+ void succeed();
+ void nextStep();
+
+protected:
+ QList<AuthStep::Ptr> m_steps;
+ AuthStep::Ptr m_currentStep;
+};
diff --git a/launcher/minecraft/auth/flows/MSA.cpp b/launcher/minecraft/auth/flows/MSA.cpp
new file mode 100644
index 00000000..416b8f2c
--- /dev/null
+++ b/launcher/minecraft/auth/flows/MSA.cpp
@@ -0,0 +1,37 @@
+#include "MSA.h"
+
+#include "minecraft/auth/steps/MSAStep.h"
+#include "minecraft/auth/steps/XboxUserStep.h"
+#include "minecraft/auth/steps/XboxAuthorizationStep.h"
+#include "minecraft/auth/steps/LauncherLoginStep.h"
+#include "minecraft/auth/steps/XboxProfileStep.h"
+#include "minecraft/auth/steps/EntitlementsStep.h"
+#include "minecraft/auth/steps/MinecraftProfileStep.h"
+#include "minecraft/auth/steps/GetSkinStep.h"
+
+MSASilent::MSASilent(AccountData* data, QObject* parent) : AuthFlow(data, parent) {
+ m_steps.append(new MSAStep(m_data, MSAStep::Action::Refresh));
+ m_steps.append(new XboxUserStep(m_data));
+ m_steps.append(new XboxAuthorizationStep(m_data, &m_data->xboxApiToken, "http://xboxlive.com", "Xbox"));
+ m_steps.append(new XboxAuthorizationStep(m_data, &m_data->mojangservicesToken, "rp://api.minecraftservices.com/", "Mojang"));
+ m_steps.append(new LauncherLoginStep(m_data));
+ m_steps.append(new XboxProfileStep(m_data));
+ m_steps.append(new EntitlementsStep(m_data));
+ m_steps.append(new MinecraftProfileStep(m_data));
+ m_steps.append(new GetSkinStep(m_data));
+}
+
+MSAInteractive::MSAInteractive(
+ AccountData* data,
+ QObject* parent
+) : AuthFlow(data, parent) {
+ m_steps.append(new MSAStep(m_data, MSAStep::Action::Login));
+ m_steps.append(new XboxUserStep(m_data));
+ m_steps.append(new XboxAuthorizationStep(m_data, &m_data->xboxApiToken, "http://xboxlive.com", "Xbox"));
+ m_steps.append(new XboxAuthorizationStep(m_data, &m_data->mojangservicesToken, "rp://api.minecraftservices.com/", "Mojang"));
+ m_steps.append(new LauncherLoginStep(m_data));
+ m_steps.append(new XboxProfileStep(m_data));
+ m_steps.append(new EntitlementsStep(m_data));
+ m_steps.append(new MinecraftProfileStep(m_data));
+ m_steps.append(new GetSkinStep(m_data));
+}
diff --git a/launcher/minecraft/auth/flows/MSA.h b/launcher/minecraft/auth/flows/MSA.h
new file mode 100644
index 00000000..14a4ff43
--- /dev/null
+++ b/launcher/minecraft/auth/flows/MSA.h
@@ -0,0 +1,22 @@
+#pragma once
+#include "AuthFlow.h"
+
+class MSAInteractive : public AuthFlow
+{
+ Q_OBJECT
+public:
+ explicit MSAInteractive(
+ AccountData *data,
+ QObject *parent = 0
+ );
+};
+
+class MSASilent : public AuthFlow
+{
+ Q_OBJECT
+public:
+ explicit MSASilent(
+ AccountData * data,
+ QObject *parent = 0
+ );
+};
diff --git a/launcher/minecraft/auth/flows/MSAInteractive.cpp b/launcher/minecraft/auth/flows/MSAInteractive.cpp
deleted file mode 100644
index 03beb279..00000000
--- a/launcher/minecraft/auth/flows/MSAInteractive.cpp
+++ /dev/null
@@ -1,20 +0,0 @@
-#include "MSAInteractive.h"
-
-MSAInteractive::MSAInteractive(AccountData* data, QObject* parent) : AuthContext(data, parent) {}
-
-void MSAInteractive::executeTask() {
- m_requestsDone = 0;
- m_xboxProfileSucceeded = false;
- m_mcAuthSucceeded = false;
-
- initMSA();
-
- QVariantMap extraOpts;
- extraOpts["prompt"] = "select_account";
- m_oauth2->setExtraRequestParams(extraOpts);
-
- beginActivity(Katabasis::Activity::LoggingIn);
- m_oauth2->unlink();
- *m_data = AccountData();
- m_oauth2->link();
-}
diff --git a/launcher/minecraft/auth/flows/MSAInteractive.h b/launcher/minecraft/auth/flows/MSAInteractive.h
deleted file mode 100644
index 9556f254..00000000
--- a/launcher/minecraft/auth/flows/MSAInteractive.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#pragma once
-#include "AuthContext.h"
-
-class MSAInteractive : public AuthContext
-{
- Q_OBJECT
-public:
- explicit MSAInteractive(AccountData * data, QObject *parent = 0);
- void executeTask() override;
-};
diff --git a/launcher/minecraft/auth/flows/MSASilent.cpp b/launcher/minecraft/auth/flows/MSASilent.cpp
deleted file mode 100644
index 8ce43c1f..00000000
--- a/launcher/minecraft/auth/flows/MSASilent.cpp
+++ /dev/null
@@ -1,16 +0,0 @@
-#include "MSASilent.h"
-
-MSASilent::MSASilent(AccountData* data, QObject* parent) : AuthContext(data, parent) {}
-
-void MSASilent::executeTask() {
- m_requestsDone = 0;
- m_xboxProfileSucceeded = false;
- m_mcAuthSucceeded = false;
-
- initMSA();
-
- beginActivity(Katabasis::Activity::Refreshing);
- if(!m_oauth2->refresh()) {
- finishActivity();
- }
-}
diff --git a/launcher/minecraft/auth/flows/MSASilent.h b/launcher/minecraft/auth/flows/MSASilent.h
deleted file mode 100644
index e1b3d43d..00000000
--- a/launcher/minecraft/auth/flows/MSASilent.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#pragma once
-#include "AuthContext.h"
-
-class MSASilent : public AuthContext
-{
- Q_OBJECT
-public:
- explicit MSASilent(AccountData * data, QObject *parent = 0);
- void executeTask() override;
-};
diff --git a/launcher/minecraft/auth/flows/Mojang.cpp b/launcher/minecraft/auth/flows/Mojang.cpp
new file mode 100644
index 00000000..4661dbe2
--- /dev/null
+++ b/launcher/minecraft/auth/flows/Mojang.cpp
@@ -0,0 +1,27 @@
+#include "Mojang.h"
+
+#include "minecraft/auth/steps/YggdrasilStep.h"
+#include "minecraft/auth/steps/MinecraftProfileStep.h"
+#include "minecraft/auth/steps/MigrationEligibilityStep.h"
+#include "minecraft/auth/steps/GetSkinStep.h"
+
+MojangRefresh::MojangRefresh(
+ AccountData *data,
+ QObject *parent
+) : AuthFlow(data, parent) {
+ m_steps.append(new YggdrasilStep(m_data, QString()));
+ m_steps.append(new MinecraftProfileStep(m_data));
+ m_steps.append(new MigrationEligibilityStep(m_data));
+ m_steps.append(new GetSkinStep(m_data));
+}
+
+MojangLogin::MojangLogin(
+ AccountData *data,
+ QString password,
+ QObject *parent
+): AuthFlow(data, parent), m_password(password) {
+ m_steps.append(new YggdrasilStep(m_data, m_password));
+ m_steps.append(new MinecraftProfileStep(m_data));
+ m_steps.append(new MigrationEligibilityStep(m_data));
+ m_steps.append(new GetSkinStep(m_data));
+}
diff --git a/launcher/minecraft/auth/flows/Mojang.h b/launcher/minecraft/auth/flows/Mojang.h
new file mode 100644
index 00000000..c09c81a8
--- /dev/null
+++ b/launcher/minecraft/auth/flows/Mojang.h
@@ -0,0 +1,26 @@
+#pragma once
+#include "AuthFlow.h"
+
+class MojangRefresh : public AuthFlow
+{
+ Q_OBJECT
+public:
+ explicit MojangRefresh(
+ AccountData *data,
+ QObject *parent = 0
+ );
+};
+
+class MojangLogin : public AuthFlow
+{
+ Q_OBJECT
+public:
+ explicit MojangLogin(
+ AccountData *data,
+ QString password,
+ QObject *parent = 0
+ );
+
+private:
+ QString m_password;
+};
diff --git a/launcher/minecraft/auth/flows/MojangLogin.cpp b/launcher/minecraft/auth/flows/MojangLogin.cpp
deleted file mode 100644
index cca911b5..00000000
--- a/launcher/minecraft/auth/flows/MojangLogin.cpp
+++ /dev/null
@@ -1,14 +0,0 @@
-#include "MojangLogin.h"
-
-MojangLogin::MojangLogin(AccountData* data, QString password, QObject* parent) : AuthContext(data, parent), m_password(password) {}
-
-void MojangLogin::executeTask() {
- m_requestsDone = 0;
- m_xboxProfileSucceeded = false;
- m_mcAuthSucceeded = false;
-
- initMojang();
-
- beginActivity(Katabasis::Activity::LoggingIn);
- m_yggdrasil->login(m_password);
-}
diff --git a/launcher/minecraft/auth/flows/MojangLogin.h b/launcher/minecraft/auth/flows/MojangLogin.h
deleted file mode 100644
index 2e765ae8..00000000
--- a/launcher/minecraft/auth/flows/MojangLogin.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#pragma once
-#include "AuthContext.h"
-
-class MojangLogin : public AuthContext
-{
- Q_OBJECT
-public:
- explicit MojangLogin(AccountData * data, QString password, QObject *parent = 0);
- void executeTask() override;
-
-private:
- QString m_password;
-};
diff --git a/launcher/minecraft/auth/flows/MojangRefresh.cpp b/launcher/minecraft/auth/flows/MojangRefresh.cpp
deleted file mode 100644
index af99175c..00000000
--- a/launcher/minecraft/auth/flows/MojangRefresh.cpp
+++ /dev/null
@@ -1,14 +0,0 @@
-#include "MojangRefresh.h"
-
-MojangRefresh::MojangRefresh(AccountData* data, QObject* parent) : AuthContext(data, parent) {}
-
-void MojangRefresh::executeTask() {
- m_requestsDone = 0;
- m_xboxProfileSucceeded = false;
- m_mcAuthSucceeded = false;
-
- initMojang();
-
- beginActivity(Katabasis::Activity::Refreshing);
- m_yggdrasil->refresh();
-}
diff --git a/launcher/minecraft/auth/flows/MojangRefresh.h b/launcher/minecraft/auth/flows/MojangRefresh.h
deleted file mode 100644
index fb4facd5..00000000
--- a/launcher/minecraft/auth/flows/MojangRefresh.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#pragma once
-#include "AuthContext.h"
-
-class MojangRefresh : public AuthContext
-{
- Q_OBJECT
-public:
- explicit MojangRefresh(AccountData * data, QObject *parent = 0);
- void executeTask() override;
-};
diff --git a/launcher/minecraft/auth/steps/EntitlementsStep.cpp b/launcher/minecraft/auth/steps/EntitlementsStep.cpp
new file mode 100644
index 00000000..f726244f
--- /dev/null
+++ b/launcher/minecraft/auth/steps/EntitlementsStep.cpp
@@ -0,0 +1,53 @@
+#include "EntitlementsStep.h"
+
+#include <QNetworkRequest>
+#include <QUuid>
+
+#include "minecraft/auth/AuthRequest.h"
+#include "minecraft/auth/Parsers.h"
+
+EntitlementsStep::EntitlementsStep(AccountData* data) : AuthStep(data) {}
+
+EntitlementsStep::~EntitlementsStep() noexcept = default;
+
+QString EntitlementsStep::describe() {
+ return tr("Determining game ownership.");
+}
+
+
+void EntitlementsStep::perform() {
+ auto uuid = QUuid::createUuid();
+ m_entitlementsRequestId = uuid.toString().remove('{').remove('}');
+ auto url = "https://api.minecraftservices.com/entitlements/license?requestId=" + m_entitlementsRequestId;
+ QNetworkRequest request = QNetworkRequest(url);
+ request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
+ request.setRawHeader("Accept", "application/json");
+ request.setRawHeader("Authorization", QString("Bearer %1").arg(m_data->yggdrasilToken.token).toUtf8());
+ AuthRequest *requestor = new AuthRequest(this);
+ connect(requestor, &AuthRequest::finished, this, &EntitlementsStep::onRequestDone);
+ requestor->get(request);
+ qDebug() << "Getting entitlements...";
+}
+
+void EntitlementsStep::rehydrate() {
+ // NOOP, for now. We only save bools and there's nothing to check.
+}
+
+void EntitlementsStep::onRequestDone(
+ QNetworkReply::NetworkError error,
+ QByteArray data,
+ QList<QNetworkReply::RawHeaderPair> headers
+) {
+ auto requestor = qobject_cast<AuthRequest *>(QObject::sender());
+ requestor->deleteLater();
+
+#ifndef NDEBUG
+ qDebug() << data;
+#endif
+
+ // TODO: check presence of same entitlementsRequestId?
+ // TODO: validate JWTs?
+ Parsers::parseMinecraftEntitlements(data, m_data->minecraftEntitlement);
+
+ emit finished(AccountTaskState::STATE_WORKING, tr("Got entitlements"));
+}
diff --git a/launcher/minecraft/auth/steps/EntitlementsStep.h b/launcher/minecraft/auth/steps/EntitlementsStep.h
new file mode 100644
index 00000000..9412ae79
--- /dev/null
+++ b/launcher/minecraft/auth/steps/EntitlementsStep.h
@@ -0,0 +1,25 @@
+#pragma once
+#include <QObject>
+
+#include "QObjectPtr.h"
+#include "minecraft/auth/AuthStep.h"
+
+
+class EntitlementsStep : public AuthStep {
+ Q_OBJECT
+
+public:
+ explicit EntitlementsStep(AccountData *data);
+ virtual ~EntitlementsStep() noexcept;
+
+ void perform() override;
+ void rehydrate() override;
+
+ QString describe() override;
+
+private slots:
+ void onRequestDone(QNetworkReply::NetworkError, QByteArray, QList<QNetworkReply::RawHeaderPair>);
+
+private:
+ QString m_entitlementsRequestId;
+};
diff --git a/launcher/minecraft/auth/steps/GetSkinStep.cpp b/launcher/minecraft/auth/steps/GetSkinStep.cpp
new file mode 100644
index 00000000..3521f8dc
--- /dev/null
+++ b/launcher/minecraft/auth/steps/GetSkinStep.cpp
@@ -0,0 +1,43 @@
+
+#include "GetSkinStep.h"
+
+#include <QNetworkRequest>
+
+#include "minecraft/auth/AuthRequest.h"
+#include "minecraft/auth/Parsers.h"
+
+GetSkinStep::GetSkinStep(AccountData* data) : AuthStep(data) {
+
+}
+
+GetSkinStep::~GetSkinStep() noexcept = default;
+
+QString GetSkinStep::describe() {
+ return tr("Getting skin.");
+}
+
+void GetSkinStep::perform() {
+ auto url = QUrl(m_data->minecraftProfile.skin.url);
+ QNetworkRequest request = QNetworkRequest(url);
+ AuthRequest *requestor = new AuthRequest(this);
+ connect(requestor, &AuthRequest::finished, this, &GetSkinStep::onRequestDone);
+ requestor->get(request);
+}
+
+void GetSkinStep::rehydrate() {
+ // NOOP, for now.
+}
+
+void GetSkinStep::onRequestDone(
+ QNetworkReply::NetworkError error,
+ QByteArray data,
+ QList<QNetworkReply::RawHeaderPair> headers
+) {
+ auto requestor = qobject_cast<AuthRequest *>(QObject::sender());
+ requestor->deleteLater();
+
+ if (error == QNetworkReply::NoError) {
+ m_data->minecraftProfile.skin.data = data;
+ }
+ emit finished(AccountTaskState::STATE_SUCCEEDED, tr("Got skin"));
+}
diff --git a/launcher/minecraft/auth/steps/GetSkinStep.h b/launcher/minecraft/auth/steps/GetSkinStep.h
new file mode 100644
index 00000000..6b97371e
--- /dev/null
+++ b/launcher/minecraft/auth/steps/GetSkinStep.h
@@ -0,0 +1,22 @@
+#pragma once
+#include <QObject>
+
+#include "QObjectPtr.h"
+#include "minecraft/auth/AuthStep.h"
+
+
+class GetSkinStep : public AuthStep {
+ Q_OBJECT
+
+public:
+ explicit GetSkinStep(AccountData *data);
+ virtual ~GetSkinStep() noexcept;
+
+ void perform() override;
+ void rehydrate() override;
+
+ QString describe() override;
+
+private slots:
+ void onRequestDone(QNetworkReply::NetworkError, QByteArray, QList<QNetworkReply::RawHeaderPair>);
+};
diff --git a/launcher/minecraft/auth/steps/LauncherLoginStep.cpp b/launcher/minecraft/auth/steps/LauncherLoginStep.cpp
new file mode 100644
index 00000000..c978bd07
--- /dev/null
+++ b/launcher/minecraft/auth/steps/LauncherLoginStep.cpp
@@ -0,0 +1,78 @@
+#include "LauncherLoginStep.h"
+
+#include <QNetworkRequest>
+
+#include "minecraft/auth/AuthRequest.h"
+#include "minecraft/auth/Parsers.h"
+#include "minecraft/auth/AccountTask.h"
+
+LauncherLoginStep::LauncherLoginStep(AccountData* data) : AuthStep(data) {
+
+}
+
+LauncherLoginStep::~LauncherLoginStep() noexcept = default;
+
+QString LauncherLoginStep::describe() {
+ return tr("Accessing Mojang services.");
+}
+
+void LauncherLoginStep::perform() {
+ auto requestURL = "https://api.minecraftservices.com/launcher/login";
+ auto uhs = m_data->mojangservicesToken.extra["uhs"].toString();
+ auto xToken = m_data->mojangservicesToken.token;
+
+ QString mc_auth_template = R"XXX(
+{
+ "xtoken": "XBL3.0 x=%1;%2",
+ "platform": "PC_LAUNCHER"
+}
+)XXX";
+ auto requestBody = mc_auth_template.arg(uhs, xToken);
+
+ QNetworkRequest request = QNetworkRequest(QUrl(requestURL));
+ request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
+ request.setRawHeader("Accept", "application/json");
+ AuthRequest *requestor = new AuthRequest(this);
+ connect(requestor, &AuthRequest::finished, this, &LauncherLoginStep::onRequestDone);
+ requestor->post(request, requestBody.toUtf8());
+ qDebug() << "Getting Minecraft access token...";
+}
+
+void LauncherLoginStep::rehydrate() {
+ // TODO: check the token validity
+}
+
+void LauncherLoginStep::onRequestDone(
+ QNetworkReply::NetworkError error,
+ QByteArray data,
+ QList<QNetworkReply::RawHeaderPair> headers
+) {
+ auto requestor = qobject_cast<AuthRequest *>(QObject::sender());
+ requestor->deleteLater();
+
+ qDebug() << data;
+ if (error != QNetworkReply::NoError) {
+ qWarning() << "Reply error:" << error;
+#ifndef NDEBUG
+ qDebug() << data;
+#endif
+ emit finished(
+ AccountTaskState::STATE_FAILED_SOFT,
+ tr("Failed to get Minecraft access token: %1").arg(requestor->errorString_)
+ );
+ return;
+ }
+
+ if(!Parsers::parseMojangResponse(data, m_data->yggdrasilToken)) {
+ qWarning() << "Could not parse login_with_xbox response...";
+#ifndef NDEBUG
+ qDebug() << data;
+#endif
+ emit finished(
+ AccountTaskState::STATE_FAILED_SOFT,
+ tr("Failed to parse the Minecraft access token response.")
+ );
+ return;
+ }
+ emit finished(AccountTaskState::STATE_WORKING, tr(""));
+}
diff --git a/launcher/minecraft/auth/steps/LauncherLoginStep.h b/launcher/minecraft/auth/steps/LauncherLoginStep.h
new file mode 100644
index 00000000..e06a306f
--- /dev/null
+++ b/launcher/minecraft/auth/steps/LauncherLoginStep.h
@@ -0,0 +1,22 @@
+#pragma once
+#include <QObject>
+
+#include "QObjectPtr.h"
+#include "minecraft/auth/AuthStep.h"
+
+
+class LauncherLoginStep : public AuthStep {
+ Q_OBJECT
+
+public:
+ explicit LauncherLoginStep(AccountData *data);
+ virtual ~LauncherLoginStep() noexcept;
+
+ void perform() override;
+ void rehydrate() override;
+
+ QString describe() override;
+
+private slots:
+ void onRequestDone(QNetworkReply::NetworkError, QByteArray, QList<QNetworkReply::RawHeaderPair>);
+};
diff --git a/launcher/minecraft/auth/steps/MSAStep.cpp b/launcher/minecraft/auth/steps/MSAStep.cpp
new file mode 100644
index 00000000..be711f7e
--- /dev/null
+++ b/launcher/minecraft/auth/steps/MSAStep.cpp
@@ -0,0 +1,111 @@
+#include "MSAStep.h"
+
+#include <QNetworkRequest>
+
+#include "minecraft/auth/AuthRequest.h"
+#include "minecraft/auth/Parsers.h"
+
+#include "Application.h"
+
+using OAuth2 = Katabasis::DeviceFlow;
+using Activity = Katabasis::Activity;
+
+MSAStep::MSAStep(AccountData* data, Action action) : AuthStep(data), m_action(action) {
+ OAuth2::Options opts;
+ opts.scope = "XboxLive.signin offline_access";
+ opts.clientIdentifier = APPLICATION->msaClientId();
+ opts.authorizationUrl = "https://login.microsoftonline.com/consumers/oauth2/v2.0/devicecode";
+ opts.accessTokenUrl = "https://login.microsoftonline.com/consumers/oauth2/v2.0/token";
+
+ // FIXME: OAuth2 is not aware of our fancy shared pointers
+ m_oauth2 = new OAuth2(opts, m_data->msaToken, this, APPLICATION->network().get());
+
+ connect(m_oauth2, &OAuth2::activityChanged, this, &MSAStep::onOAuthActivityChanged);
+ connect(m_oauth2, &OAuth2::showVerificationUriAndCode, this, &MSAStep::showVerificationUriAndCode);
+}
+
+MSAStep::~MSAStep() noexcept = default;
+
+QString MSAStep::describe() {
+ return tr("Logging in with Microsoft account.");
+}
+
+
+void MSAStep::rehydrate() {
+ switch(m_action) {
+ case Refresh: {
+ // TODO: check the tokens and see if they are old (older than a day)
+ return;
+ }
+ case Login: {
+ // NOOP
+ return;
+ }
+ }
+}
+
+void MSAStep::perform() {
+ switch(m_action) {
+ case Refresh: {
+ m_oauth2->refresh();
+ return;
+ }
+ case Login: {
+ QVariantMap extraOpts;
+ extraOpts["prompt"] = "select_account";
+ m_oauth2->setExtraRequestParams(extraOpts);
+
+ *m_data = AccountData();
+ m_oauth2->login();
+ return;
+ }
+ }
+}
+
+void MSAStep::onOAuthActivityChanged(Katabasis::Activity activity) {
+ switch(activity) {
+ case Katabasis::Activity::Idle:
+ case Katabasis::Activity::LoggingIn:
+ case Katabasis::Activity::Refreshing:
+ case Katabasis::Activity::LoggingOut: {
+ // We asked it to do something, it's doing it. Nothing to act upon.
+ return;
+ }
+ case Katabasis::Activity::Succeeded: {
+ // Succeeded or did not invalidate tokens
+ emit hideVerificationUriAndCode();
+ QVariantMap extraTokens = m_oauth2->extraTokens();
+#ifndef NDEBUG
+ if (!extraTokens.isEmpty()) {
+ qDebug() << "Extra tokens in response:";
+ foreach (QString key, extraTokens.keys()) {
+ qDebug() << "\t" << key << ":" << extraTokens.value(key);
+ }
+ }
+#endif
+ emit finished(AccountTaskState::STATE_WORKING, tr("Got "));
+ return;
+ }
+ case Katabasis::Activity::FailedSoft: {
+ // NOTE: soft error in the first step means 'offline'
+ emit hideVerificationUriAndCode();
+ emit finished(AccountTaskState::STATE_OFFLINE, tr("Microsoft user authentication ended with a network error."));
+ return;
+ }
+ case Katabasis::Activity::FailedGone: {
+ emit hideVerificationUriAndCode();
+ emit finished(AccountTaskState::STATE_FAILED_GONE, tr("Microsoft user authentication failed - user no longer exists."));
+ return;
+ }
+ case Katabasis::Activity::FailedHard: {
+ emit hideVerificationUriAndCode();
+ emit finished(AccountTaskState::STATE_FAILED_HARD, tr("Microsoft user authentication failed."));
+ return;
+ }
+ default: {
+ emit hideVerificationUriAndCode();
+ emit finished(AccountTaskState::STATE_FAILED_HARD, tr("Microsoft user authentication completed with an unrecognized result."));
+ return;
+ }
+ }
+}
diff --git a/launcher/minecraft/auth/steps/MSAStep.h b/launcher/minecraft/auth/steps/MSAStep.h
new file mode 100644
index 00000000..49ba3542
--- /dev/null
+++ b/launcher/minecraft/auth/steps/MSAStep.h
@@ -0,0 +1,32 @@
+
+#pragma once
+#include <QObject>
+
+#include "QObjectPtr.h"
+#include "minecraft/auth/AuthStep.h"
+
+#include <katabasis/DeviceFlow.h>
+
+class MSAStep : public AuthStep {
+ Q_OBJECT
+public:
+ enum Action {
+ Refresh,
+ Login
+ };
+public:
+ explicit MSAStep(AccountData *data, Action action);
+ virtual ~MSAStep() noexcept;
+
+ void perform() override;
+ void rehydrate() override;
+
+ QString describe() override;
+
+private slots:
+ void onOAuthActivityChanged(Katabasis::Activity activity);
+
+private:
+ Katabasis::DeviceFlow *m_oauth2 = nullptr;
+ Action m_action;
+};
diff --git a/launcher/minecraft/auth/steps/MigrationEligibilityStep.cpp b/launcher/minecraft/auth/steps/MigrationEligibilityStep.cpp
new file mode 100644
index 00000000..f5b5637a
--- /dev/null
+++ b/launcher/minecraft/auth/steps/MigrationEligibilityStep.cpp
@@ -0,0 +1,45 @@
+#include "MigrationEligibilityStep.h"
+
+#include <QNetworkRequest>
+
+#include "minecraft/auth/AuthRequest.h"
+#include "minecraft/auth/Parsers.h"
+
+MigrationEligibilityStep::MigrationEligibilityStep(AccountData* data) : AuthStep(data) {
+
+}
+
+MigrationEligibilityStep::~MigrationEligibilityStep() noexcept = default;
+
+QString MigrationEligibilityStep::describe() {
+ return tr("Checking for migration eligibility.");
+}
+
+void MigrationEligibilityStep::perform() {
+ auto url = QUrl("https://api.minecraftservices.com/rollout/v1/msamigration");
+ QNetworkRequest request = QNetworkRequest(url);
+ request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
+ request.setRawHeader("Authorization", QString("Bearer %1").arg(m_data->yggdrasilToken.token).toUtf8());
+
+ AuthRequest *requestor = new AuthRequest(this);
+ connect(requestor, &AuthRequest::finished, this, &MigrationEligibilityStep::onRequestDone);
+ requestor->get(request);
+}
+
+void MigrationEligibilityStep::rehydrate() {
+ // NOOP, for now. We only save bools and there's nothing to check.
+}
+
+void MigrationEligibilityStep::onRequestDone(
+ QNetworkReply::NetworkError error,
+ QByteArray data,
+ QList<QNetworkReply::RawHeaderPair> headers
+) {
+ auto requestor = qobject_cast<AuthRequest *>(QObject::sender());
+ requestor->deleteLater();
+
+ if (error == QNetworkReply::NoError) {
+ Parsers::parseRolloutResponse(data, m_data->canMigrateToMSA);
+ }
+ emit finished(AccountTaskState::STATE_WORKING, tr("Got migration flags"));
+}
diff --git a/launcher/minecraft/auth/steps/MigrationEligibilityStep.h b/launcher/minecraft/auth/steps/MigrationEligibilityStep.h
new file mode 100644
index 00000000..b1bf9cbf
--- /dev/null
+++ b/launcher/minecraft/auth/steps/MigrationEligibilityStep.h
@@ -0,0 +1,22 @@
+#pragma once
+#include <QObject>
+
+#include "QObjectPtr.h"
+#include "minecraft/auth/AuthStep.h"
+
+
+class MigrationEligibilityStep : public AuthStep {
+ Q_OBJECT
+
+public:
+ explicit MigrationEligibilityStep(AccountData *data);
+ virtual ~MigrationEligibilityStep() noexcept;
+
+ void perform() override;
+ void rehydrate() override;
+
+ QString describe() override;
+
+private slots:
+ void onRequestDone(QNetworkReply::NetworkError, QByteArray, QList<QNetworkReply::RawHeaderPair>);
+};
diff --git a/launcher/minecraft/auth/steps/MinecraftProfileStep.cpp b/launcher/minecraft/auth/steps/MinecraftProfileStep.cpp
new file mode 100644
index 00000000..9fef99b0
--- /dev/null
+++ b/launcher/minecraft/auth/steps/MinecraftProfileStep.cpp
@@ -0,0 +1,83 @@
+#include "MinecraftProfileStep.h"
+
+#include <QNetworkRequest>
+
+#include "minecraft/auth/AuthRequest.h"
+#include "minecraft/auth/Parsers.h"
+
+MinecraftProfileStep::MinecraftProfileStep(AccountData* data) : AuthStep(data) {
+
+}
+
+MinecraftProfileStep::~MinecraftProfileStep() noexcept = default;
+
+QString MinecraftProfileStep::describe() {
+ return tr("Fetching the Minecraft profile.");
+}
+
+
+void MinecraftProfileStep::perform() {
+ auto url = QUrl("https://api.minecraftservices.com/minecraft/profile");
+ QNetworkRequest request = QNetworkRequest(url);
+ request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
+ request.setRawHeader("Authorization", QString("Bearer %1").arg(m_data->yggdrasilToken.token).toUtf8());
+
+ AuthRequest *requestor = new AuthRequest(this);
+ connect(requestor, &AuthRequest::finished, this, &MinecraftProfileStep::onRequestDone);
+ requestor->get(request);
+}
+
+void MinecraftProfileStep::rehydrate() {
+ // NOOP, for now. We only save bools and there's nothing to check.
+}
+
+void MinecraftProfileStep::onRequestDone(
+ QNetworkReply::NetworkError error,
+ QByteArray data,
+ QList<QNetworkReply::RawHeaderPair> headers
+) {
+ auto requestor = qobject_cast<AuthRequest *>(QObject::sender());
+ requestor->deleteLater();
+
+#ifndef NDEBUG
+ qDebug() << data;
+#endif
+ if (error == QNetworkReply::ContentNotFoundError) {
+ // NOTE: Succeed even if we do not have a profile. This is a valid account state.
+ if(m_data->type == AccountType::Mojang) {
+ m_data->minecraftEntitlement.canPlayMinecraft = false;
+ m_data->minecraftEntitlement.ownsMinecraft = false;
+ }
+ m_data->minecraftProfile = MinecraftProfile();
+ emit finished(
+ AccountTaskState::STATE_SUCCEEDED,
+ tr("Account has no Minecraft profile.")
+ );
+ return;
+ }
+ if (error != QNetworkReply::NoError) {
+ emit finished(
+ AccountTaskState::STATE_FAILED_SOFT,
+ tr("Minecraft Java profile acquisition failed.")
+ );
+ return;
+ }
+ if(!Parsers::parseMinecraftProfile(data, m_data->minecraftProfile)) {
+ m_data->minecraftProfile = MinecraftProfile();
+ emit finished(
+ AccountTaskState::STATE_FAILED_SOFT,
+ tr("Minecraft Java profile response could not be parsed")
+ );
+ return;
+ }
+
+ if(m_data->type == AccountType::Mojang) {
+ auto validProfile = m_data->minecraftProfile.validity == Katabasis::Validity::Certain;
+ m_data->minecraftEntitlement.canPlayMinecraft = validProfile;
+ m_data->minecraftEntitlement.ownsMinecraft = validProfile;
+ }
+ emit finished(
+ AccountTaskState::STATE_WORKING,
+ tr("Minecraft Java profile acquisition succeeded.")
+ );
+}
diff --git a/launcher/minecraft/auth/steps/MinecraftProfileStep.h b/launcher/minecraft/auth/steps/MinecraftProfileStep.h
new file mode 100644
index 00000000..8ef3395c
--- /dev/null
+++ b/launcher/minecraft/auth/steps/MinecraftProfileStep.h
@@ -0,0 +1,22 @@
+#pragma once
+#include <QObject>
+
+#include "QObjectPtr.h"
+#include "minecraft/auth/AuthStep.h"
+
+
+class MinecraftProfileStep : public AuthStep {
+ Q_OBJECT
+
+public:
+ explicit MinecraftProfileStep(AccountData *data);
+ virtual ~MinecraftProfileStep() noexcept;
+
+ void perform() override;
+ void rehydrate() override;
+
+ QString describe() override;
+
+private slots:
+ void onRequestDone(QNetworkReply::NetworkError, QByteArray, QList<QNetworkReply::RawHeaderPair>);
+};
diff --git a/launcher/minecraft/auth/steps/XboxAuthorizationStep.cpp b/launcher/minecraft/auth/steps/XboxAuthorizationStep.cpp
new file mode 100644
index 00000000..07eeb7dc
--- /dev/null
+++ b/launcher/minecraft/auth/steps/XboxAuthorizationStep.cpp
@@ -0,0 +1,158 @@
+#include "XboxAuthorizationStep.h"
+
+#include <QNetworkRequest>
+#include <QJsonParseError>
+#include <QJsonDocument>
+
+#include "minecraft/auth/AuthRequest.h"
+#include "minecraft/auth/Parsers.h"
+
+XboxAuthorizationStep::XboxAuthorizationStep(AccountData* data, Katabasis::Token *token, QString relyingParty, QString authorizationKind):
+ AuthStep(data),
+ m_token(token),
+ m_relyingParty(relyingParty),
+ m_authorizationKind(authorizationKind)
+{
+}
+
+XboxAuthorizationStep::~XboxAuthorizationStep() noexcept = default;
+
+QString XboxAuthorizationStep::describe() {
+ return tr("Getting authorization to access %1 services.").arg(m_authorizationKind);
+}
+
+void XboxAuthorizationStep::rehydrate() {
+ // FIXME: check if the tokens are good?
+}
+
+void XboxAuthorizationStep::perform() {
+ QString xbox_auth_template = R"XXX(
+{
+ "Properties": {
+ "SandboxId": "RETAIL",
+ "UserTokens": [
+ "%1"
+ ]
+ },
+ "RelyingParty": "%2",
+ "TokenType": "JWT"
+}
+)XXX";
+ auto xbox_auth_data = xbox_auth_template.arg(m_data->userToken.token, m_relyingParty);
+// http://xboxlive.com
+ QNetworkRequest request = QNetworkRequest(QUrl("https://xsts.auth.xboxlive.com/xsts/authorize"));
+ request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
+ request.setRawHeader("Accept", "application/json");
+ AuthRequest *requestor = new AuthRequest(this);
+ connect(requestor, &AuthRequest::finished, this, &XboxAuthorizationStep::onRequestDone);
+ requestor->post(request, xbox_auth_data.toUtf8());
+ qDebug() << "Getting authorization token for " << m_relyingParty;
+}
+
+void XboxAuthorizationStep::onRequestDone(
+ QNetworkReply::NetworkError error,
+ QByteArray data,
+ QList<QNetworkReply::RawHeaderPair> headers
+) {
+ auto requestor = qobject_cast<AuthRequest *>(QObject::sender());
+ requestor->deleteLater();
+
+#ifndef NDEBUG
+ qDebug() << data;
+#endif
+ if (error != QNetworkReply::NoError) {
+ qWarning() << "Reply error:" << error;
+ if(!processSTSError(error, data, headers)) {
+ emit finished(
+ AccountTaskState::STATE_FAILED_SOFT,
+ tr("Failed to get authorization for %1 services. Error %1.").arg(m_authorizationKind, error)
+ );
+ }
+ return;
+ }
+
+ Katabasis::Token temp;
+ if(!Parsers::parseXTokenResponse(data, temp, m_authorizationKind)) {
+ emit finished(
+ AccountTaskState::STATE_FAILED_SOFT,
+ tr("Could not parse authorization response for access to %1 services.").arg(m_authorizationKind)
+ );
+ return;
+ }
+
+ if(temp.extra["uhs"] != m_data->userToken.extra["uhs"]) {
+ emit finished(
+ AccountTaskState::STATE_FAILED_SOFT,
+ tr("Server has changed %1 authorization user hash in the reply. Something is wrong.").arg(m_authorizationKind)
+ );
+ return;
+ }
+ auto & token = *m_token;
+ token = temp;
+
+ emit finished(AccountTaskState::STATE_WORKING, tr("Got authorization to access %1").arg(m_relyingParty));
+}
+
+
+bool XboxAuthorizationStep::processSTSError(
+ QNetworkReply::NetworkError error,
+ QByteArray data,
+ QList<QNetworkReply::RawHeaderPair> headers
+) {
+ if(error == QNetworkReply::AuthenticationRequiredError) {
+ QJsonParseError jsonError;
+ QJsonDocument doc = QJsonDocument::fromJson(data, &jsonError);
+ if(jsonError.error) {
+ qWarning() << "Cannot parse error XSTS response as JSON: " << jsonError.errorString();
+ emit finished(
+ AccountTaskState::STATE_FAILED_SOFT,
+ tr("Cannot parse %1 authorization error response as JSON: %2").arg(m_authorizationKind, jsonError.errorString())
+ );
+ return true;
+ }
+
+ int64_t errorCode = -1;
+ auto obj = doc.object();
+ if(!Parsers::getNumber(obj.value("XErr"), errorCode)) {
+ emit finished(
+ AccountTaskState::STATE_FAILED_SOFT,
+ tr("XErr element is missing from %1 authorization error response.").arg(m_authorizationKind)
+ );
+ return true;
+ }
+ switch(errorCode) {
+ case 2148916233:{
+ emit finished(
+ AccountTaskState::STATE_FAILED_SOFT,
+ tr("This Microsoft account does not have an XBox Live profile. Buy the game on %1 first.")
+ .arg("<a href=\"https://www.minecraft.net/en-us/store/minecraft-java-edition\">minecraft.net</a>")
+ );
+ return true;
+ }
+ case 2148916235: {
+ // NOTE: this is the Grulovia error
+ emit finished(
+ AccountTaskState::STATE_FAILED_SOFT,
+ tr("XBox Live is not available in your country. You've been blocked.")
+ );
+ return true;
+ }
+ case 2148916238: {
+ emit finished(
+ AccountTaskState::STATE_FAILED_SOFT,
+ tr("This Microsoft account is underaged and is not linked to a family.\n\nPlease set up your account according to %1.")
+ .arg("<a href=\"https://help.minecraft.net/hc/en-us/articles/4403181904525\">help.minecraft.net</a>")
+ );
+ return true;
+ }
+ default: {
+ emit finished(
+ AccountTaskState::STATE_FAILED_SOFT,
+ tr("XSTS authentication ended with unrecognized error(s):\n\n%1").arg(errorCode)
+ );
+ return true;
+ }
+ }
+ }
+ return false;
+}
diff --git a/launcher/minecraft/auth/steps/XboxAuthorizationStep.h b/launcher/minecraft/auth/steps/XboxAuthorizationStep.h
new file mode 100644
index 00000000..31e43bf0
--- /dev/null
+++ b/launcher/minecraft/auth/steps/XboxAuthorizationStep.h
@@ -0,0 +1,34 @@
+#pragma once
+#include <QObject>
+
+#include "QObjectPtr.h"
+#include "minecraft/auth/AuthStep.h"
+
+
+class XboxAuthorizationStep : public AuthStep {
+ Q_OBJECT
+
+public:
+ explicit XboxAuthorizationStep(AccountData *data, Katabasis::Token *token, QString relyingParty, QString authorizationKind);
+ virtual ~XboxAuthorizationStep() noexcept;
+
+ void perform() override;
+ void rehydrate() override;
+
+ QString describe() override;
+
+private:
+ bool processSTSError(
+ QNetworkReply::NetworkError error,
+ QByteArray data,
+ QList<QNetworkReply::RawHeaderPair> headers
+ );
+
+private slots:
+ void onRequestDone(QNetworkReply::NetworkError, QByteArray, QList<QNetworkReply::RawHeaderPair>);
+
+private:
+ Katabasis::Token *m_token;
+ QString m_relyingParty;
+ QString m_authorizationKind;
+};
diff --git a/launcher/minecraft/auth/steps/XboxProfileStep.cpp b/launcher/minecraft/auth/steps/XboxProfileStep.cpp
new file mode 100644
index 00000000..9f50138e
--- /dev/null
+++ b/launcher/minecraft/auth/steps/XboxProfileStep.cpp
@@ -0,0 +1,73 @@
+#include "XboxProfileStep.h"
+
+#include <QNetworkRequest>
+#include <QUrlQuery>
+
+
+#include "minecraft/auth/AuthRequest.h"
+#include "minecraft/auth/Parsers.h"
+
+XboxProfileStep::XboxProfileStep(AccountData* data) : AuthStep(data) {
+
+}
+
+XboxProfileStep::~XboxProfileStep() noexcept = default;
+
+QString XboxProfileStep::describe() {
+ return tr("Fetching Xbox profile.");
+}
+
+void XboxProfileStep::rehydrate() {
+ // NOOP, for now. We only save bools and there's nothing to check.
+}
+
+void XboxProfileStep::perform() {
+ auto url = QUrl("https://profile.xboxlive.com/users/me/profile/settings");
+ QUrlQuery q;
+ q.addQueryItem(
+ "settings",
+ "GameDisplayName,AppDisplayName,AppDisplayPicRaw,GameDisplayPicRaw,"
+ "PublicGamerpic,ShowUserAsAvatar,Gamerscore,Gamertag,ModernGamertag,ModernGamertagSuffix,"
+ "UniqueModernGamertag,AccountTier,TenureLevel,XboxOneRep,"
+ "PreferredColor,Location,Bio,Watermarks,"
+ "RealName,RealNameOverride,IsQuarantined"
+ );
+ url.setQuery(q);
+
+ QNetworkRequest request = QNetworkRequest(url);
+ request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
+ request.setRawHeader("Accept", "application/json");
+ request.setRawHeader("x-xbl-contract-version", "3");
+ request.setRawHeader("Authorization", QString("XBL3.0 x=%1;%2").arg(m_data->userToken.extra["uhs"].toString(), m_data->xboxApiToken.token).toUtf8());
+ AuthRequest *requestor = new AuthRequest(this);
+ connect(requestor, &AuthRequest::finished, this, &XboxProfileStep::onRequestDone);
+ requestor->get(request);
+ qDebug() << "Getting Xbox profile...";
+}
+
+void XboxProfileStep::onRequestDone(
+ QNetworkReply::NetworkError error,
+ QByteArray data,
+ QList<QNetworkReply::RawHeaderPair> headers
+) {
+ auto requestor = qobject_cast<AuthRequest *>(QObject::sender());
+ requestor->deleteLater();
+
+ if (error != QNetworkReply::NoError) {
+ qWarning() << "Reply error:" << error;
+#ifndef NDEBUG
+ qDebug() << data;
+#endif
+ finished(
+ AccountTaskState::STATE_FAILED_SOFT,
+ tr("Failed to retrieve the Xbox profile.")
+ );
+ return;
+ }
+
+#ifndef NDEBUG
+ qDebug() << "XBox profile: " << data;
+#endif
+
+ emit finished(AccountTaskState::STATE_WORKING, tr("Got Xbox profile"));
+}
diff --git a/launcher/minecraft/auth/steps/XboxProfileStep.h b/launcher/minecraft/auth/steps/XboxProfileStep.h
new file mode 100644
index 00000000..7a0c5873
--- /dev/null
+++ b/launcher/minecraft/auth/steps/XboxProfileStep.h
@@ -0,0 +1,22 @@
+#pragma once
+#include <QObject>
+
+#include "QObjectPtr.h"
+#include "minecraft/auth/AuthStep.h"
+
+
+class XboxProfileStep : public AuthStep {
+ Q_OBJECT
+
+public:
+ explicit XboxProfileStep(AccountData *data);
+ virtual ~XboxProfileStep() noexcept;
+
+ void perform() override;
+ void rehydrate() override;
+
+ QString describe() override;
+
+private slots:
+ void onRequestDone(QNetworkReply::NetworkError, QByteArray, QList<QNetworkReply::RawHeaderPair>);
+};
diff --git a/launcher/minecraft/auth/steps/XboxUserStep.cpp b/launcher/minecraft/auth/steps/XboxUserStep.cpp
new file mode 100644
index 00000000..a38a28e4
--- /dev/null
+++ b/launcher/minecraft/auth/steps/XboxUserStep.cpp
@@ -0,0 +1,68 @@
+#include "XboxUserStep.h"
+
+#include <QNetworkRequest>
+
+#include "minecraft/auth/AuthRequest.h"
+#include "minecraft/auth/Parsers.h"
+
+XboxUserStep::XboxUserStep(AccountData* data) : AuthStep(data) {
+
+}
+
+XboxUserStep::~XboxUserStep() noexcept = default;
+
+QString XboxUserStep::describe() {
+ return tr("Logging in as an Xbox user.");
+}
+
+
+void XboxUserStep::rehydrate() {
+ // NOOP, for now. We only save bools and there's nothing to check.
+}
+
+void XboxUserStep::perform() {
+ QString xbox_auth_template = R"XXX(
+{
+ "Properties": {
+ "AuthMethod": "RPS",
+ "SiteName": "user.auth.xboxlive.com",
+ "RpsTicket": "d=%1"
+ },
+ "RelyingParty": "http://auth.xboxlive.com",
+ "TokenType": "JWT"
+}
+)XXX";
+ auto xbox_auth_data = xbox_auth_template.arg(m_data->msaToken.token);
+
+ QNetworkRequest request = QNetworkRequest(QUrl("https://user.auth.xboxlive.com/user/authenticate"));
+ request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
+ request.setRawHeader("Accept", "application/json");
+ auto *requestor = new AuthRequest(this);
+ connect(requestor, &AuthRequest::finished, this, &XboxUserStep::onRequestDone);
+ requestor->post(request, xbox_auth_data.toUtf8());
+ qDebug() << "First layer of XBox auth ... commencing.";
+}
+
+void XboxUserStep::onRequestDone(
+ QNetworkReply::NetworkError error,
+ QByteArray data,
+ QList<QNetworkReply::RawHeaderPair> headers
+) {
+ auto requestor = qobject_cast<AuthRequest *>(QObject::sender());
+ requestor->deleteLater();
+
+ if (error != QNetworkReply::NoError) {
+ qWarning() << "Reply error:" << error;
+ emit finished(AccountTaskState::STATE_FAILED_SOFT, tr("XBox user authentication failed."));
+ return;
+ }
+
+ Katabasis::Token temp;
+ if(!Parsers::parseXTokenResponse(data, temp, "UToken")) {
+ qWarning() << "Could not parse user authentication response...";
+ emit finished(AccountTaskState::STATE_FAILED_SOFT, tr("XBox user authentication response could not be understood."));
+ return;
+ }
+ m_data->userToken = temp;
+ emit finished(AccountTaskState::STATE_WORKING, tr("Got Xbox user token"));
+}
diff --git a/launcher/minecraft/auth/steps/XboxUserStep.h b/launcher/minecraft/auth/steps/XboxUserStep.h
new file mode 100644
index 00000000..83e9405f
--- /dev/null
+++ b/launcher/minecraft/auth/steps/XboxUserStep.h
@@ -0,0 +1,22 @@
+#pragma once
+#include <QObject>
+
+#include "QObjectPtr.h"
+#include "minecraft/auth/AuthStep.h"
+
+
+class XboxUserStep : public AuthStep {
+ Q_OBJECT
+
+public:
+ explicit XboxUserStep(AccountData *data);
+ virtual ~XboxUserStep() noexcept;
+
+ void perform() override;
+ void rehydrate() override;
+
+ QString describe() override;
+
+private slots:
+ void onRequestDone(QNetworkReply::NetworkError, QByteArray, QList<QNetworkReply::RawHeaderPair>);
+};
diff --git a/launcher/minecraft/auth/steps/YggdrasilStep.cpp b/launcher/minecraft/auth/steps/YggdrasilStep.cpp
new file mode 100644
index 00000000..4c6b1624
--- /dev/null
+++ b/launcher/minecraft/auth/steps/YggdrasilStep.cpp
@@ -0,0 +1,51 @@
+#include "YggdrasilStep.h"
+
+#include "minecraft/auth/AuthRequest.h"
+#include "minecraft/auth/Parsers.h"
+#include "minecraft/auth/Yggdrasil.h"
+
+YggdrasilStep::YggdrasilStep(AccountData* data, QString password) : AuthStep(data), m_password(password) {
+ m_yggdrasil = new Yggdrasil(m_data, this);
+
+ connect(m_yggdrasil, &Task::failed, this, &YggdrasilStep::onAuthFailed);
+ connect(m_yggdrasil, &Task::succeeded, this, &YggdrasilStep::onAuthSucceeded);
+}
+
+YggdrasilStep::~YggdrasilStep() noexcept = default;
+
+QString YggdrasilStep::describe() {
+ return tr("Logging in with Mojang account.");
+}
+
+void YggdrasilStep::rehydrate() {
+ // NOOP, for now.
+}
+
+void YggdrasilStep::perform() {
+ if(m_password.size()) {
+ m_yggdrasil->login(m_password);
+ }
+ else {
+ m_yggdrasil->refresh();
+ }
+}
+
+void YggdrasilStep::onAuthSucceeded() {
+ emit finished(AccountTaskState::STATE_WORKING, tr("Logged in with Mojang"));
+}
+
+void YggdrasilStep::onAuthFailed() {
+ // TODO: hook these in again, expand to MSA
+ // m_error = m_yggdrasil->m_error;
+ // m_aborted = m_yggdrasil->m_aborted;
+
+ auto state = m_yggdrasil->taskState();
+ QString errorMessage = tr("Mojang user authentication failed.");
+
+ // NOTE: soft error in the first step means 'offline'
+ if(state == AccountTaskState::STATE_FAILED_SOFT) {
+ state = AccountTaskState::STATE_OFFLINE;
+ errorMessage = tr("Mojang user authentication ended with a network error.");
+ }
+ emit finished(state, errorMessage);
+}
diff --git a/launcher/minecraft/auth/steps/YggdrasilStep.h b/launcher/minecraft/auth/steps/YggdrasilStep.h
new file mode 100644
index 00000000..ebafb8e5
--- /dev/null
+++ b/launcher/minecraft/auth/steps/YggdrasilStep.h
@@ -0,0 +1,28 @@
+#pragma once
+#include <QObject>
+
+#include "QObjectPtr.h"
+#include "minecraft/auth/AuthStep.h"
+
+class Yggdrasil;
+
+class YggdrasilStep : public AuthStep {
+ Q_OBJECT
+
+public:
+ explicit YggdrasilStep(AccountData *data, QString password);
+ virtual ~YggdrasilStep() noexcept;
+
+ void perform() override;
+ void rehydrate() override;
+
+ QString describe() override;
+
+private slots:
+ void onAuthSucceeded();
+ void onAuthFailed();
+
+private:
+ Yggdrasil *m_yggdrasil = nullptr;
+ QString m_password;
+};
diff --git a/launcher/minecraft/launch/ClaimAccount.cpp b/launcher/minecraft/launch/ClaimAccount.cpp
index a1180f0a..bb4f6806 100644
--- a/launcher/minecraft/launch/ClaimAccount.cpp
+++ b/launcher/minecraft/launch/ClaimAccount.cpp
@@ -1,11 +1,15 @@
#include "ClaimAccount.h"
#include <launch/LaunchTask.h>
+#include "Application.h"
+#include "minecraft/auth/AccountList.h"
+
ClaimAccount::ClaimAccount(LaunchTask* parent, AuthSessionPtr session): LaunchStep(parent)
{
if(session->status == AuthSession::Status::PlayableOnline)
{
- m_account = session->m_accountPtr;
+ auto accounts = APPLICATION->accounts();
+ m_account = accounts->getAccountByProfileName(session->player_name);
}
}
diff --git a/launcher/minecraft/launch/LauncherPartLaunch.cpp b/launcher/minecraft/launch/LauncherPartLaunch.cpp
index ff022c40..8fd11eca 100644
--- a/launcher/minecraft/launch/LauncherPartLaunch.cpp
+++ b/launcher/minecraft/launch/LauncherPartLaunch.cpp
@@ -14,13 +14,14 @@
*/
#include "LauncherPartLaunch.h"
-#include <QCoreApplication>
-#include <launch/LaunchTask.h>
-#include <minecraft/MinecraftInstance.h>
-#include <FileSystem.h>
-#include <Commandline.h>
+
#include <QStandardPaths>
-#include "Env.h"
+
+#include "launch/LaunchTask.h"
+#include "minecraft/MinecraftInstance.h"
+#include "FileSystem.h"
+#include "Commandline.h"
+#include "Application.h"
LauncherPartLaunch::LauncherPartLaunch(LaunchTask *parent) : LaunchStep(parent)
{
@@ -72,7 +73,7 @@ void LauncherPartLaunch::executeTask()
m_process.setDetachable(true);
auto classPath = minecraftInstance->getClassPath();
- classPath.prepend(FS::PathCombine(ENV.getJarsPath(), "NewLaunch.jar"));
+ classPath.prepend(FS::PathCombine(APPLICATION->getJarsPath(), "NewLaunch.jar"));
auto natPath = minecraftInstance->getNativePath();
#ifdef Q_OS_WIN
diff --git a/launcher/minecraft/launch/VerifyJavaInstall.cpp b/launcher/minecraft/launch/VerifyJavaInstall.cpp
index 657669af..d9f7ecdc 100644
--- a/launcher/minecraft/launch/VerifyJavaInstall.cpp
+++ b/launcher/minecraft/launch/VerifyJavaInstall.cpp
@@ -11,8 +11,17 @@ void VerifyJavaInstall::executeTask() {
auto javaVersion = m_inst->getJavaVersion();
auto minecraftComponent = m_inst->getPackProfile()->getComponent("net.minecraft");
+ // Java 17 requirement
+ if (minecraftComponent->getReleaseDateTime() >= g_VersionFilterData.java17BeginsDate) {
+ if (javaVersion.major() < 17) {
+ emit logLine("Minecraft 1.18 Pre Release 2 and above require the use of Java 17",
+ MessageLevel::Fatal);
+ emitFailed(tr("Minecraft 1.18 Pre Release 2 and above require the use of Java 17"));
+ return;
+ }
+ }
// Java 16 requirement
- if (minecraftComponent->getReleaseDateTime() >= g_VersionFilterData.java16BeginsDate) {
+ else if (minecraftComponent->getReleaseDateTime() >= g_VersionFilterData.java16BeginsDate) {
if (javaVersion.major() < 16) {
emit logLine("Minecraft 21w19a and above require the use of Java 16",
MessageLevel::Fatal);
diff --git a/launcher/minecraft/legacy/LegacyInstance.cpp b/launcher/minecraft/legacy/LegacyInstance.cpp
index 9f9bda5a..f467ec06 100644
--- a/launcher/minecraft/legacy/LegacyInstance.cpp
+++ b/launcher/minecraft/legacy/LegacyInstance.cpp
@@ -90,7 +90,7 @@ bool LegacyInstance::shouldUseCustomBaseJar() const
}
-shared_qobject_ptr<Task> LegacyInstance::createUpdateTask(Net::Mode)
+Task::Ptr LegacyInstance::createUpdateTask(Net::Mode)
{
return nullptr;
}
@@ -122,6 +122,11 @@ QString LegacyInstance::binRoot() const
return FS::PathCombine(gameRoot(), "bin");
}
+QString LegacyInstance::modsRoot() const {
+ return FS::PathCombine(gameRoot(), "mods");
+}
+
+
QString LegacyInstance::jarModsDir() const
{
return FS::PathCombine(instanceRoot(), "instMods");
@@ -137,11 +142,6 @@ QString LegacyInstance::savesDir() const
return FS::PathCombine(gameRoot(), "saves");
}
-QString LegacyInstance::loaderModsDir() const
-{
- return FS::PathCombine(gameRoot(), "mods");
-}
-
QString LegacyInstance::coreModsDir() const
{
return FS::PathCombine(gameRoot(), "coremods");
diff --git a/launcher/minecraft/legacy/LegacyInstance.h b/launcher/minecraft/legacy/LegacyInstance.h
index ac2a8543..298543f7 100644
--- a/launcher/minecraft/legacy/LegacyInstance.h
+++ b/launcher/minecraft/legacy/LegacyInstance.h
@@ -45,11 +45,13 @@ public:
QString savesDir() const;
QString texturePacksDir() const;
QString jarModsDir() const;
- QString loaderModsDir() const;
QString coreModsDir() const;
QString resourceDir() const;
- virtual QString instanceConfigFolder() const override;
+
+ QString instanceConfigFolder() const override;
+
QString gameRoot() const override; // Path to the instance's minecraft directory.
+ QString modsRoot() const override; // Path to the instance's minecraft directory.
QString binRoot() const; // Path to the instance's minecraft bin directory.
/// Get the curent base jar of this instance. By default, it's the
@@ -93,7 +95,7 @@ public:
};
virtual bool shouldUpdate() const;
- virtual shared_qobject_ptr<Task> createUpdateTask(Net::Mode mode) override;
+ virtual Task::Ptr createUpdateTask(Net::Mode mode) override;
virtual QString typeName() const override;
diff --git a/launcher/minecraft/services/CapeChange.cpp b/launcher/minecraft/services/CapeChange.cpp
index c1d88d14..e49c166a 100644
--- a/launcher/minecraft/services/CapeChange.cpp
+++ b/launcher/minecraft/services/CapeChange.cpp
@@ -1,22 +1,24 @@
#include "CapeChange.h"
+
#include <QNetworkRequest>
#include <QHttpMultiPart>
-#include <Env.h>
-CapeChange::CapeChange(QObject *parent, AuthSessionPtr session, QString cape)
- : Task(parent), m_capeId(cape), m_session(session)
+#include "Application.h"
+
+CapeChange::CapeChange(QObject *parent, QString token, QString cape)
+ : Task(parent), m_capeId(cape), m_token(token)
{
}
void CapeChange::setCape(QString& cape) {
QNetworkRequest request(QUrl("https://api.minecraftservices.com/minecraft/profile/capes/active"));
auto requestString = QString("{\"capeId\":\"%1\"}").arg(m_capeId);
- request.setRawHeader("Authorization", QString("Bearer %1").arg(m_session->access_token).toLocal8Bit());
- QNetworkReply *rep = ENV.qnam().put(request, requestString.toUtf8());
+ request.setRawHeader("Authorization", QString("Bearer %1").arg(m_token).toLocal8Bit());
+ QNetworkReply *rep = APPLICATION->network()->put(request, requestString.toUtf8());
setStatus(tr("Equipping cape"));
- m_reply = std::shared_ptr<QNetworkReply>(rep);
+ m_reply = shared_qobject_ptr<QNetworkReply>(rep);
connect(rep, &QNetworkReply::uploadProgress, this, &Task::setProgress);
connect(rep, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(downloadError(QNetworkReply::NetworkError)));
connect(rep, SIGNAL(finished()), this, SLOT(downloadFinished()));
@@ -25,12 +27,12 @@ void CapeChange::setCape(QString& cape) {
void CapeChange::clearCape() {
QNetworkRequest request(QUrl("https://api.minecraftservices.com/minecraft/profile/capes/active"));
auto requestString = QString("{\"capeId\":\"%1\"}").arg(m_capeId);
- request.setRawHeader("Authorization", QString("Bearer %1").arg(m_session->access_token).toLocal8Bit());
- QNetworkReply *rep = ENV.qnam().deleteResource(request);
+ request.setRawHeader("Authorization", QString("Bearer %1").arg(m_token).toLocal8Bit());
+ QNetworkReply *rep = APPLICATION->network()->deleteResource(request);
setStatus(tr("Removing cape"));
- m_reply = std::shared_ptr<QNetworkReply>(rep);
+ m_reply = shared_qobject_ptr<QNetworkReply>(rep);
connect(rep, &QNetworkReply::uploadProgress, this, &Task::setProgress);
connect(rep, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(downloadError(QNetworkReply::NetworkError)));
connect(rep, SIGNAL(finished()), this, SLOT(downloadFinished()));
diff --git a/launcher/minecraft/services/CapeChange.h b/launcher/minecraft/services/CapeChange.h
index 1b6f2f72..185d69b6 100644
--- a/launcher/minecraft/services/CapeChange.h
+++ b/launcher/minecraft/services/CapeChange.h
@@ -3,14 +3,14 @@
#include <QFile>
#include <QtNetwork/QtNetwork>
#include <memory>
-#include <minecraft/auth/AuthSession.h>
#include "tasks/Task.h"
+#include "QObjectPtr.h"
class CapeChange : public Task
{
Q_OBJECT
public:
- CapeChange(QObject *parent, AuthSessionPtr session, QString capeId);
+ CapeChange(QObject *parent, QString token, QString capeId);
virtual ~CapeChange() {}
private:
@@ -19,8 +19,8 @@ private:
private:
QString m_capeId;
- AuthSessionPtr m_session;
- std::shared_ptr<QNetworkReply> m_reply;
+ QString m_token;
+ shared_qobject_ptr<QNetworkReply> m_reply;
protected:
virtual void executeTask();
diff --git a/launcher/minecraft/services/SkinDelete.cpp b/launcher/minecraft/services/SkinDelete.cpp
index 34977257..cce8364e 100644
--- a/launcher/minecraft/services/SkinDelete.cpp
+++ b/launcher/minecraft/services/SkinDelete.cpp
@@ -1,19 +1,21 @@
#include "SkinDelete.h"
+
#include <QNetworkRequest>
#include <QHttpMultiPart>
-#include <Env.h>
-SkinDelete::SkinDelete(QObject *parent, AuthSessionPtr session)
- : Task(parent), m_session(session)
+#include "Application.h"
+
+SkinDelete::SkinDelete(QObject *parent, QString token)
+ : Task(parent), m_token(token)
{
}
void SkinDelete::executeTask()
{
QNetworkRequest request(QUrl("https://api.minecraftservices.com/minecraft/profile/skins/active"));
- request.setRawHeader("Authorization", QString("Bearer %1").arg(m_session->access_token).toLocal8Bit());
- QNetworkReply *rep = ENV.qnam().deleteResource(request);
- m_reply = std::shared_ptr<QNetworkReply>(rep);
+ request.setRawHeader("Authorization", QString("Bearer %1").arg(m_token).toLocal8Bit());
+ QNetworkReply *rep = APPLICATION->network()->deleteResource(request);
+ m_reply = shared_qobject_ptr<QNetworkReply>(rep);
setStatus(tr("Deleting skin"));
connect(rep, &QNetworkReply::uploadProgress, this, &Task::setProgress);
diff --git a/launcher/minecraft/services/SkinDelete.h b/launcher/minecraft/services/SkinDelete.h
index 839bf9bc..83a84685 100644
--- a/launcher/minecraft/services/SkinDelete.h
+++ b/launcher/minecraft/services/SkinDelete.h
@@ -2,22 +2,20 @@
#include <QFile>
#include <QtNetwork/QtNetwork>
-#include <memory>
-#include <minecraft/auth/AuthSession.h>
#include "tasks/Task.h"
-typedef std::shared_ptr<class SkinDelete> SkinDeletePtr;
+typedef shared_qobject_ptr<class SkinDelete> SkinDeletePtr;
class SkinDelete : public Task
{
Q_OBJECT
public:
- SkinDelete(QObject *parent, AuthSessionPtr session);
+ SkinDelete(QObject *parent, QString token);
virtual ~SkinDelete() = default;
private:
- AuthSessionPtr m_session;
- std::shared_ptr<QNetworkReply> m_reply;
+ QString m_token;
+ shared_qobject_ptr<QNetworkReply> m_reply;
protected:
virtual void executeTask();
@@ -26,4 +24,3 @@ public slots:
void downloadError(QNetworkReply::NetworkError);
void downloadFinished();
};
-
diff --git a/launcher/minecraft/services/SkinUpload.cpp b/launcher/minecraft/services/SkinUpload.cpp
index 4e5a1698..7c2e8337 100644
--- a/launcher/minecraft/services/SkinUpload.cpp
+++ b/launcher/minecraft/services/SkinUpload.cpp
@@ -1,7 +1,9 @@
#include "SkinUpload.h"
+
#include <QNetworkRequest>
#include <QHttpMultiPart>
-#include <Env.h>
+
+#include "Application.h"
QByteArray getVariant(SkinUpload::Model model) {
switch (model) {
@@ -14,15 +16,15 @@ QByteArray getVariant(SkinUpload::Model model) {
}
}
-SkinUpload::SkinUpload(QObject *parent, AuthSessionPtr session, QByteArray skin, SkinUpload::Model model)
- : Task(parent), m_model(model), m_skin(skin), m_session(session)
+SkinUpload::SkinUpload(QObject *parent, QString token, QByteArray skin, SkinUpload::Model model)
+ : Task(parent), m_model(model), m_skin(skin), m_token(token)
{
}
void SkinUpload::executeTask()
{
QNetworkRequest request(QUrl("https://api.minecraftservices.com/minecraft/profile/skins"));
- request.setRawHeader("Authorization", QString("Bearer %1").arg(m_session->access_token).toLocal8Bit());
+ request.setRawHeader("Authorization", QString("Bearer %1").arg(m_token).toLocal8Bit());
QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
QHttpPart skin;
@@ -37,8 +39,8 @@ void SkinUpload::executeTask()
multiPart->append(skin);
multiPart->append(model);
- QNetworkReply *rep = ENV.qnam().post(request, multiPart);
- m_reply = std::shared_ptr<QNetworkReply>(rep);
+ QNetworkReply *rep = APPLICATION->network()->post(request, multiPart);
+ m_reply = shared_qobject_ptr<QNetworkReply>(rep);
setStatus(tr("Uploading skin"));
connect(rep, &QNetworkReply::uploadProgress, this, &Task::setProgress);
diff --git a/launcher/minecraft/services/SkinUpload.h b/launcher/minecraft/services/SkinUpload.h
index ec859699..2c1f0a2e 100644
--- a/launcher/minecraft/services/SkinUpload.h
+++ b/launcher/minecraft/services/SkinUpload.h
@@ -3,10 +3,9 @@
#include <QFile>
#include <QtNetwork/QtNetwork>
#include <memory>
-#include <minecraft/auth/AuthSession.h>
#include "tasks/Task.h"
-typedef std::shared_ptr<class SkinUpload> SkinUploadPtr;
+typedef shared_qobject_ptr<class SkinUpload> SkinUploadPtr;
class SkinUpload : public Task
{
@@ -19,14 +18,14 @@ public:
};
// Note this class takes ownership of the file.
- SkinUpload(QObject *parent, AuthSessionPtr session, QByteArray skin, Model model = STEVE);
+ SkinUpload(QObject *parent, QString token, QByteArray skin, Model model = STEVE);
virtual ~SkinUpload() {}
private:
Model m_model;
QByteArray m_skin;
- AuthSessionPtr m_session;
- std::shared_ptr<QNetworkReply> m_reply;
+ QString m_token;
+ shared_qobject_ptr<QNetworkReply> m_reply;
protected:
virtual void executeTask();
diff --git a/launcher/minecraft/update/AssetUpdateTask.cpp b/launcher/minecraft/update/AssetUpdateTask.cpp
index e26ab4ef..096e1719 100644
--- a/launcher/minecraft/update/AssetUpdateTask.cpp
+++ b/launcher/minecraft/update/AssetUpdateTask.cpp
@@ -1,10 +1,12 @@
-#include "Env.h"
#include "AssetUpdateTask.h"
+
#include "minecraft/MinecraftInstance.h"
#include "minecraft/PackProfile.h"
#include "net/ChecksumValidator.h"
#include "minecraft/AssetsUtils.h"
+#include "Application.h"
+
AssetUpdateTask::AssetUpdateTask(MinecraftInstance * inst)
{
m_inst = inst;
@@ -24,7 +26,7 @@ void AssetUpdateTask::executeTask()
QString localPath = assets->id + ".json";
auto job = new NetJob(tr("Asset index for %1").arg(m_inst->name()));
- auto metacache = ENV.metacache();
+ auto metacache = APPLICATION->metacache();
auto entry = metacache->resolveEntry("asset_indexes", localPath);
entry->setStale(true);
auto hexSha1 = assets->sha1.toLatin1();
@@ -41,7 +43,7 @@ void AssetUpdateTask::executeTask()
connect(downloadJob.get(), &NetJob::progress, this, &AssetUpdateTask::progress);
qDebug() << m_inst->name() << ": Starting asset index download";
- downloadJob->start();
+ downloadJob->start(APPLICATION->network());
}
bool AssetUpdateTask::canAbort() const
@@ -62,7 +64,7 @@ void AssetUpdateTask::assetIndexFinished()
// FIXME: this looks like a job for a generic validator based on json schema?
if (!AssetsUtils::loadAssetsIndexJson(assets->id, asset_fname, index))
{
- auto metacache = ENV.metacache();
+ auto metacache = APPLICATION->metacache();
auto entry = metacache->resolveEntry("asset_indexes", assets->id + ".json");
metacache->evictEntry(entry);
emitFailed(tr("Failed to read the assets index!"));
@@ -76,7 +78,7 @@ void AssetUpdateTask::assetIndexFinished()
connect(downloadJob.get(), &NetJob::succeeded, this, &AssetUpdateTask::emitSucceeded);
connect(downloadJob.get(), &NetJob::failed, this, &AssetUpdateTask::assetsFailed);
connect(downloadJob.get(), &NetJob::progress, this, &AssetUpdateTask::progress);
- downloadJob->start();
+ downloadJob->start(APPLICATION->network());
return;
}
emitSucceeded();
diff --git a/launcher/minecraft/update/AssetUpdateTask.h b/launcher/minecraft/update/AssetUpdateTask.h
index fdfa8f1c..6d7356f3 100644
--- a/launcher/minecraft/update/AssetUpdateTask.h
+++ b/launcher/minecraft/update/AssetUpdateTask.h
@@ -24,5 +24,5 @@ public slots:
private:
MinecraftInstance *m_inst;
- NetJobPtr downloadJob;
+ NetJob::Ptr downloadJob;
};
diff --git a/launcher/minecraft/update/FMLLibrariesTask.cpp b/launcher/minecraft/update/FMLLibrariesTask.cpp
index 8f1a43ff..a5c6b1e3 100644
--- a/launcher/minecraft/update/FMLLibrariesTask.cpp
+++ b/launcher/minecraft/update/FMLLibrariesTask.cpp
@@ -1,10 +1,12 @@
-#include "Env.h"
-#include <FileSystem.h>
-#include <minecraft/VersionFilterData.h>
#include "FMLLibrariesTask.h"
+
+#include "FileSystem.h"
+#include "minecraft/VersionFilterData.h"
#include "minecraft/MinecraftInstance.h"
#include "minecraft/PackProfile.h"
+
#include "BuildConfig.h"
+#include "Application.h"
FMLLibrariesTask::FMLLibrariesTask(MinecraftInstance * inst)
{
@@ -60,7 +62,7 @@ void FMLLibrariesTask::executeTask()
// download missing libs to our place
setStatus(tr("Downloading FML libraries..."));
auto dljob = new NetJob("FML libraries");
- auto metacache = ENV.metacache();
+ auto metacache = APPLICATION->metacache();
for (auto &lib : fmlLibsToProcess)
{
auto entry = metacache->resolveEntry("fmllibs", lib.filename);
@@ -72,7 +74,7 @@ void FMLLibrariesTask::executeTask()
connect(dljob, &NetJob::failed, this, &FMLLibrariesTask::fmllibsFailed);
connect(dljob, &NetJob::progress, this, &FMLLibrariesTask::progress);
downloadJob.reset(dljob);
- downloadJob->start();
+ downloadJob->start(APPLICATION->network());
}
bool FMLLibrariesTask::canAbort() const
@@ -87,7 +89,7 @@ void FMLLibrariesTask::fmllibsFinished()
{
setStatus(tr("Copying FML libraries into the instance..."));
MinecraftInstance *inst = (MinecraftInstance *)m_inst;
- auto metacache = ENV.metacache();
+ auto metacache = APPLICATION->metacache();
int index = 0;
for (auto &lib : fmlLibsToProcess)
{
diff --git a/launcher/minecraft/update/FMLLibrariesTask.h b/launcher/minecraft/update/FMLLibrariesTask.h
index a1e70ed4..2e5ad83a 100644
--- a/launcher/minecraft/update/FMLLibrariesTask.h
+++ b/launcher/minecraft/update/FMLLibrariesTask.h
@@ -25,7 +25,7 @@ public slots:
private:
MinecraftInstance *m_inst;
- NetJobPtr downloadJob;
+ NetJob::Ptr downloadJob;
QList<FMLlib> fmlLibsToProcess;
};
diff --git a/launcher/minecraft/update/LibrariesTask.cpp b/launcher/minecraft/update/LibrariesTask.cpp
index 7f66a651..065b4e06 100644
--- a/launcher/minecraft/update/LibrariesTask.cpp
+++ b/launcher/minecraft/update/LibrariesTask.cpp
@@ -1,8 +1,10 @@
-#include "Env.h"
#include "LibrariesTask.h"
+
#include "minecraft/MinecraftInstance.h"
#include "minecraft/PackProfile.h"
+#include "Application.h"
+
LibrariesTask::LibrariesTask(MinecraftInstance * inst)
{
m_inst = inst;
@@ -21,7 +23,7 @@ void LibrariesTask::executeTask()
auto job = new NetJob(tr("Libraries for instance %1").arg(inst->name()));
downloadJob.reset(job);
- auto metacache = ENV.metacache();
+ auto metacache = APPLICATION->metacache();
auto processArtifactPool = [&](const QList<LibraryPtr> & pool, QStringList & errors, const QString & localPath)
{
@@ -63,7 +65,7 @@ void LibrariesTask::executeTask()
connect(downloadJob.get(), &NetJob::succeeded, this, &LibrariesTask::emitSucceeded);
connect(downloadJob.get(), &NetJob::failed, this, &LibrariesTask::jarlibFailed);
connect(downloadJob.get(), &NetJob::progress, this, &LibrariesTask::progress);
- downloadJob->start();
+ downloadJob->start(APPLICATION->network());
}
bool LibrariesTask::canAbort() const
diff --git a/launcher/minecraft/update/LibrariesTask.h b/launcher/minecraft/update/LibrariesTask.h
index 49f76932..b966ad6c 100644
--- a/launcher/minecraft/update/LibrariesTask.h
+++ b/launcher/minecraft/update/LibrariesTask.h
@@ -22,5 +22,5 @@ public slots:
private:
MinecraftInstance *m_inst;
- NetJobPtr downloadJob;
+ NetJob::Ptr downloadJob;
};
diff --git a/launcher/modplatform/atlauncher/ATLPackInstallTask.cpp b/launcher/modplatform/atlauncher/ATLPackInstallTask.cpp
index 55087a27..9ef32db1 100644
--- a/launcher/modplatform/atlauncher/ATLPackInstallTask.cpp
+++ b/launcher/modplatform/atlauncher/ATLPackInstallTask.cpp
@@ -1,13 +1,13 @@
-#include <Env.h>
-#include <quazip.h>
-#include <QtConcurrent/QtConcurrent>
-#include <MMCZip.h>
-#include <minecraft/OneSixVersionFormat.h>
-#include <Version.h>
-#include <net/ChecksumValidator.h>
#include "ATLPackInstallTask.h"
-#include "BuildConfig.h"
+#include <QtConcurrent/QtConcurrent>
+
+#include <quazip.h>
+
+#include "MMCZip.h"
+#include "minecraft/OneSixVersionFormat.h"
+#include "Version.h"
+#include "net/ChecksumValidator.h"
#include "FileSystem.h"
#include "Json.h"
#include "minecraft/MinecraftInstance.h"
@@ -17,6 +17,9 @@
#include "meta/Version.h"
#include "meta/VersionList.h"
+#include "BuildConfig.h"
+#include "Application.h"
+
namespace ATLauncher {
PackInstallTask::PackInstallTask(UserInteractionSupport *support, QString pack, QString version)
@@ -43,7 +46,7 @@ void PackInstallTask::executeTask()
.arg(m_pack).arg(m_version_name);
netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), &response));
jobPtr = netJob;
- jobPtr->start();
+ jobPtr->start(APPLICATION->network());
QObject::connect(netJob, &NetJob::succeeded, this, &PackInstallTask::onDownloadSucceeded);
QObject::connect(netJob, &NetJob::failed, this, &PackInstallTask::onDownloadFailed);
@@ -76,7 +79,7 @@ void PackInstallTask::onDownloadSucceeded()
}
m_version = version;
- auto vlist = ENV.metadataIndex()->get("net.minecraft");
+ auto vlist = APPLICATION->metadataIndex()->get("net.minecraft");
if(!vlist)
{
emitFailed(tr("Failed to get local metadata index for %1").arg("net.minecraft"));
@@ -157,7 +160,7 @@ QString PackInstallTask::getDirForModType(ModType type, QString raw)
QString PackInstallTask::getVersionForLoader(QString uid)
{
if(m_version.loader.recommended || m_version.loader.latest || m_version.loader.choose) {
- auto vlist = ENV.metadataIndex()->get(uid);
+ auto vlist = APPLICATION->metadataIndex()->get(uid);
if(!vlist)
{
emitFailed(tr("Failed to get local metadata index for %1").arg(uid));
@@ -409,7 +412,7 @@ void PackInstallTask::installConfigs()
auto path = QString("Configs/%1/%2.zip").arg(m_pack).arg(m_version_name);
auto url = QString(BuildConfig.ATL_DOWNLOAD_SERVER_URL + "packs/%1/versions/%2/Configs.zip")
.arg(m_pack).arg(m_version_name);
- auto entry = ENV.metacache()->resolveEntry("ATLauncherPacks", path);
+ auto entry = APPLICATION->metacache()->resolveEntry("ATLauncherPacks", path);
entry->setStale(true);
auto dl = Net::Download::makeCached(url, entry);
@@ -438,7 +441,7 @@ void PackInstallTask::installConfigs()
setProgress(current, total);
});
- jobPtr->start();
+ jobPtr->start(APPLICATION->network());
}
void PackInstallTask::extractConfigs()
@@ -516,7 +519,7 @@ void PackInstallTask::downloadMods()
auto cacheName = fileName.completeBaseName() + "-" + mod.md5 + "." + fileName.suffix();
if (mod.type == ModType::Extract || mod.type == ModType::TexturePackExtract || mod.type == ModType::ResourcePackExtract) {
- auto entry = ENV.metacache()->resolveEntry("ATLauncherPacks", cacheName);
+ auto entry = APPLICATION->metacache()->resolveEntry("ATLauncherPacks", cacheName);
entry->setStale(true);
modsToExtract.insert(entry->getFullPath(), mod);
@@ -528,7 +531,7 @@ void PackInstallTask::downloadMods()
jobPtr->addNetAction(dl);
}
else if(mod.type == ModType::Decomp) {
- auto entry = ENV.metacache()->resolveEntry("ATLauncherPacks", cacheName);
+ auto entry = APPLICATION->metacache()->resolveEntry("ATLauncherPacks", cacheName);
entry->setStale(true);
modsToDecomp.insert(entry->getFullPath(), mod);
@@ -543,7 +546,7 @@ void PackInstallTask::downloadMods()
auto relpath = getDirForModType(mod.type, mod.type_raw);
if(relpath == Q_NULLPTR) continue;
- auto entry = ENV.metacache()->resolveEntry("ATLauncherPacks", cacheName);
+ auto entry = APPLICATION->metacache()->resolveEntry("ATLauncherPacks", cacheName);
entry->setStale(true);
auto dl = Net::Download::makeCached(url, entry);
@@ -558,7 +561,7 @@ void PackInstallTask::downloadMods()
modsToCopy[entry->getFullPath()] = path;
if(mod.type == ModType::Forge) {
- auto vlist = ENV.metadataIndex()->get("net.minecraftforge");
+ auto vlist = APPLICATION->metadataIndex()->get("net.minecraftforge");
if(vlist)
{
auto ver = vlist->getVersion(mod.version);
@@ -593,7 +596,7 @@ void PackInstallTask::downloadMods()
setProgress(current, total);
});
- jobPtr->start();
+ jobPtr->start(APPLICATION->network());
}
void PackInstallTask::onModsDownloaded() {
diff --git a/launcher/modplatform/atlauncher/ATLPackInstallTask.h b/launcher/modplatform/atlauncher/ATLPackInstallTask.h
index 39e2b013..f8ea2d54 100644
--- a/launcher/modplatform/atlauncher/ATLPackInstallTask.h
+++ b/launcher/modplatform/atlauncher/ATLPackInstallTask.h
@@ -74,7 +74,7 @@ private:
bool abortable = false;
- NetJobPtr jobPtr;
+ NetJob::Ptr jobPtr;
QByteArray response;
QString m_pack;
diff --git a/launcher/modplatform/flame/FileResolvingTask.cpp b/launcher/modplatform/flame/FileResolvingTask.cpp
index 295574f0..06f0cf2b 100644
--- a/launcher/modplatform/flame/FileResolvingTask.cpp
+++ b/launcher/modplatform/flame/FileResolvingTask.cpp
@@ -5,8 +5,8 @@ namespace {
const char * metabase = "https://cursemeta.dries007.net";
}
-Flame::FileResolvingTask::FileResolvingTask(Flame::Manifest& toProcess)
- : m_toProcess(toProcess)
+Flame::FileResolvingTask::FileResolvingTask(shared_qobject_ptr<QNetworkAccessManager> network, Flame::Manifest& toProcess)
+ : m_network(network), m_toProcess(toProcess)
{
}
@@ -14,7 +14,7 @@ void Flame::FileResolvingTask::executeTask()
{
setStatus(tr("Resolving mod IDs..."));
setProgress(0, m_toProcess.files.size());
- m_dljob.reset(new NetJob("Mod id resolver"));
+ m_dljob = new NetJob("Mod id resolver");
results.resize(m_toProcess.files.size());
int index = 0;
for(auto & file: m_toProcess.files)
@@ -27,7 +27,7 @@ void Flame::FileResolvingTask::executeTask()
index ++;
}
connect(m_dljob.get(), &NetJob::finished, this, &Flame::FileResolvingTask::netJobFinished);
- m_dljob->start();
+ m_dljob->start(m_network);
}
void Flame::FileResolvingTask::netJobFinished()
diff --git a/launcher/modplatform/flame/FileResolvingTask.h b/launcher/modplatform/flame/FileResolvingTask.h
index 78a38fcb..5e5adcd7 100644
--- a/launcher/modplatform/flame/FileResolvingTask.h
+++ b/launcher/modplatform/flame/FileResolvingTask.h
@@ -10,7 +10,7 @@ class FileResolvingTask : public Task
{
Q_OBJECT
public:
- explicit FileResolvingTask(Flame::Manifest &toProcess);
+ explicit FileResolvingTask(shared_qobject_ptr<QNetworkAccessManager> network, Flame::Manifest &toProcess);
virtual ~FileResolvingTask() {};
const Flame::Manifest &getResults() const
@@ -25,8 +25,9 @@ protected slots:
void netJobFinished();
private: /* data */
+ shared_qobject_ptr<QNetworkAccessManager> m_network;
Flame::Manifest m_toProcess;
QVector<QByteArray> results;
- NetJobPtr m_dljob;
+ NetJob::Ptr m_dljob;
};
}
diff --git a/launcher/modplatform/legacy_ftb/PackFetchTask.cpp b/launcher/modplatform/legacy_ftb/PackFetchTask.cpp
index c2ef6436..ecf36188 100644
--- a/launcher/modplatform/legacy_ftb/PackFetchTask.cpp
+++ b/launcher/modplatform/legacy_ftb/PackFetchTask.cpp
@@ -2,7 +2,8 @@
#include "PrivatePackManager.h"
#include <QDomDocument>
-#include <BuildConfig.h>
+#include "BuildConfig.h"
+#include "Application.h"
namespace LegacyFTB {
@@ -11,21 +12,20 @@ void PackFetchTask::fetch()
publicPacks.clear();
thirdPartyPacks.clear();
- NetJob *netJob = new NetJob("LegacyFTB::ModpackFetch");
+ jobPtr = new NetJob("LegacyFTB::ModpackFetch");
QUrl publicPacksUrl = QUrl(BuildConfig.LEGACY_FTB_CDN_BASE_URL + "static/modpacks.xml");
qDebug() << "Downloading public version info from" << publicPacksUrl.toString();
- netJob->addNetAction(Net::Download::makeByteArray(publicPacksUrl, &publicModpacksXmlFileData));
+ jobPtr->addNetAction(Net::Download::makeByteArray(publicPacksUrl, &publicModpacksXmlFileData));
QUrl thirdPartyUrl = QUrl(BuildConfig.LEGACY_FTB_CDN_BASE_URL + "static/thirdparty.xml");
qDebug() << "Downloading thirdparty version info from" << thirdPartyUrl.toString();
- netJob->addNetAction(Net::Download::makeByteArray(thirdPartyUrl, &thirdPartyModpacksXmlFileData));
+ jobPtr->addNetAction(Net::Download::makeByteArray(thirdPartyUrl, &thirdPartyModpacksXmlFileData));
- QObject::connect(netJob, &NetJob::succeeded, this, &PackFetchTask::fileDownloadFinished);
- QObject::connect(netJob, &NetJob::failed, this, &PackFetchTask::fileDownloadFailed);
+ QObject::connect(jobPtr.get(), &NetJob::succeeded, this, &PackFetchTask::fileDownloadFinished);
+ QObject::connect(jobPtr.get(), &NetJob::failed, this, &PackFetchTask::fileDownloadFailed);
- jobPtr.reset(netJob);
- netJob->start();
+ jobPtr->start(m_network);
}
void PackFetchTask::fetchPrivate(const QStringList & toFetch)
@@ -63,7 +63,7 @@ void PackFetchTask::fetchPrivate(const QStringList & toFetch)
delete data;
});
- job->start();
+ job->start(m_network);
}
}
diff --git a/launcher/modplatform/legacy_ftb/PackFetchTask.h b/launcher/modplatform/legacy_ftb/PackFetchTask.h
index 3ab32fab..f1667e90 100644
--- a/launcher/modplatform/legacy_ftb/PackFetchTask.h
+++ b/launcher/modplatform/legacy_ftb/PackFetchTask.h
@@ -13,14 +13,15 @@ class PackFetchTask : public QObject {
Q_OBJECT
public:
- PackFetchTask() = default;
+ PackFetchTask(shared_qobject_ptr<QNetworkAccessManager> network) : QObject(nullptr), m_network(network) {};
virtual ~PackFetchTask() = default;
void fetch();
void fetchPrivate(const QStringList &toFetch);
private:
- NetJobPtr jobPtr;
+ shared_qobject_ptr<QNetworkAccessManager> m_network;
+ NetJob::Ptr jobPtr;
QByteArray publicModpacksXmlFileData;
QByteArray thirdPartyModpacksXmlFileData;
diff --git a/launcher/modplatform/legacy_ftb/PackInstallTask.cpp b/launcher/modplatform/legacy_ftb/PackInstallTask.cpp
index c77f3250..64aecb39 100644
--- a/launcher/modplatform/legacy_ftb/PackInstallTask.cpp
+++ b/launcher/modplatform/legacy_ftb/PackInstallTask.cpp
@@ -1,24 +1,25 @@
#include "PackInstallTask.h"
-#include "Env.h"
-#include "MMCZip.h"
+#include <QtConcurrent>
+#include "MMCZip.h"
#include "BaseInstance.h"
#include "FileSystem.h"
#include "settings/INISettingsObject.h"
#include "minecraft/MinecraftInstance.h"
#include "minecraft/PackProfile.h"
#include "minecraft/GradleSpecifier.h"
-#include "BuildConfig.h"
-#include <QtConcurrent>
+#include "BuildConfig.h"
+#include "Application.h"
namespace LegacyFTB {
-PackInstallTask::PackInstallTask(Modpack pack, QString version)
+PackInstallTask::PackInstallTask(shared_qobject_ptr<QNetworkAccessManager> network, Modpack pack, QString version)
{
m_pack = pack;
m_version = version;
+ m_network = network;
}
void PackInstallTask::executeTask()
@@ -31,8 +32,8 @@ void PackInstallTask::downloadPack()
setStatus(tr("Downloading zip for %1").arg(m_pack.name));
auto packoffset = QString("%1/%2/%3").arg(m_pack.dir, m_version.replace(".", "_"), m_pack.file);
- auto entry = ENV.metacache()->resolveEntry("FTBPacks", packoffset);
- NetJob *job = new NetJob("Download FTB Pack");
+ auto entry = APPLICATION->metacache()->resolveEntry("FTBPacks", packoffset);
+ netJobContainer = new NetJob("Download FTB Pack");
entry->setStale(true);
QString url;
@@ -44,14 +45,13 @@ void PackInstallTask::downloadPack()
{
url = QString(BuildConfig.LEGACY_FTB_CDN_BASE_URL + "modpacks/%1").arg(packoffset);
}
- job->addNetAction(Net::Download::makeCached(url, entry));
+ netJobContainer->addNetAction(Net::Download::makeCached(url, entry));
archivePath = entry->getFullPath();
- netJobContainer.reset(job);
- connect(job, &NetJob::succeeded, this, &PackInstallTask::onDownloadSucceeded);
- connect(job, &NetJob::failed, this, &PackInstallTask::onDownloadFailed);
- connect(job, &NetJob::progress, this, &PackInstallTask::onDownloadProgress);
- job->start();
+ connect(netJobContainer.get(), &NetJob::succeeded, this, &PackInstallTask::onDownloadSucceeded);
+ connect(netJobContainer.get(), &NetJob::failed, this, &PackInstallTask::onDownloadFailed);
+ connect(netJobContainer.get(), &NetJob::progress, this, &PackInstallTask::onDownloadProgress);
+ netJobContainer->start(m_network);
progress(1, 4);
}
diff --git a/launcher/modplatform/legacy_ftb/PackInstallTask.h b/launcher/modplatform/legacy_ftb/PackInstallTask.h
index 600f72e7..305635a1 100644
--- a/launcher/modplatform/legacy_ftb/PackInstallTask.h
+++ b/launcher/modplatform/legacy_ftb/PackInstallTask.h
@@ -8,6 +8,8 @@
#include "meta/VersionList.h"
#include "PackHelpers.h"
+#include "net/NetJob.h"
+
#include <nonstd/optional>
namespace LegacyFTB {
@@ -17,7 +19,7 @@ class PackInstallTask : public InstanceTask
Q_OBJECT
public:
- explicit PackInstallTask(Modpack pack, QString version);
+ explicit PackInstallTask(shared_qobject_ptr<QNetworkAccessManager> network, Modpack pack, QString version);
virtual ~PackInstallTask(){}
bool canAbort() const override { return true; }
@@ -41,11 +43,12 @@ private slots:
void onUnzipCanceled();
private: /* data */
+ shared_qobject_ptr<QNetworkAccessManager> m_network;
bool abortable = false;
std::unique_ptr<QuaZip> m_packZip;
QFuture<nonstd::optional<QStringList>> m_extractFuture;
QFutureWatcher<nonstd::optional<QStringList>> m_extractFutureWatcher;
- NetJobPtr netJobContainer;
+ NetJob::Ptr netJobContainer;
QString archivePath;
Modpack m_pack;
diff --git a/launcher/modplatform/modpacksch/FTBPackInstallTask.cpp b/launcher/modplatform/modpacksch/FTBPackInstallTask.cpp
index 496edde7..563b5cfa 100644
--- a/launcher/modplatform/modpacksch/FTBPackInstallTask.cpp
+++ b/launcher/modplatform/modpacksch/FTBPackInstallTask.cpp
@@ -1,7 +1,5 @@
#include "FTBPackInstallTask.h"
-#include "BuildConfig.h"
-#include "Env.h"
#include "FileSystem.h"
#include "Json.h"
#include "minecraft/MinecraftInstance.h"
@@ -9,6 +7,9 @@
#include "net/ChecksumValidator.h"
#include "settings/INISettingsObject.h"
+#include "BuildConfig.h"
+#include "Application.h"
+
namespace ModpacksCH {
PackInstallTask::PackInstallTask(Modpack pack, QString version)
@@ -50,7 +51,7 @@ void PackInstallTask::executeTask()
.arg(m_pack.id).arg(version.id);
netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), &response));
jobPtr = netJob;
- jobPtr->start();
+ jobPtr->start(APPLICATION->network());
QObject::connect(netJob, &NetJob::succeeded, this, &PackInstallTask::onDownloadSucceeded);
QObject::connect(netJob, &NetJob::failed, this, &PackInstallTask::onDownloadFailed);
@@ -95,14 +96,14 @@ void PackInstallTask::downloadPack()
{
setStatus(tr("Downloading mods..."));
- jobPtr.reset(new NetJob(tr("Mod download")));
+ jobPtr = new NetJob(tr("Mod download"));
for(auto file : m_version.files) {
if(file.serverOnly) continue;
QFileInfo fileName(file.name);
auto cacheName = fileName.completeBaseName() + "-" + file.sha1 + "." + fileName.suffix();
- auto entry = ENV.metacache()->resolveEntry("ModpacksCHPacks", cacheName);
+ auto entry = APPLICATION->metacache()->resolveEntry("ModpacksCHPacks", cacheName);
entry->setStale(true);
auto relpath = FS::PathCombine("minecraft", file.path, file.name);
@@ -141,7 +142,7 @@ void PackInstallTask::downloadPack()
setProgress(current, total);
});
- jobPtr->start();
+ jobPtr->start(APPLICATION->network());
}
void PackInstallTask::install()
diff --git a/launcher/modplatform/modpacksch/FTBPackInstallTask.h b/launcher/modplatform/modpacksch/FTBPackInstallTask.h
index fdd84c4e..23362dc9 100644
--- a/launcher/modplatform/modpacksch/FTBPackInstallTask.h
+++ b/launcher/modplatform/modpacksch/FTBPackInstallTask.h
@@ -32,7 +32,7 @@ private:
private:
bool abortable = false;
- NetJobPtr jobPtr;
+ NetJob::Ptr jobPtr;
QByteArray response;
Modpack m_pack;
diff --git a/launcher/modplatform/technic/SingleZipPackInstallTask.cpp b/launcher/modplatform/technic/SingleZipPackInstallTask.cpp
index dbce8e53..0ab9f3c0 100644
--- a/launcher/modplatform/technic/SingleZipPackInstallTask.cpp
+++ b/launcher/modplatform/technic/SingleZipPackInstallTask.cpp
@@ -15,12 +15,13 @@
#include "SingleZipPackInstallTask.h"
-#include "Env.h"
+#include <QtConcurrent>
+
#include "MMCZip.h"
#include "TechnicPackProcessor.h"
+#include "FileSystem.h"
-#include <QtConcurrent>
-#include <FileSystem.h>
+#include "Application.h"
Technic::SingleZipPackInstallTask::SingleZipPackInstallTask(const QUrl &sourceUrl, const QString &minecraftVersion)
{
@@ -41,7 +42,7 @@ void Technic::SingleZipPackInstallTask::executeTask()
setStatus(tr("Downloading modpack:\n%1").arg(m_sourceUrl.toString()));
const QString path = m_sourceUrl.host() + '/' + m_sourceUrl.path();
- auto entry = ENV.metacache()->resolveEntry("general", path);
+ auto entry = APPLICATION->metacache()->resolveEntry("general", path);
entry->setStale(true);
m_filesNetJob.reset(new NetJob(tr("Modpack download")));
m_filesNetJob->addNetAction(Net::Download::makeCached(m_sourceUrl, entry));
@@ -50,7 +51,7 @@ void Technic::SingleZipPackInstallTask::executeTask()
connect(job, &NetJob::succeeded, this, &Technic::SingleZipPackInstallTask::downloadSucceeded);
connect(job, &NetJob::progress, this, &Technic::SingleZipPackInstallTask::downloadProgressChanged);
connect(job, &NetJob::failed, this, &Technic::SingleZipPackInstallTask::downloadFailed);
- m_filesNetJob->start();
+ m_filesNetJob->start(APPLICATION->network());
}
void Technic::SingleZipPackInstallTask::downloadSucceeded()
diff --git a/launcher/modplatform/technic/SingleZipPackInstallTask.h b/launcher/modplatform/technic/SingleZipPackInstallTask.h
index 80f10a98..74f60941 100644
--- a/launcher/modplatform/technic/SingleZipPackInstallTask.h
+++ b/launcher/modplatform/technic/SingleZipPackInstallTask.h
@@ -55,7 +55,7 @@ private:
QUrl m_sourceUrl;
QString m_minecraftVersion;
QString m_archivePath;
- NetJobPtr m_filesNetJob;
+ NetJob::Ptr m_filesNetJob;
std::unique_ptr<QuaZip> m_packZip;
QFuture<nonstd::optional<QStringList>> m_extractFuture;
QFutureWatcher<nonstd::optional<QStringList>> m_extractFutureWatcher;
diff --git a/launcher/modplatform/technic/SolderPackInstallTask.cpp b/launcher/modplatform/technic/SolderPackInstallTask.cpp
index 1b4186d4..2492ee81 100644
--- a/launcher/modplatform/technic/SolderPackInstallTask.cpp
+++ b/launcher/modplatform/technic/SolderPackInstallTask.cpp
@@ -21,10 +21,14 @@
#include <MMCZip.h>
#include "TechnicPackProcessor.h"
-Technic::SolderPackInstallTask::SolderPackInstallTask(const QUrl &sourceUrl, const QString &minecraftVersion)
-{
+Technic::SolderPackInstallTask::SolderPackInstallTask(
+ shared_qobject_ptr<QNetworkAccessManager> network,
+ const QUrl &sourceUrl,
+ const QString &minecraftVersion
+) {
m_sourceUrl = sourceUrl;
m_minecraftVersion = minecraftVersion;
+ m_network = network;
}
bool Technic::SolderPackInstallTask::abort() {
@@ -43,7 +47,7 @@ void Technic::SolderPackInstallTask::executeTask()
auto job = m_filesNetJob.get();
connect(job, &NetJob::succeeded, this, &Technic::SolderPackInstallTask::versionSucceeded);
connect(job, &NetJob::failed, this, &Technic::SolderPackInstallTask::downloadFailed);
- m_filesNetJob->start();
+ m_filesNetJob->start(m_network);
}
void Technic::SolderPackInstallTask::versionSucceeded()
@@ -68,7 +72,7 @@ void Technic::SolderPackInstallTask::versionSucceeded()
auto job = m_filesNetJob.get();
connect(job, &NetJob::succeeded, this, &Technic::SolderPackInstallTask::fileListSucceeded);
connect(job, &NetJob::failed, this, &Technic::SolderPackInstallTask::downloadFailed);
- m_filesNetJob->start();
+ m_filesNetJob->start(m_network);
}
void Technic::SolderPackInstallTask::fileListSucceeded()
@@ -109,7 +113,7 @@ void Technic::SolderPackInstallTask::fileListSucceeded()
connect(m_filesNetJob.get(), &NetJob::succeeded, this, &Technic::SolderPackInstallTask::downloadSucceeded);
connect(m_filesNetJob.get(), &NetJob::progress, this, &Technic::SolderPackInstallTask::downloadProgressChanged);
connect(m_filesNetJob.get(), &NetJob::failed, this, &Technic::SolderPackInstallTask::downloadFailed);
- m_filesNetJob->start();
+ m_filesNetJob->start(m_network);
}
void Technic::SolderPackInstallTask::downloadSucceeded()
diff --git a/launcher/modplatform/technic/SolderPackInstallTask.h b/launcher/modplatform/technic/SolderPackInstallTask.h
index 6e1057eb..9b2058d8 100644
--- a/launcher/modplatform/technic/SolderPackInstallTask.h
+++ b/launcher/modplatform/technic/SolderPackInstallTask.h
@@ -27,7 +27,7 @@ namespace Technic
{
Q_OBJECT
public:
- explicit SolderPackInstallTask(const QUrl &sourceUrl, const QString &minecraftVersion);
+ explicit SolderPackInstallTask(shared_qobject_ptr<QNetworkAccessManager> network, const QUrl &sourceUrl, const QString &minecraftVersion);
bool canAbort() const override { return true; }
bool abort() override;
@@ -48,7 +48,9 @@ namespace Technic
private:
bool m_abortable = false;
- NetJobPtr m_filesNetJob;
+ shared_qobject_ptr<QNetworkAccessManager> m_network;
+
+ NetJob::Ptr m_filesNetJob;
QUrl m_sourceUrl;
QString m_minecraftVersion;
QByteArray m_response;
diff --git a/launcher/net/Download.cpp b/launcher/net/Download.cpp
index 3f183b7d..b314573f 100644
--- a/launcher/net/Download.cpp
+++ b/launcher/net/Download.cpp
@@ -15,16 +15,17 @@
#include "Download.h"
-#include "BuildConfig.h"
#include <QFileInfo>
#include <QDateTime>
#include <QDebug>
-#include "Env.h"
-#include <FileSystem.h>
+
+#include "FileSystem.h"
#include "ChecksumValidator.h"
#include "MetaCacheSink.h"
#include "ByteArraySink.h"
+#include "BuildConfig.h"
+
namespace Net {
Download::Download():NetAction()
@@ -41,7 +42,7 @@ Download::Ptr Download::makeCached(QUrl url, MetaEntryPtr entry, Options options
auto cachedNode = new MetaCacheSink(entry, md5Node);
dl->m_sink.reset(cachedNode);
dl->m_target_path = entry->getFullPath();
- return std::shared_ptr<Download>(dl);
+ return dl;
}
Download::Ptr Download::makeByteArray(QUrl url, QByteArray *output, Options options)
@@ -50,7 +51,7 @@ Download::Ptr Download::makeByteArray(QUrl url, QByteArray *output, Options opti
dl->m_url = url;
dl->m_options = options;
dl->m_sink.reset(new ByteArraySink(output));
- return std::shared_ptr<Download>(dl);
+ return dl;
}
Download::Ptr Download::makeFile(QUrl url, QString path, Options options)
@@ -59,7 +60,7 @@ Download::Ptr Download::makeFile(QUrl url, QString path, Options options)
dl->m_url = url;
dl->m_options = options;
dl->m_sink.reset(new FileSink(path));
- return std::shared_ptr<Download>(dl);
+ return dl;
}
void Download::addValidator(Validator * v)
@@ -67,7 +68,7 @@ void Download::addValidator(Validator * v)
m_sink->addValidator(v);
}
-void Download::start()
+void Download::startImpl()
{
if(m_status == Job_Aborted)
{
@@ -97,7 +98,7 @@ void Download::start()
request.setHeader(QNetworkRequest::UserAgentHeader, BuildConfig.USER_AGENT);
- QNetworkReply *rep = ENV.qnam().get(request);
+ QNetworkReply *rep = m_network->get(request);
m_reply.reset(rep);
connect(rep, SIGNAL(downloadProgress(qint64, qint64)), SLOT(downloadProgress(qint64, qint64)));
@@ -207,7 +208,7 @@ bool Download::handleRedirect()
m_url = QUrl(redirect.toString());
qDebug() << "Following redirect to " << m_url.toString();
- start();
+ start(m_network);
return true;
}
diff --git a/launcher/net/Download.h b/launcher/net/Download.h
index a224bb86..0f9bfe7f 100644
--- a/launcher/net/Download.h
+++ b/launcher/net/Download.h
@@ -20,13 +20,15 @@
#include "Validator.h"
#include "Sink.h"
+#include "QObjectPtr.h"
+
namespace Net {
class Download : public NetAction
{
Q_OBJECT
public: /* types */
- typedef std::shared_ptr<class Download> Ptr;
+ typedef shared_qobject_ptr<class Download> Ptr;
enum class Option
{
NoOptions = 0,
@@ -62,7 +64,7 @@ protected slots:
void downloadReadyRead() override;
public slots:
- void start() override;
+ void startImpl() override;
private: /* data */
// FIXME: remove this, it has no business being here.
diff --git a/launcher/net/FileSink.cpp b/launcher/net/FileSink.cpp
index 8b3e917d..7e9b8929 100644
--- a/launcher/net/FileSink.cpp
+++ b/launcher/net/FileSink.cpp
@@ -1,7 +1,6 @@
#include "FileSink.h"
#include <QFile>
#include <QFileInfo>
-#include "Env.h"
#include "FileSystem.h"
namespace Net {
diff --git a/launcher/net/HttpMetaCache.cpp b/launcher/net/HttpMetaCache.cpp
index 4bc8fbc8..8734e0bf 100644
--- a/launcher/net/HttpMetaCache.cpp
+++ b/launcher/net/HttpMetaCache.cpp
@@ -13,7 +13,6 @@
* limitations under the License.
*/
-#include "Env.h"
#include "HttpMetaCache.h"
#include "FileSystem.h"
diff --git a/launcher/net/MetaCacheSink.cpp b/launcher/net/MetaCacheSink.cpp
index d7f18533..5cdf0460 100644
--- a/launcher/net/MetaCacheSink.cpp
+++ b/launcher/net/MetaCacheSink.cpp
@@ -1,8 +1,8 @@
#include "MetaCacheSink.h"
#include <QFile>
#include <QFileInfo>
-#include "Env.h"
#include "FileSystem.h"
+#include "Application.h"
namespace Net {
@@ -53,7 +53,7 @@ JobStatus MetaCacheSink::finalizeCache(QNetworkReply & reply)
}
m_entry->setLocalChangedTimestamp(output_file_info.lastModified().toUTC().toMSecsSinceEpoch());
m_entry->setStale(false);
- ENV.metacache()->updateEntry(m_entry);
+ APPLICATION->metacache()->updateEntry(m_entry);
return Job_Finished;
}
diff --git a/launcher/net/NetAction.h b/launcher/net/NetAction.h
index c13c187f..efb20953 100644
--- a/launcher/net/NetAction.h
+++ b/launcher/net/NetAction.h
@@ -35,14 +35,15 @@ enum JobStatus
Job_Failed_Proceed
};
-typedef std::shared_ptr<class NetAction> NetActionPtr;
class NetAction : public QObject
{
Q_OBJECT
protected:
- explicit NetAction() : QObject(0) {};
+ explicit NetAction() : QObject(nullptr) {};
public:
+ using Ptr = shared_qobject_ptr<NetAction>;
+
virtual ~NetAction() {};
bool isRunning() const
@@ -93,9 +94,17 @@ protected slots:
virtual void downloadReadyRead() = 0;
public slots:
- virtual void start() = 0;
+ void start(shared_qobject_ptr<QNetworkAccessManager> network) {
+ m_network = network;
+ startImpl();
+ }
+
+protected:
+ virtual void startImpl() = 0;
public:
+ shared_qobject_ptr<QNetworkAccessManager> m_network;
+
/// index within the parent job, FIXME: nuke
int m_index_within_job = 0;
diff --git a/launcher/net/NetJob.cpp b/launcher/net/NetJob.cpp
index 029d9e34..9bad89ed 100644
--- a/launcher/net/NetJob.cpp
+++ b/launcher/net/NetJob.cpp
@@ -144,7 +144,7 @@ void NetJob::startMoreParts()
connect(part.get(), SIGNAL(aborted(int)), SLOT(partAborted(int)));
connect(part.get(), SIGNAL(netActionProgress(int, qint64, qint64)),
SLOT(partProgress(int, qint64, qint64)));
- part->start();
+ part->start(m_network);
}
}
@@ -194,7 +194,7 @@ bool NetJob::abort()
return fullyAborted;
}
-bool NetJob::addNetAction(NetActionPtr action)
+bool NetJob::addNetAction(NetAction::Ptr action)
{
action->m_index_within_job = downloads.size();
downloads.append(action);
diff --git a/launcher/net/NetJob.h b/launcher/net/NetJob.h
index 338f8e71..45b9bc0f 100644
--- a/launcher/net/NetJob.h
+++ b/launcher/net/NetJob.h
@@ -22,33 +22,34 @@
#include "QObjectPtr.h"
class NetJob;
-typedef shared_qobject_ptr<NetJob> NetJobPtr;
class NetJob : public Task
{
Q_OBJECT
public:
+ using Ptr = shared_qobject_ptr<NetJob>;
+
explicit NetJob(QString job_name) : Task()
{
setObjectName(job_name);
}
virtual ~NetJob();
- bool addNetAction(NetActionPtr action);
+ bool addNetAction(NetAction::Ptr action);
- NetActionPtr operator[](int index)
+ NetAction::Ptr operator[](int index)
{
return downloads[index];
}
- const NetActionPtr at(const int index)
+ const NetAction::Ptr at(const int index)
{
return downloads.at(index);
}
- NetActionPtr first()
+ NetAction::Ptr first()
{
if (downloads.size())
return downloads[0];
- return NetActionPtr();
+ return NetAction::Ptr();
}
int size() const
{
@@ -64,6 +65,19 @@ private slots:
public slots:
virtual void executeTask() override;
virtual bool abort() override;
+ virtual void start(shared_qobject_ptr<QNetworkAccessManager> network) {
+ m_network = network;
+ start();
+ }
+
+protected slots:
+ void start() override {
+ if(!m_network) {
+ throw "Missing network while trying to start " + objectName();
+ return;
+ }
+ Task::start();
+ }
private slots:
void partProgress(int index, qint64 bytesReceived, qint64 bytesTotal);
@@ -72,13 +86,15 @@ private slots:
void partAborted(int index);
private:
+ shared_qobject_ptr<QNetworkAccessManager> m_network;
+
struct part_info
{
qint64 current_progress = 0;
qint64 total_progress = 1;
int failures = 0;
};
- QList<NetActionPtr> downloads;
+ QList<NetAction::Ptr> downloads;
QList<part_info> parts_progress;
QQueue<int> m_todo;
QSet<int> m_doing;
diff --git a/launcher/net/PasteUpload.cpp b/launcher/net/PasteUpload.cpp
index 8ec6e4ae..4b69b68a 100644
--- a/launcher/net/PasteUpload.cpp
+++ b/launcher/net/PasteUpload.cpp
@@ -1,11 +1,12 @@
#include "PasteUpload.h"
-#include "Env.h"
+#include "BuildConfig.h"
+#include "Application.h"
+
#include <QDebug>
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonDocument>
#include <QFile>
-#include <BuildConfig.h>
PasteUpload::PasteUpload(QWidget *window, QString text, QString key) : m_window(window)
{
@@ -41,7 +42,7 @@ void PasteUpload::executeTask()
request.setRawHeader("Content-Length", QByteArray::number(m_jsonContent.size()));
request.setRawHeader("X-Auth-Token", m_key.toStdString().c_str());
- QNetworkReply *rep = ENV.qnam().post(request, m_jsonContent);
+ QNetworkReply *rep = APPLICATION->network()->post(request, m_jsonContent);
m_reply = std::shared_ptr<QNetworkReply>(rep);
setStatus(tr("Uploading to paste.ee"));
diff --git a/launcher/news/NewsChecker.cpp b/launcher/news/NewsChecker.cpp
index c66f49e1..77d428a5 100644
--- a/launcher/news/NewsChecker.cpp
+++ b/launcher/news/NewsChecker.cpp
@@ -20,8 +20,9 @@
#include <QDebug>
-NewsChecker::NewsChecker(const QString& feedUrl)
+NewsChecker::NewsChecker(shared_qobject_ptr<QNetworkAccessManager> network, const QString& feedUrl)
{
+ m_network = network;
m_feedUrl = feedUrl;
}
@@ -41,7 +42,7 @@ void NewsChecker::reloadNews()
QObject::connect(job, &NetJob::succeeded, this, &NewsChecker::rssDownloadFinished);
QObject::connect(job, &NetJob::failed, this, &NewsChecker::rssDownloadFailed);
m_newsNetJob.reset(job);
- job->start();
+ job->start(m_network);
}
void NewsChecker::rssDownloadFinished()
diff --git a/launcher/news/NewsChecker.h b/launcher/news/NewsChecker.h
index 84b1f552..8467a541 100644
--- a/launcher/news/NewsChecker.h
+++ b/launcher/news/NewsChecker.h
@@ -30,7 +30,7 @@ public:
/*!
* Constructs a news reader to read from the given RSS feed URL.
*/
- NewsChecker(const QString& feedUrl);
+ NewsChecker(shared_qobject_ptr<QNetworkAccessManager> network, const QString& feedUrl);
/*!
* Returns the error message for the last time the news was loaded.
@@ -80,7 +80,7 @@ protected: /* data */
QList<NewsEntryPtr> m_newsEntries;
//! The network job to use to load the news.
- NetJobPtr m_newsNetJob;
+ NetJob::Ptr m_newsNetJob;
//! True if news has been loaded.
bool m_loadedNews;
@@ -93,6 +93,8 @@ protected: /* data */
*/
QString m_lastLoadError;
+ shared_qobject_ptr<QNetworkAccessManager> m_network;
+
protected slots:
/// Emits newsLoaded() and sets m_lastLoadError to empty string.
void succeed();
diff --git a/launcher/notifications/NotificationChecker.cpp b/launcher/notifications/NotificationChecker.cpp
index 8209c28b..00c918f8 100644
--- a/launcher/notifications/NotificationChecker.cpp
+++ b/launcher/notifications/NotificationChecker.cpp
@@ -5,9 +5,9 @@
#include <QJsonArray>
#include <QDebug>
-#include "Env.h"
#include "net/Download.h"
+#include "Application.h"
NotificationChecker::NotificationChecker(QObject *parent)
: QObject(parent)
@@ -53,11 +53,11 @@ void NotificationChecker::checkForNotifications()
return;
}
m_checkJob.reset(new NetJob("Checking for notifications"));
- auto entry = ENV.metacache()->resolveEntry("root", "notifications.json");
+ auto entry = APPLICATION->metacache()->resolveEntry("root", "notifications.json");
entry->setStale(true);
m_checkJob->addNetAction(m_download = Net::Download::makeCached(m_notificationsUrl, entry));
connect(m_download.get(), &Net::Download::succeeded, this, &NotificationChecker::downloadSucceeded);
- m_checkJob->start();
+ m_checkJob->start(APPLICATION->network());
}
void NotificationChecker::downloadSucceeded(int)
diff --git a/launcher/notifications/NotificationChecker.h b/launcher/notifications/NotificationChecker.h
index eb2b32a2..0f305f33 100644
--- a/launcher/notifications/NotificationChecker.h
+++ b/launcher/notifications/NotificationChecker.h
@@ -52,7 +52,7 @@ private:
private:
QList<NotificationEntry> m_entries;
QUrl m_notificationsUrl;
- NetJobPtr m_checkJob;
+ NetJob::Ptr m_checkJob;
Net::Download::Ptr m_download;
QString m_appVersionChannel;
diff --git a/launcher/resources/backgrounds/backgrounds.qrc b/launcher/resources/backgrounds/backgrounds.qrc
index 83505635..52921512 100644
--- a/launcher/resources/backgrounds/backgrounds.qrc
+++ b/launcher/resources/backgrounds/backgrounds.qrc
@@ -3,5 +3,6 @@
<qresource prefix="/backgrounds">
<file alias="kitteh">catbgrnd2.png</file>
<file alias="catmas">catmas.png</file>
+ <file alias="cattiversary">cattiversary.png</file>
</qresource>
</RCC>
diff --git a/launcher/resources/backgrounds/cattiversary.png b/launcher/resources/backgrounds/cattiversary.png
new file mode 100644
index 00000000..09a36566
--- /dev/null
+++ b/launcher/resources/backgrounds/cattiversary.png
Binary files differ
diff --git a/launcher/resources/sources/burfcat_hat.png b/launcher/resources/sources/burfcat_hat.png
new file mode 100644
index 00000000..a378c1fb
--- /dev/null
+++ b/launcher/resources/sources/burfcat_hat.png
Binary files differ
diff --git a/launcher/resources/sources/cattiversary.xcf b/launcher/resources/sources/cattiversary.xcf
new file mode 100644
index 00000000..0026cd35
--- /dev/null
+++ b/launcher/resources/sources/cattiversary.xcf
Binary files differ
diff --git a/launcher/screenshots/ImgurAlbumCreation.cpp b/launcher/screenshots/ImgurAlbumCreation.cpp
index 1f195f00..d5de302a 100644
--- a/launcher/screenshots/ImgurAlbumCreation.cpp
+++ b/launcher/screenshots/ImgurAlbumCreation.cpp
@@ -5,18 +5,18 @@
#include <QJsonObject>
#include <QUrl>
#include <QStringList>
+#include <QDebug>
#include "BuildConfig.h"
-#include "Env.h"
-#include <QDebug>
+#include "Application.h"
-ImgurAlbumCreation::ImgurAlbumCreation(QList<ScreenshotPtr> screenshots) : NetAction(), m_screenshots(screenshots)
+ImgurAlbumCreation::ImgurAlbumCreation(QList<ScreenShot::Ptr> screenshots) : NetAction(), m_screenshots(screenshots)
{
m_url = BuildConfig.IMGUR_BASE_URL + "album.json";
m_status = Job_NotStarted;
}
-void ImgurAlbumCreation::start()
+void ImgurAlbumCreation::startImpl()
{
m_status = Job_InProgress;
QNetworkRequest request(m_url);
@@ -33,7 +33,7 @@ void ImgurAlbumCreation::start()
const QByteArray data = "deletehashes=" + hashes.join(',').toUtf8() + "&title=Minecraft%20Screenshots&privacy=hidden";
- QNetworkReply *rep = ENV.qnam().post(request, data);
+ QNetworkReply *rep = APPLICATION->network()->post(request, data);
m_reply.reset(rep);
connect(rep, &QNetworkReply::uploadProgress, this, &ImgurAlbumCreation::downloadProgress);
diff --git a/launcher/screenshots/ImgurAlbumCreation.h b/launcher/screenshots/ImgurAlbumCreation.h
index 954637e6..cb048a23 100644
--- a/launcher/screenshots/ImgurAlbumCreation.h
+++ b/launcher/screenshots/ImgurAlbumCreation.h
@@ -1,13 +1,14 @@
#pragma once
#include "net/NetAction.h"
#include "Screenshot.h"
+#include "QObjectPtr.h"
-typedef std::shared_ptr<class ImgurAlbumCreation> ImgurAlbumCreationPtr;
+typedef shared_qobject_ptr<class ImgurAlbumCreation> ImgurAlbumCreationPtr;
class ImgurAlbumCreation : public NetAction
{
public:
- explicit ImgurAlbumCreation(QList<ScreenshotPtr> screenshots);
- static ImgurAlbumCreationPtr make(QList<ScreenshotPtr> screenshots)
+ explicit ImgurAlbumCreation(QList<ScreenShot::Ptr> screenshots);
+ static ImgurAlbumCreationPtr make(QList<ScreenShot::Ptr> screenshots)
{
return ImgurAlbumCreationPtr(new ImgurAlbumCreation(screenshots));
}
@@ -32,10 +33,10 @@ slots:
public
slots:
- virtual void start();
+ virtual void startImpl();
private:
- QList<ScreenshotPtr> m_screenshots;
+ QList<ScreenShot::Ptr> m_screenshots;
QString m_deleteHash;
QString m_id;
diff --git a/launcher/screenshots/ImgurUpload.cpp b/launcher/screenshots/ImgurUpload.cpp
index 7e95d5ca..76a84947 100644
--- a/launcher/screenshots/ImgurUpload.cpp
+++ b/launcher/screenshots/ImgurUpload.cpp
@@ -1,4 +1,5 @@
#include "ImgurUpload.h"
+#include "BuildConfig.h"
#include <QNetworkRequest>
#include <QHttpMultiPart>
@@ -7,18 +8,15 @@
#include <QHttpPart>
#include <QFile>
#include <QUrl>
-
-#include "BuildConfig.h"
-#include "Env.h"
#include <QDebug>
-ImgurUpload::ImgurUpload(ScreenshotPtr shot) : NetAction(), m_shot(shot)
+ImgurUpload::ImgurUpload(ScreenShot::Ptr shot) : NetAction(), m_shot(shot)
{
m_url = BuildConfig.IMGUR_BASE_URL + "upload.json";
m_status = Job_NotStarted;
}
-void ImgurUpload::start()
+void ImgurUpload::startImpl()
{
finished = false;
m_status = Job_InProgress;
@@ -49,7 +47,7 @@ void ImgurUpload::start()
namePart.setBody(m_shot->m_file.baseName().toUtf8());
multipart->append(namePart);
- QNetworkReply *rep = ENV.qnam().post(request, multipart);
+ QNetworkReply *rep = m_network->post(request, multipart);
m_reply.reset(rep);
connect(rep, &QNetworkReply::uploadProgress, this, &ImgurUpload::downloadProgress);
diff --git a/launcher/screenshots/ImgurUpload.h b/launcher/screenshots/ImgurUpload.h
index 0507d499..cf54f58d 100644
--- a/launcher/screenshots/ImgurUpload.h
+++ b/launcher/screenshots/ImgurUpload.h
@@ -1,31 +1,29 @@
#pragma once
+#include "QObjectPtr.h"
#include "net/NetAction.h"
#include "Screenshot.h"
-typedef std::shared_ptr<class ImgurUpload> ImgurUploadPtr;
-class ImgurUpload : public NetAction
-{
+class ImgurUpload : public NetAction {
public:
- explicit ImgurUpload(ScreenshotPtr shot);
- static ImgurUploadPtr make(ScreenshotPtr shot)
- {
- return ImgurUploadPtr(new ImgurUpload(shot));
+ using Ptr = shared_qobject_ptr<ImgurUpload>;
+
+ explicit ImgurUpload(ScreenShot::Ptr shot);
+ static Ptr make(ScreenShot::Ptr shot) {
+ return Ptr(new ImgurUpload(shot));
}
protected
slots:
- virtual void downloadProgress(qint64 bytesReceived, qint64 bytesTotal);
- virtual void downloadError(QNetworkReply::NetworkError error);
- virtual void downloadFinished();
- virtual void downloadReadyRead()
- {
- }
+ void downloadProgress(qint64 bytesReceived, qint64 bytesTotal) override;
+ void downloadError(QNetworkReply::NetworkError error) override;
+ void downloadFinished() override;
+ void downloadReadyRead() override {}
public
slots:
- virtual void start();
+ void startImpl() override;
private:
- ScreenshotPtr m_shot;
+ ScreenShot::Ptr m_shot;
bool finished = true;
};
diff --git a/launcher/screenshots/Screenshot.h b/launcher/screenshots/Screenshot.h
index 9db3a8a1..ca45aabf 100644
--- a/launcher/screenshots/Screenshot.h
+++ b/launcher/screenshots/Screenshot.h
@@ -5,10 +5,10 @@
#include <QFileInfo>
#include <memory>
-struct ScreenShot
-{
- ScreenShot(QFileInfo file)
- {
+struct ScreenShot {
+ using Ptr = std::shared_ptr<ScreenShot>;
+
+ ScreenShot(QFileInfo file) {
m_file = file;
}
QFileInfo m_file;
@@ -16,5 +16,3 @@ struct ScreenShot
QString m_imgurId;
QString m_imgurDeleteHash;
};
-
-typedef std::shared_ptr<ScreenShot> ScreenshotPtr;
diff --git a/launcher/tasks/SequentialTask.cpp b/launcher/tasks/SequentialTask.cpp
index d0777132..a66b9d78 100644
--- a/launcher/tasks/SequentialTask.cpp
+++ b/launcher/tasks/SequentialTask.cpp
@@ -4,7 +4,7 @@ SequentialTask::SequentialTask(QObject *parent) : Task(parent), m_currentIndex(-
{
}
-void SequentialTask::addTask(std::shared_ptr<Task> task)
+void SequentialTask::addTask(Task::Ptr task)
{
m_queue.append(task);
}
@@ -19,7 +19,7 @@ void SequentialTask::startNext()
{
if (m_currentIndex != -1)
{
- std::shared_ptr<Task> previous = m_queue[m_currentIndex];
+ Task::Ptr previous = m_queue[m_currentIndex];
disconnect(previous.get(), 0, this, 0);
}
m_currentIndex++;
@@ -28,7 +28,7 @@ void SequentialTask::startNext()
emitSucceeded();
return;
}
- std::shared_ptr<Task> next = m_queue[m_currentIndex];
+ Task::Ptr next = m_queue[m_currentIndex];
connect(next.get(), SIGNAL(failed(QString)), this, SLOT(subTaskFailed(QString)));
connect(next.get(), SIGNAL(status(QString)), this, SLOT(subTaskStatus(QString)));
connect(next.get(), SIGNAL(progress(qint64, qint64)), this, SLOT(subTaskProgress(qint64, qint64)));
diff --git a/launcher/tasks/SequentialTask.h b/launcher/tasks/SequentialTask.h
index 6898c8a6..027744f3 100644
--- a/launcher/tasks/SequentialTask.h
+++ b/launcher/tasks/SequentialTask.h
@@ -1,9 +1,9 @@
#pragma once
#include "Task.h"
+#include "QObjectPtr.h"
#include <QQueue>
-#include <memory>
class SequentialTask : public Task
{
@@ -12,7 +12,7 @@ public:
explicit SequentialTask(QObject *parent = 0);
virtual ~SequentialTask() {};
- void addTask(std::shared_ptr<Task> task);
+ void addTask(Task::Ptr task);
protected:
void executeTask();
@@ -25,6 +25,6 @@ slots:
void subTaskProgress(qint64 current, qint64 total);
private:
- QQueue<std::shared_ptr<Task> > m_queue;
+ QQueue<Task::Ptr > m_queue;
int m_currentIndex;
};
diff --git a/launcher/tasks/Task.h b/launcher/tasks/Task.h
index 2367f1ec..9cf08dbd 100644
--- a/launcher/tasks/Task.h
+++ b/launcher/tasks/Task.h
@@ -19,10 +19,14 @@
#include <QString>
#include <QStringList>
+#include "QObjectPtr.h"
+
class Task : public QObject
{
Q_OBJECT
public:
+ using Ptr = shared_qobject_ptr<Task>;
+
enum class State
{
Inactive,
diff --git a/launcher/translations/TranslationsModel.cpp b/launcher/translations/TranslationsModel.cpp
index 29a952b0..576258eb 100644
--- a/launcher/translations/TranslationsModel.cpp
+++ b/launcher/translations/TranslationsModel.cpp
@@ -6,15 +6,17 @@
#include <QDir>
#include <QLibraryInfo>
#include <QDebug>
-#include <FileSystem.h>
-#include <net/NetJob.h>
-#include <net/ChecksumValidator.h>
-#include <Env.h>
-#include <BuildConfig.h>
+
+#include "FileSystem.h"
+#include "net/NetJob.h"
+#include "net/ChecksumValidator.h"
+#include "BuildConfig.h"
#include "Json.h"
#include "POTranslator.h"
+#include "Application.h"
+
const static QLatin1Literal defaultLangCode("en_US");
enum class FileType
@@ -37,6 +39,20 @@ struct Language
updated = (key == defaultLangCode);
}
+ QString languageName() const {
+ QString result;
+ if(key == "ja_KANJI") {
+ result = locale.nativeLanguageName() + u8" (漢字)";
+ }
+ else if(key == "es_UY") {
+ result = u8"español de Latinoamérica";
+ }
+ else {
+ result = locale.nativeLanguageName();
+ }
+ return result;
+ }
+
float percentTranslated() const
{
if (total == 0)
@@ -119,10 +135,10 @@ struct TranslationsModel::Private
std::unique_ptr<QTranslator> m_qt_translator;
std::unique_ptr<QTranslator> m_app_translator;
- std::shared_ptr<Net::Download> m_index_task;
+ Net::Download::Ptr m_index_task;
QString m_downloadingTranslation;
- NetJobPtr m_dl_job;
- NetJobPtr m_index_job;
+ NetJob::Ptr m_dl_job;
+ NetJob::Ptr m_index_job;
QString m_nextDownload;
std::unique_ptr<POTranslator> m_po_translator;
@@ -338,7 +354,7 @@ QVariant TranslationsModel::data(const QModelIndex& index, int role) const
{
case Column::Language:
{
- return lang.locale.nativeLanguageName();
+ return lang.languageName();
}
case Column::Completeness:
{
@@ -558,13 +574,13 @@ void TranslationsModel::downloadIndex()
}
qDebug() << "Downloading Translations Index...";
d->m_index_job.reset(new NetJob("Translations Index"));
- MetaEntryPtr entry = ENV.metacache()->resolveEntry("translations", "index_v2.json");
+ MetaEntryPtr entry = APPLICATION->metacache()->resolveEntry("translations", "index_v2.json");
entry->setStale(true);
d->m_index_task = Net::Download::makeCached(QUrl("https://files.multimc.org/translations/index_v2.json"), entry);
d->m_index_job->addNetAction(d->m_index_task);
connect(d->m_index_job.get(), &NetJob::failed, this, &TranslationsModel::indexFailed);
connect(d->m_index_job.get(), &NetJob::succeeded, this, &TranslationsModel::indexReceived);
- d->m_index_job->start();
+ d->m_index_job->start(APPLICATION->network());
}
void TranslationsModel::updateLanguage(QString key)
@@ -601,7 +617,7 @@ void TranslationsModel::downloadTranslation(QString key)
}
d->m_downloadingTranslation = key;
- MetaEntryPtr entry = ENV.metacache()->resolveEntry("translations", "mmc_" + key + ".qm");
+ MetaEntryPtr entry = APPLICATION->metacache()->resolveEntry("translations", "mmc_" + key + ".qm");
entry->setStale(true);
auto dl = Net::Download::makeCached(QUrl(BuildConfig.TRANSLATIONS_BASE_URL + lang->file_name), entry);
@@ -615,7 +631,7 @@ void TranslationsModel::downloadTranslation(QString key)
connect(d->m_dl_job.get(), &NetJob::succeeded, this, &TranslationsModel::dlGood);
connect(d->m_dl_job.get(), &NetJob::failed, this, &TranslationsModel::dlFailed);
- d->m_dl_job->start();
+ d->m_dl_job->start(APPLICATION->network());
}
void TranslationsModel::downloadNext()
diff --git a/launcher/ColorCache.cpp b/launcher/ui/ColorCache.cpp
index ef268dd2..ef268dd2 100644
--- a/launcher/ColorCache.cpp
+++ b/launcher/ui/ColorCache.cpp
diff --git a/launcher/ColorCache.h b/launcher/ui/ColorCache.h
index a840664d..a840664d 100644
--- a/launcher/ColorCache.h
+++ b/launcher/ui/ColorCache.h
diff --git a/launcher/GuiUtil.cpp b/launcher/ui/GuiUtil.cpp
index 3dd31c7a..efb1a4df 100644
--- a/launcher/GuiUtil.cpp
+++ b/launcher/ui/GuiUtil.cpp
@@ -4,11 +4,11 @@
#include <QApplication>
#include <QFileDialog>
-#include "dialogs/ProgressDialog.h"
+#include "ui/dialogs/ProgressDialog.h"
+#include "ui/dialogs/CustomMessageBox.h"
#include "net/PasteUpload.h"
-#include "dialogs/CustomMessageBox.h"
-#include "Launcher.h"
+#include "Application.h"
#include <settings/SettingsObject.h>
#include <DesktopServices.h>
#include <BuildConfig.h>
@@ -16,7 +16,7 @@
QString GuiUtil::uploadPaste(const QString &text, QWidget *parentWidget)
{
ProgressDialog dialog(parentWidget);
- auto APIKeySetting = LAUNCHER->settings()->get("PasteEEAPIKey").toString();
+ auto APIKeySetting = APPLICATION->settings()->get("PasteEEAPIKey").toString();
if(APIKeySetting == "multimc")
{
APIKeySetting = BuildConfig.PASTE_EE_KEY;
@@ -35,8 +35,12 @@ QString GuiUtil::uploadPaste(const QString &text, QWidget *parentWidget)
dialog.execWithTask(paste.get());
if (!paste->wasSuccessful())
{
- CustomMessageBox::selectable(parentWidget, QObject::tr("Upload failed"),
- paste->failReason(), QMessageBox::Critical)->exec();
+ CustomMessageBox::selectable(
+ parentWidget,
+ QObject::tr("Upload failed"),
+ paste->failReason(),
+ QMessageBox::Critical
+ )->exec();
return QString();
}
else
@@ -66,8 +70,9 @@ static QStringList BrowseForFileInternal(QString context, QString caption, QStri
{
QString location = QStandardPaths::writableLocation(l);
QFileInfo finfo(location);
- if (!finfo.exists())
+ if (!finfo.exists()) {
return;
+ }
locations.insert(location);
};
f(QStandardPaths::DesktopLocation);
diff --git a/launcher/GuiUtil.h b/launcher/ui/GuiUtil.h
index 5e109383..5e109383 100644
--- a/launcher/GuiUtil.h
+++ b/launcher/ui/GuiUtil.h
diff --git a/launcher/InstanceWindow.cpp b/launcher/ui/InstanceWindow.cpp
index 8f73671b..ae765c3c 100644
--- a/launcher/InstanceWindow.cpp
+++ b/launcher/ui/InstanceWindow.cpp
@@ -14,7 +14,7 @@
*/
#include "InstanceWindow.h"
-#include "Launcher.h"
+#include "Application.h"
#include <QScrollBar>
#include <QMessageBox>
@@ -23,9 +23,10 @@
#include <qlayoutitem.h>
#include <QCloseEvent>
-#include <dialogs/CustomMessageBox.h>
-#include <dialogs/ProgressDialog.h>
-#include "widgets/PageContainer.h"
+#include "ui/dialogs/CustomMessageBox.h"
+#include "ui/dialogs/ProgressDialog.h"
+#include "ui/widgets/PageContainer.h"
+
#include "InstancePageProvider.h"
#include "icons/IconList.h"
@@ -35,7 +36,7 @@ InstanceWindow::InstanceWindow(InstancePtr instance, QWidget *parent)
{
setAttribute(Qt::WA_DeleteOnClose);
- auto icon = LAUNCHER->icons()->getIcon(m_instance->iconKey());
+ auto icon = APPLICATION->icons()->getIcon(m_instance->iconKey());
QString windowTitle = tr("Console window for ") + m_instance->name();
// Set window properties
@@ -87,9 +88,9 @@ InstanceWindow::InstanceWindow(InstancePtr instance, QWidget *parent)
// restore window state
{
- auto base64State = LAUNCHER->settings()->get("ConsoleWindowState").toByteArray();
+ auto base64State = APPLICATION->settings()->get("ConsoleWindowState").toByteArray();
restoreState(QByteArray::fromBase64(base64State));
- auto base64Geometry = LAUNCHER->settings()->get("ConsoleWindowGeometry").toByteArray();
+ auto base64Geometry = APPLICATION->settings()->get("ConsoleWindowGeometry").toByteArray();
restoreGeometry(QByteArray::fromBase64(base64Geometry));
}
@@ -148,7 +149,7 @@ void InstanceWindow::updateLaunchButtons()
void InstanceWindow::on_btnLaunchMinecraftOffline_clicked()
{
- LAUNCHER->launch(m_instance, false, nullptr);
+ APPLICATION->launch(m_instance, false, nullptr);
}
void InstanceWindow::on_InstanceLaunchTask_changed(shared_qobject_ptr<LaunchTask> proc)
@@ -183,8 +184,8 @@ void InstanceWindow::closeEvent(QCloseEvent *event)
return;
}
- LAUNCHER->settings()->set("ConsoleWindowState", saveState().toBase64());
- LAUNCHER->settings()->set("ConsoleWindowGeometry", saveGeometry().toBase64());
+ APPLICATION->settings()->set("ConsoleWindowState", saveState().toBase64());
+ APPLICATION->settings()->set("ConsoleWindowGeometry", saveGeometry().toBase64());
emit isClosing();
event->accept();
}
@@ -198,11 +199,11 @@ void InstanceWindow::on_btnKillMinecraft_clicked()
{
if(m_instance->isRunning())
{
- LAUNCHER->kill(m_instance);
+ APPLICATION->kill(m_instance);
}
else
{
- LAUNCHER->launch(m_instance, true, nullptr);
+ APPLICATION->launch(m_instance, true, nullptr);
}
}
diff --git a/launcher/InstanceWindow.h b/launcher/ui/InstanceWindow.h
index cd7d2494..1acf684e 100644
--- a/launcher/InstanceWindow.h
+++ b/launcher/ui/InstanceWindow.h
@@ -16,11 +16,14 @@
#pragma once
#include <QMainWindow>
-#include "LaunchController.h"
-#include <QObjectPtr.h>
#include <QSystemTrayIcon>
+
+#include "LaunchController.h"
#include "launch/LaunchTask.h"
-#include "pages/BasePageContainer.h"
+
+#include "ui/pages/BasePageContainer.h"
+
+#include "QObjectPtr.h"
class QPushButton;
class PageContainer;
diff --git a/launcher/MainWindow.cpp b/launcher/ui/MainWindow.cpp
index 21502894..b06f3d5a 100644
--- a/launcher/MainWindow.cpp
+++ b/launcher/ui/MainWindow.cpp
@@ -16,7 +16,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#include "Launcher.h"
+#include "Application.h"
#include "BuildConfig.h"
#include "MainWindow.h"
@@ -47,7 +47,6 @@
#include <QtWidgets/QShortcut>
#include <BaseInstance.h>
-#include <Env.h>
#include <InstanceList.h>
#include <MMCZip.h>
#include <icons/IconList.h>
@@ -67,27 +66,31 @@
#include <DesktopServices.h>
#include "InstanceWindow.h"
#include "InstancePageProvider.h"
-#include "instanceview/InstanceProxyModel.h"
#include "JavaCommon.h"
#include "LaunchController.h"
-#include "instanceview/InstanceView.h"
-#include "instanceview/InstanceDelegate.h"
-#include "widgets/LabeledToolButton.h"
-#include "dialogs/NewInstanceDialog.h"
-#include "dialogs/ProgressDialog.h"
-#include "dialogs/AboutDialog.h"
-#include "dialogs/VersionSelectDialog.h"
-#include "dialogs/CustomMessageBox.h"
-#include "dialogs/IconPickerDialog.h"
-#include "dialogs/CopyInstanceDialog.h"
-#include "dialogs/UpdateDialog.h"
-#include "dialogs/EditAccountDialog.h"
-#include "dialogs/NotificationDialog.h"
-#include "dialogs/ExportInstanceDialog.h"
-#include <InstanceImportTask.h>
+
+#include "ui/instanceview/InstanceProxyModel.h"
+#include "ui/instanceview/InstanceView.h"
+#include "ui/instanceview/InstanceDelegate.h"
+#include "ui/widgets/LabeledToolButton.h"
+#include "ui/dialogs/NewInstanceDialog.h"
+#include "ui/dialogs/ProgressDialog.h"
+#include "ui/dialogs/AboutDialog.h"
+#include "ui/dialogs/VersionSelectDialog.h"
+#include "ui/dialogs/CustomMessageBox.h"
+#include "ui/dialogs/IconPickerDialog.h"
+#include "ui/dialogs/CopyInstanceDialog.h"
+#include "ui/dialogs/UpdateDialog.h"
+#include "ui/dialogs/EditAccountDialog.h"
+#include "ui/dialogs/NotificationDialog.h"
+#include "ui/dialogs/ExportInstanceDialog.h"
+
#include "UpdateController.h"
#include "KonamiCode.h"
-#include <InstanceCopyTask.h>
+
+#include "InstanceImportTask.h"
+#include "InstanceCopyTask.h"
+
#include "MMCTime.h"
namespace {
@@ -208,8 +211,10 @@ public:
TranslatedAction actionEditInstNotes;
TranslatedAction actionEditInstance;
TranslatedAction actionWorlds;
+ TranslatedAction actionMods;
TranslatedAction actionViewSelectedInstFolder;
TranslatedAction actionViewSelectedMCFolder;
+ TranslatedAction actionViewSelectedModsFolder;
TranslatedAction actionDeleteInstance;
TranslatedAction actionConfig_Folder;
TranslatedAction actionCAT;
@@ -278,7 +283,7 @@ public:
actionAddInstance = TranslatedAction(MainWindow);
actionAddInstance->setObjectName(QStringLiteral("actionAddInstance"));
- actionAddInstance->setIcon(LAUNCHER->getThemedIcon("new"));
+ actionAddInstance->setIcon(APPLICATION->getThemedIcon("new"));
actionAddInstance.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Add Instance"));
actionAddInstance.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Add a new instance."));
all_actions.append(&actionAddInstance);
@@ -291,7 +296,7 @@ public:
actionViewInstanceFolder = TranslatedAction(MainWindow);
actionViewInstanceFolder->setObjectName(QStringLiteral("actionViewInstanceFolder"));
- actionViewInstanceFolder->setIcon(LAUNCHER->getThemedIcon("viewfolder"));
+ actionViewInstanceFolder->setIcon(APPLICATION->getThemedIcon("viewfolder"));
actionViewInstanceFolder.setTextId(QT_TRANSLATE_NOOP("MainWindow", "View Instance Folder"));
actionViewInstanceFolder.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Open the instance folder in a file browser."));
all_actions.append(&actionViewInstanceFolder);
@@ -299,7 +304,7 @@ public:
actionViewCentralModsFolder = TranslatedAction(MainWindow);
actionViewCentralModsFolder->setObjectName(QStringLiteral("actionViewCentralModsFolder"));
- actionViewCentralModsFolder->setIcon(LAUNCHER->getThemedIcon("centralmods"));
+ actionViewCentralModsFolder->setIcon(APPLICATION->getThemedIcon("centralmods"));
actionViewCentralModsFolder.setTextId(QT_TRANSLATE_NOOP("MainWindow", "View Central Mods Folder"));
actionViewCentralModsFolder.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Open the central mods folder in a file browser."));
all_actions.append(&actionViewCentralModsFolder);
@@ -311,7 +316,7 @@ public:
foldersMenuButton->setMenu(foldersMenu);
foldersMenuButton->setPopupMode(QToolButton::InstantPopup);
foldersMenuButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
- foldersMenuButton->setIcon(LAUNCHER->getThemedIcon("viewfolder"));
+ foldersMenuButton->setIcon(APPLICATION->getThemedIcon("viewfolder"));
foldersMenuButton->setFocusPolicy(Qt::NoFocus);
all_toolbuttons.append(&foldersMenuButton);
QWidgetAction* foldersButtonAction = new QWidgetAction(MainWindow);
@@ -320,7 +325,7 @@ public:
actionSettings = TranslatedAction(MainWindow);
actionSettings->setObjectName(QStringLiteral("actionSettings"));
- actionSettings->setIcon(LAUNCHER->getThemedIcon("settings"));
+ actionSettings->setIcon(APPLICATION->getThemedIcon("settings"));
actionSettings->setMenuRole(QAction::PreferencesRole);
actionSettings.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Settings"));
actionSettings.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Change settings."));
@@ -333,7 +338,7 @@ public:
if (!BuildConfig.BUG_TRACKER_URL.isEmpty()) {
actionReportBug = TranslatedAction(MainWindow);
actionReportBug->setObjectName(QStringLiteral("actionReportBug"));
- actionReportBug->setIcon(LAUNCHER->getThemedIcon("bug"));
+ actionReportBug->setIcon(APPLICATION->getThemedIcon("bug"));
actionReportBug.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Report a Bug"));
actionReportBug.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Open the bug tracker to report a bug with %1."));
all_actions.append(&actionReportBug);
@@ -343,7 +348,7 @@ public:
if (!BuildConfig.DISCORD_URL.isEmpty()) {
actionDISCORD = TranslatedAction(MainWindow);
actionDISCORD->setObjectName(QStringLiteral("actionDISCORD"));
- actionDISCORD->setIcon(LAUNCHER->getThemedIcon("discord"));
+ actionDISCORD->setIcon(APPLICATION->getThemedIcon("discord"));
actionDISCORD.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Discord"));
actionDISCORD.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Open %1 discord voice chat."));
all_actions.append(&actionDISCORD);
@@ -353,7 +358,7 @@ public:
if (!BuildConfig.SUBREDDIT_URL.isEmpty()) {
actionREDDIT = TranslatedAction(MainWindow);
actionREDDIT->setObjectName(QStringLiteral("actionREDDIT"));
- actionREDDIT->setIcon(LAUNCHER->getThemedIcon("reddit-alien"));
+ actionREDDIT->setIcon(APPLICATION->getThemedIcon("reddit-alien"));
actionREDDIT.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Reddit"));
actionREDDIT.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Open %1 subreddit."));
all_actions.append(&actionREDDIT);
@@ -362,7 +367,7 @@ public:
actionAbout = TranslatedAction(MainWindow);
actionAbout->setObjectName(QStringLiteral("actionAbout"));
- actionAbout->setIcon(LAUNCHER->getThemedIcon("about"));
+ actionAbout->setIcon(APPLICATION->getThemedIcon("about"));
actionAbout->setMenuRole(QAction::AboutRole);
actionAbout.setTextId(QT_TRANSLATE_NOOP("MainWindow", "About %1"));
actionAbout.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "View information about %1."));
@@ -375,7 +380,7 @@ public:
helpMenuButton->setMenu(helpMenu);
helpMenuButton->setPopupMode(QToolButton::InstantPopup);
helpMenuButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
- helpMenuButton->setIcon(LAUNCHER->getThemedIcon("help"));
+ helpMenuButton->setIcon(APPLICATION->getThemedIcon("help"));
helpMenuButton->setFocusPolicy(Qt::NoFocus);
all_toolbuttons.append(&helpMenuButton);
QWidgetAction* helpButtonAction = new QWidgetAction(MainWindow);
@@ -386,7 +391,7 @@ public:
{
actionCheckUpdate = TranslatedAction(MainWindow);
actionCheckUpdate->setObjectName(QStringLiteral("actionCheckUpdate"));
- actionCheckUpdate->setIcon(LAUNCHER->getThemedIcon("checkupdate"));
+ actionCheckUpdate->setIcon(APPLICATION->getThemedIcon("checkupdate"));
actionCheckUpdate.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Update"));
actionCheckUpdate.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Check for new updates for %1."));
all_actions.append(&actionCheckUpdate);
@@ -397,7 +402,7 @@ public:
actionPatreon = TranslatedAction(MainWindow);
actionPatreon->setObjectName(QStringLiteral("actionPatreon"));
- actionPatreon->setIcon(LAUNCHER->getThemedIcon("patreon"));
+ actionPatreon->setIcon(APPLICATION->getThemedIcon("patreon"));
actionPatreon.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Support %1"));
actionPatreon.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Open the %1 Patreon page."));
all_actions.append(&actionPatreon);
@@ -406,7 +411,7 @@ public:
actionCAT = TranslatedAction(MainWindow);
actionCAT->setObjectName(QStringLiteral("actionCAT"));
actionCAT->setCheckable(true);
- actionCAT->setIcon(LAUNCHER->getThemedIcon("cat"));
+ actionCAT->setIcon(APPLICATION->getThemedIcon("cat"));
actionCAT.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Meow"));
actionCAT.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "It's a fluffy kitty :3"));
actionCAT->setPriority(QAction::LowPriority);
@@ -419,7 +424,7 @@ public:
actionManageAccounts.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Manage Accounts"));
// FIXME: no tooltip!
actionManageAccounts->setCheckable(false);
- actionManageAccounts->setIcon(LAUNCHER->getThemedIcon("accounts"));
+ actionManageAccounts->setIcon(APPLICATION->getThemedIcon("accounts"));
all_actions.append(&actionManageAccounts);
all_toolbars.append(&mainToolBar);
@@ -446,7 +451,7 @@ public:
actionMoreNews = TranslatedAction(MainWindow);
actionMoreNews->setObjectName(QStringLiteral("actionMoreNews"));
- actionMoreNews->setIcon(LAUNCHER->getThemedIcon("news"));
+ actionMoreNews->setIcon(APPLICATION->getThemedIcon("news"));
actionMoreNews.setTextId(QT_TRANSLATE_NOOP("MainWindow", "More news..."));
actionMoreNews.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Open the development blog to read more news about %1."));
all_actions.append(&actionMoreNews);
@@ -478,7 +483,7 @@ public:
changeIconButton = new LabeledToolButton(MainWindow);
changeIconButton->setObjectName(QStringLiteral("changeIconButton"));
- changeIconButton->setIcon(LAUNCHER->getThemedIcon("news"));
+ changeIconButton->setIcon(APPLICATION->getThemedIcon("news"));
changeIconButton->setToolTip(actionChangeInstIcon->toolTip());
changeIconButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
instanceToolBar->addWidget(changeIconButton);
@@ -527,6 +532,13 @@ public:
all_actions.append(&actionEditInstNotes);
instanceToolBar->addAction(actionEditInstNotes);
+ actionMods = TranslatedAction(MainWindow);
+ actionMods->setObjectName(QStringLiteral("actionMods"));
+ actionMods.setTextId(QT_TRANSLATE_NOOP("MainWindow", "View Mods"));
+ actionMods.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "View the mods of this instance."));
+ all_actions.append(&actionMods);
+ instanceToolBar->addAction(actionMods);
+
actionWorlds = TranslatedAction(MainWindow);
actionWorlds->setObjectName(QStringLiteral("actionWorlds"));
actionWorlds.setTextId(QT_TRANSLATE_NOOP("MainWindow", "View Worlds"));
@@ -557,6 +569,15 @@ public:
all_actions.append(&actionViewSelectedMCFolder);
instanceToolBar->addAction(actionViewSelectedMCFolder);
+ /*
+ actionViewSelectedModsFolder = TranslatedAction(MainWindow);
+ actionViewSelectedModsFolder->setObjectName(QStringLiteral("actionViewSelectedModsFolder"));
+ actionViewSelectedModsFolder.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Mods Folder"));
+ actionViewSelectedModsFolder.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Open the selected instance's mods folder in a file browser."));
+ all_actions.append(&actionViewSelectedModsFolder);
+ instanceToolBar->addAction(actionViewSelectedModsFolder);
+ */
+
actionConfig_Folder = TranslatedAction(MainWindow);
actionConfig_Folder->setObjectName(QStringLiteral("actionConfig_Folder"));
actionConfig_Folder.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Config Folder"));
@@ -589,7 +610,7 @@ public:
actionCopyInstance = TranslatedAction(MainWindow);
actionCopyInstance->setObjectName(QStringLiteral("actionCopyInstance"));
- actionCopyInstance->setIcon(LAUNCHER->getThemedIcon("copy"));
+ actionCopyInstance->setIcon(APPLICATION->getThemedIcon("copy"));
actionCopyInstance.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Copy Instance"));
actionCopyInstance.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Copy the selected instance."));
all_actions.append(&actionCopyInstance);
@@ -606,7 +627,7 @@ public:
MainWindow->setObjectName(QStringLiteral("MainWindow"));
}
MainWindow->resize(800, 600);
- MainWindow->setWindowIcon(LAUNCHER->getThemedIcon("logo"));
+ MainWindow->setWindowIcon(APPLICATION->getThemedIcon("logo"));
MainWindow->setWindowTitle(BuildConfig.LAUNCHER_DISPLAYNAME);
#ifndef QT_NO_ACCESSIBILITY
MainWindow->setAccessibleName(BuildConfig.LAUNCHER_NAME);
@@ -681,9 +702,9 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new MainWindow
// Add the news label to the news toolbar.
{
- m_newsChecker.reset(new NewsChecker(BuildConfig.NEWS_RSS_URL));
+ m_newsChecker.reset(new NewsChecker(APPLICATION->network(), BuildConfig.NEWS_RSS_URL));
newsLabel = new QToolButton();
- newsLabel->setIcon(LAUNCHER->getThemedIcon("news"));
+ newsLabel->setIcon(APPLICATION->getThemedIcon("news"));
newsLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
newsLabel->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
newsLabel->setFocusPolicy(Qt::NoFocus);
@@ -710,20 +731,20 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new MainWindow
connect(view, &InstanceView::droppedURLs, this, &MainWindow::droppedURLs, Qt::QueuedConnection);
proxymodel = new InstanceProxyModel(this);
- proxymodel->setSourceModel(LAUNCHER->instances().get());
+ proxymodel->setSourceModel(APPLICATION->instances().get());
proxymodel->sort(0);
connect(proxymodel, &InstanceProxyModel::dataChanged, this, &MainWindow::instanceDataChanged);
view->setModel(proxymodel);
view->setSourceOfGroupCollapseStatus([](const QString & groupName)->bool {
- return LAUNCHER->instances()->isGroupCollapsed(groupName);
+ return APPLICATION->instances()->isGroupCollapsed(groupName);
});
- connect(view, &InstanceView::groupStateChanged, LAUNCHER->instances().get(), &InstanceList::on_GroupStateChanged);
+ connect(view, &InstanceView::groupStateChanged, APPLICATION->instances().get(), &InstanceList::on_GroupStateChanged);
ui->horizontalLayout->addWidget(view);
}
// The cat background
{
- bool cat_enable = LAUNCHER->settings()->get("TheCat").toBool();
+ bool cat_enable = APPLICATION->settings()->get("TheCat").toBool();
ui->actionCAT->setChecked(cat_enable);
// NOTE: calling the operator like that is an ugly hack to appease ancient gcc...
connect(ui->actionCAT.operator->(), SIGNAL(toggled(bool)), SLOT(onCatToggled(bool)));
@@ -736,16 +757,16 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new MainWindow
connect(view->selectionModel(), &QItemSelectionModel::currentChanged, this, &MainWindow::instanceChanged);
// track icon changes and update the toolbar!
- connect(LAUNCHER->icons().get(), &IconList::iconUpdated, this, &MainWindow::iconUpdated);
+ connect(APPLICATION->icons().get(), &IconList::iconUpdated, this, &MainWindow::iconUpdated);
// model reset -> selection is invalid. All the instance pointers are wrong.
- connect(LAUNCHER->instances().get(), &InstanceList::dataIsInvalid, this, &MainWindow::selectionBad);
+ connect(APPLICATION->instances().get(), &InstanceList::dataIsInvalid, this, &MainWindow::selectionBad);
// handle newly added instances
- connect(LAUNCHER->instances().get(), &InstanceList::instanceSelectRequest, this, &MainWindow::instanceSelectRequest);
+ connect(APPLICATION->instances().get(), &InstanceList::instanceSelectRequest, this, &MainWindow::instanceSelectRequest);
// When the global settings page closes, we want to know about it and update our state
- connect(LAUNCHER, &Launcher::globalSettingsClosed, this, &MainWindow::globalSettingsClosed);
+ connect(APPLICATION, &Application::globalSettingsClosed, this, &MainWindow::globalSettingsClosed);
m_statusLeft = new QLabel(tr("No instance selected"), this);
m_statusCenter = new QLabel(tr("Total playtime: 0s"), this);
@@ -765,7 +786,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new MainWindow
accountMenuButton->setMenu(accountMenu);
accountMenuButton->setPopupMode(QToolButton::InstantPopup);
accountMenuButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
- accountMenuButton->setIcon(LAUNCHER->getThemedIcon("noaccount"));
+ accountMenuButton->setIcon(APPLICATION->getThemedIcon("noaccount"));
QWidgetAction *accountMenuButtonAction = new QWidgetAction(this);
accountMenuButtonAction->setDefaultWidget(accountMenuButton);
@@ -776,14 +797,14 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new MainWindow
// Shouldn't have to use lambdas here like this, but if I don't, the compiler throws a fit.
// Template hell sucks...
connect(
- LAUNCHER->accounts().get(),
- &AccountList::activeAccountChanged,
+ APPLICATION->accounts().get(),
+ &AccountList::defaultAccountChanged,
[this] {
- activeAccountChanged();
+ defaultAccountChanged();
}
);
connect(
- LAUNCHER->accounts().get(),
+ APPLICATION->accounts().get(),
&AccountList::listChanged,
[this]
{
@@ -792,10 +813,10 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new MainWindow
);
// Show initial account
- activeAccountChanged();
+ defaultAccountChanged();
// TODO: refresh accounts here?
- // auto accounts = LAUNCHER->accounts();
+ // auto accounts = APPLICATION->accounts();
// load the news
{
@@ -806,20 +827,20 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new MainWindow
if(BuildConfig.UPDATER_ENABLED)
{
- bool updatesAllowed = LAUNCHER->updatesAreAllowed();
+ bool updatesAllowed = APPLICATION->updatesAreAllowed();
updatesAllowedChanged(updatesAllowed);
// NOTE: calling the operator like that is an ugly hack to appease ancient gcc...
connect(ui->actionCheckUpdate.operator->(), &QAction::triggered, this, &MainWindow::checkForUpdates);
// set up the updater object.
- auto updater = LAUNCHER->updateChecker();
+ auto updater = APPLICATION->updateChecker();
connect(updater.get(), &UpdateChecker::updateAvailable, this, &MainWindow::updateAvailable);
connect(updater.get(), &UpdateChecker::noUpdateFound, this, &MainWindow::updateNotAvailable);
// if automatic update checks are allowed, start one.
- if (LAUNCHER->settings()->get("AutoUpdate").toBool() && updatesAllowed)
+ if (APPLICATION->settings()->get("AutoUpdate").toBool() && updatesAllowed)
{
- updater->checkForUpdate(LAUNCHER->settings()->get("UpdateChannel").toString(), false);
+ updater->checkForUpdate(APPLICATION->settings()->get("UpdateChannel").toString(), false);
}
}
@@ -834,7 +855,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new MainWindow
checker->checkForNotifications();
}
- setSelectedInstanceById(LAUNCHER->settings()->get("SelectedInstance").toString());
+ setSelectedInstanceById(APPLICATION->settings()->get("SelectedInstance").toString());
// removing this looks stupid
view->setFocus();
@@ -844,10 +865,10 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new MainWindow
void MainWindow::retranslateUi()
{
- std::shared_ptr<AccountList> accounts = LAUNCHER->accounts();
- MinecraftAccountPtr active_account = accounts->activeAccount();
- if(active_account) {
- auto profileLabel = profileInUseFilter(active_account->profileName(), active_account->isInUse());
+ auto accounts = APPLICATION->accounts();
+ MinecraftAccountPtr defaultAccount = accounts->defaultAccount();
+ if(defaultAccount) {
+ auto profileLabel = profileInUseFilter(defaultAccount->profileName(), defaultAccount->isInUse());
accountMenuButton->setText(profileLabel);
}
else {
@@ -876,7 +897,6 @@ QMenu * MainWindow::createPopupMenu()
void MainWindow::konamiTriggered()
{
- // ENV.enableFeature("NewModsPage");
qDebug() << "Super Secret Mode ACTIVATED!";
}
@@ -982,16 +1002,16 @@ void MainWindow::updateToolsMenu()
QAction *normalLaunchOffline = launchOfflineMenu->addAction(tr("Launch Offline"));
connect(normalLaunch, &QAction::triggered, [this]()
{
- LAUNCHER->launch(m_selectedInstance, true);
+ APPLICATION->launch(m_selectedInstance, true);
});
connect(normalLaunchOffline, &QAction::triggered, [this]()
{
- LAUNCHER->launch(m_selectedInstance, false);
+ APPLICATION->launch(m_selectedInstance, false);
});
QString profilersTitle = tr("Profilers");
launchMenu->addSeparator()->setText(profilersTitle);
launchOfflineMenu->addSeparator()->setText(profilersTitle);
- for (auto profiler : LAUNCHER->profilers().values())
+ for (auto profiler : APPLICATION->profilers().values())
{
QAction *profilerAction = launchMenu->addAction(profiler->name());
QAction *profilerOfflineAction = launchOfflineMenu->addAction(profiler->name());
@@ -1008,11 +1028,11 @@ void MainWindow::updateToolsMenu()
{
connect(profilerAction, &QAction::triggered, [this, profiler]()
{
- LAUNCHER->launch(m_selectedInstance, true, profiler.get());
+ APPLICATION->launch(m_selectedInstance, true, profiler.get());
});
connect(profilerOfflineAction, &QAction::triggered, [this, profiler]()
{
- LAUNCHER->launch(m_selectedInstance, false, profiler.get());
+ APPLICATION->launch(m_selectedInstance, false, profiler.get());
});
}
}
@@ -1024,17 +1044,16 @@ void MainWindow::repopulateAccountsMenu()
{
accountMenu->clear();
- std::shared_ptr<AccountList> accounts = LAUNCHER->accounts();
- MinecraftAccountPtr active_account = accounts->activeAccount();
+ auto accounts = APPLICATION->accounts();
+ MinecraftAccountPtr defaultAccount = accounts->defaultAccount();
QString active_profileId = "";
- if (active_account != nullptr)
+ if (defaultAccount)
{
- active_profileId = active_account->profileId();
// this can be called before accountMenuButton exists
if (accountMenuButton)
{
- auto profileLabel = profileInUseFilter(active_account->profileName(), active_account->isInUse());
+ auto profileLabel = profileInUseFilter(defaultAccount->profileName(), defaultAccount->isInUse());
accountMenuButton->setText(profileLabel);
}
}
@@ -1053,14 +1072,20 @@ void MainWindow::repopulateAccountsMenu()
MinecraftAccountPtr account = accounts->at(i);
auto profileLabel = profileInUseFilter(account->profileName(), account->isInUse());
QAction *action = new QAction(profileLabel, this);
- action->setData(account->profileId());
+ action->setData(i);
action->setCheckable(true);
- if (active_profileId == account->profileId())
+ if (defaultAccount == account)
{
action->setChecked(true);
}
- action->setIcon(account->getFace());
+ auto face = account->getFace();
+ if(!face.isNull()) {
+ action->setIcon(face);
+ }
+ else {
+ action->setIcon(APPLICATION->getThemedIcon("noaccount"));
+ }
accountMenu->addAction(action);
connect(action, SIGNAL(triggered(bool)), SLOT(changeActiveAccount()));
}
@@ -1070,9 +1095,9 @@ void MainWindow::repopulateAccountsMenu()
QAction *action = new QAction(tr("No Default Account"), this);
action->setCheckable(true);
- action->setIcon(LAUNCHER->getThemedIcon("noaccount"));
- action->setData("");
- if (active_profileId.isEmpty()) {
+ action->setIcon(APPLICATION->getThemedIcon("noaccount"));
+ action->setData(-1);
+ if (!defaultAccount) {
action->setChecked(true);
}
@@ -1098,40 +1123,45 @@ void MainWindow::updatesAllowedChanged(bool allowed)
void MainWindow::changeActiveAccount()
{
QAction *sAction = (QAction *)sender();
+
// Profile's associated Mojang username
- // Will need to change when profiles are properly implemented
- if (sAction->data().type() != QVariant::Type::String)
+ if (sAction->data().type() != QVariant::Type::Int)
return;
QVariant data = sAction->data();
- QString id = "";
- if (!data.isNull())
- {
- id = data.toString();
+ bool valid = false;
+ int index = data.toInt(&valid);
+ if(!valid) {
+ index = -1;
}
-
- LAUNCHER->accounts()->setActiveAccount(id);
-
- activeAccountChanged();
+ auto accounts = APPLICATION->accounts();
+ accounts->setDefaultAccount(index == -1 ? nullptr : accounts->at(index));
+ defaultAccountChanged();
}
-void MainWindow::activeAccountChanged()
+void MainWindow::defaultAccountChanged()
{
repopulateAccountsMenu();
- MinecraftAccountPtr account = LAUNCHER->accounts()->activeAccount();
+ MinecraftAccountPtr account = APPLICATION->accounts()->defaultAccount();
// FIXME: this needs adjustment for MSA
- if (account != nullptr && account->profileName() != "")
+ if (account && account->profileName() != "")
{
auto profileLabel = profileInUseFilter(account->profileName(), account->isInUse());
accountMenuButton->setText(profileLabel);
- accountMenuButton->setIcon(account->getFace());
+ auto face = account->getFace();
+ if(face.isNull()) {
+ accountMenuButton->setIcon(APPLICATION->getThemedIcon("noaccount"));
+ }
+ else {
+ accountMenuButton->setIcon(face);
+ }
return;
}
// Set the icon to the "no account" icon.
- accountMenuButton->setIcon(LAUNCHER->getThemedIcon("noaccount"));
+ accountMenuButton->setIcon(APPLICATION->getThemedIcon("noaccount"));
accountMenuButton->setText(tr("Profiles"));
}
@@ -1193,7 +1223,7 @@ void MainWindow::updateNewsLabel()
void MainWindow::updateAvailable(GoUpdate::Status status)
{
- if(!LAUNCHER->updatesAreAllowed())
+ if(!APPLICATION->updatesAreAllowed())
{
updateNotAvailable();
return;
@@ -1239,7 +1269,7 @@ QString intListToString(const QList<int> &list)
void MainWindow::notificationsChanged()
{
QList<NotificationChecker::NotificationEntry> entries = m_notificationChecker->notificationEntries();
- QList<int> shownNotifications = stringToIntList(LAUNCHER->settings()->get("ShownNotifications").toString());
+ QList<int> shownNotifications = stringToIntList(APPLICATION->settings()->get("ShownNotifications").toString());
for (auto it = entries.begin(); it != entries.end(); ++it)
{
NotificationChecker::NotificationEntry entry = *it;
@@ -1252,25 +1282,25 @@ void MainWindow::notificationsChanged()
}
}
}
- LAUNCHER->settings()->set("ShownNotifications", intListToString(shownNotifications));
+ APPLICATION->settings()->set("ShownNotifications", intListToString(shownNotifications));
}
void MainWindow::downloadUpdates(GoUpdate::Status status)
{
- if(!LAUNCHER->updatesAreAllowed())
+ if(!APPLICATION->updatesAreAllowed())
{
return;
}
qDebug() << "Downloading updates.";
ProgressDialog updateDlg(this);
- status.rootPath = LAUNCHER->root();
+ status.rootPath = APPLICATION->root();
- auto dlPath = FS::PathCombine(LAUNCHER->root(), "update", "XXXXXX");
+ auto dlPath = FS::PathCombine(APPLICATION->root(), "update", "XXXXXX");
if (!FS::ensureFilePathExists(dlPath))
{
CustomMessageBox::selectable(this, tr("Error"), tr("Couldn't create folder for update downloads:\n%1").arg(dlPath), QMessageBox::Warning)->show();
}
- GoUpdate::DownloadTask updateTask(status, dlPath, &updateDlg);
+ GoUpdate::DownloadTask updateTask(APPLICATION->network(), status, dlPath, &updateDlg);
// If the task succeeds, install the updates.
if (updateDlg.execWithTask(&updateTask))
{
@@ -1278,10 +1308,10 @@ void MainWindow::downloadUpdates(GoUpdate::Status status)
* NOTE: This disables launching instances until the update either succeeds (and this process exits)
* or the update fails (and the control leaves this scope).
*/
- LAUNCHER->updateIsRunning(true);
- UpdateController update(this, LAUNCHER->root(), updateTask.updateFilesDir(), updateTask.operations());
+ APPLICATION->updateIsRunning(true);
+ UpdateController update(this, APPLICATION->root(), updateTask.updateFilesDir(), updateTask.operations());
update.installUpdates();
- LAUNCHER->updateIsRunning(false);
+ APPLICATION->updateIsRunning(false);
}
else
{
@@ -1292,7 +1322,7 @@ void MainWindow::downloadUpdates(GoUpdate::Status status)
void MainWindow::onCatToggled(bool state)
{
setCatBackground(state);
- LAUNCHER->settings()->set("TheCat", state);
+ APPLICATION->settings()->set("TheCat", state);
}
namespace {
@@ -1310,8 +1340,18 @@ void MainWindow::setCatBackground(bool enabled)
if (enabled)
{
QDateTime now = QDateTime::currentDateTime();
+ QDateTime birthday(QDate(now.date().year(), 11, 30), QTime(0, 0));
QDateTime xmas(QDate(now.date().year(), 12, 25), QTime(0, 0));
- QString cat = (non_stupid_abs(now.daysTo(xmas)) <= 4) ? "catmas" : "kitteh";
+ QString cat;
+ if(non_stupid_abs(now.daysTo(xmas)) <= 4) {
+ cat = "catmas";
+ }
+ else if (non_stupid_abs(now.daysTo(birthday)) <= 12) {
+ cat = "cattiversary";
+ }
+ else {
+ cat = "kitteh";
+ }
view->setStyleSheet(QString(R"(
InstanceView
{
@@ -1350,7 +1390,7 @@ void MainWindow::runModalTask(Task *task)
void MainWindow::instanceFromInstanceTask(InstanceTask *rawTask)
{
- unique_qobject_ptr<Task> task(LAUNCHER->instances()->wrapInstanceTask(rawTask));
+ unique_qobject_ptr<Task> task(APPLICATION->instances()->wrapInstanceTask(rawTask));
runModalTask(task.get());
}
@@ -1367,7 +1407,7 @@ void MainWindow::on_actionCopyInstance_triggered()
copyTask->setName(copyInstDlg.instName());
copyTask->setGroup(copyInstDlg.instGroup());
copyTask->setIcon(copyInstDlg.iconKey());
- unique_qobject_ptr<Task> task(LAUNCHER->instances()->wrapInstanceTask(copyTask));
+ unique_qobject_ptr<Task> task(APPLICATION->instances()->wrapInstanceTask(copyTask));
runModalTask(task.get());
}
@@ -1375,7 +1415,7 @@ void MainWindow::finalizeInstance(InstancePtr inst)
{
view->updateGeometries();
setSelectedInstanceById(inst->id());
- if (LAUNCHER->accounts()->anyAccountIsValid())
+ if (APPLICATION->accounts()->anyAccountIsValid())
{
ProgressDialog loadDialog(this);
auto update = inst->createUpdateTask(Net::Mode::Online);
@@ -1421,14 +1461,14 @@ void MainWindow::addInstance(QString url)
if(groupName.isEmpty())
{
- groupName = LAUNCHER->settings()->get("LastUsedGroupForNewInstance").toString();
+ groupName = APPLICATION->settings()->get("LastUsedGroupForNewInstance").toString();
}
NewInstanceDialog newInstDlg(groupName, url, this);
if (!newInstDlg.exec())
return;
- LAUNCHER->settings()->set("LastUsedGroupForNewInstance", newInstDlg.instGroup());
+ APPLICATION->settings()->set("LastUsedGroupForNewInstance", newInstDlg.instGroup());
InstanceTask * creationTask = newInstDlg.extractTask();
if(creationTask)
@@ -1479,7 +1519,7 @@ void MainWindow::on_actionChangeInstIcon_triggered()
if (dlg.result() == QDialog::Accepted)
{
m_selectedInstance->setIconKey(dlg.selectedIconKey);
- auto icon = LAUNCHER->icons()->getIcon(dlg.selectedIconKey);
+ auto icon = APPLICATION->icons()->getIcon(dlg.selectedIconKey);
ui->actionChangeInstIcon->setIcon(icon);
ui->changeIconButton->setIcon(icon);
}
@@ -1489,7 +1529,7 @@ void MainWindow::iconUpdated(QString icon)
{
if (icon == m_currentInstIcon)
{
- auto icon = LAUNCHER->icons()->getIcon(m_currentInstIcon);
+ auto icon = APPLICATION->icons()->getIcon(m_currentInstIcon);
ui->actionChangeInstIcon->setIcon(icon);
ui->changeIconButton->setIcon(icon);
}
@@ -1498,7 +1538,7 @@ void MainWindow::iconUpdated(QString icon)
void MainWindow::updateInstanceToolIcon(QString new_icon)
{
m_currentInstIcon = new_icon;
- auto icon = LAUNCHER->icons()->getIcon(m_currentInstIcon);
+ auto icon = APPLICATION->icons()->getIcon(m_currentInstIcon);
ui->actionChangeInstIcon->setIcon(icon);
ui->changeIconButton->setIcon(icon);
}
@@ -1507,7 +1547,7 @@ void MainWindow::setSelectedInstanceById(const QString &id)
{
if (id.isNull())
return;
- const QModelIndex index = LAUNCHER->instances()->getInstanceIndexById(id);
+ const QModelIndex index = APPLICATION->instances()->getInstanceIndexById(id);
if (index.isValid())
{
QModelIndex selectionIndex = proxymodel->mapFromSource(index);
@@ -1523,8 +1563,8 @@ void MainWindow::on_actionChangeInstGroup_triggered()
bool ok = false;
InstanceId instId = m_selectedInstance->id();
- QString name(LAUNCHER->instances()->getInstanceGroup(instId));
- auto groups = LAUNCHER->instances()->getGroups();
+ QString name(APPLICATION->instances()->getInstanceGroup(instId));
+ auto groups = APPLICATION->instances()->getGroups();
groups.insert(0, "");
groups.sort(Qt::CaseInsensitive);
int foo = groups.indexOf(name);
@@ -1533,7 +1573,7 @@ void MainWindow::on_actionChangeInstGroup_triggered()
name = name.simplified();
if (ok)
{
- LAUNCHER->instances()->setInstanceGroup(instId, name);
+ APPLICATION->instances()->setInstanceGroup(instId, name);
}
}
@@ -1555,25 +1595,25 @@ void MainWindow::deleteGroup()
.arg(groupName), QMessageBox::Yes | QMessageBox::No);
if(reply == QMessageBox::Yes)
{
- LAUNCHER->instances()->deleteGroup(groupName);
+ APPLICATION->instances()->deleteGroup(groupName);
}
}
}
void MainWindow::on_actionViewInstanceFolder_triggered()
{
- QString str = LAUNCHER->settings()->get("InstanceDir").toString();
+ QString str = APPLICATION->settings()->get("InstanceDir").toString();
DesktopServices::openDirectory(str);
}
void MainWindow::refreshInstances()
{
- LAUNCHER->instances()->loadList();
+ APPLICATION->instances()->loadList();
}
void MainWindow::on_actionViewCentralModsFolder_triggered()
{
- DesktopServices::openDirectory(LAUNCHER->settings()->get("CentralModsDir").toString(), true);
+ DesktopServices::openDirectory(APPLICATION->settings()->get("CentralModsDir").toString(), true);
}
void MainWindow::on_actionConfig_Folder_triggered()
@@ -1589,8 +1629,8 @@ void MainWindow::checkForUpdates()
{
if(BuildConfig.UPDATER_ENABLED)
{
- auto updater = LAUNCHER->updateChecker();
- updater->checkForUpdate(LAUNCHER->settings()->get("UpdateChannel").toString(), true);
+ auto updater = APPLICATION->updateChecker();
+ updater->checkForUpdate(APPLICATION->settings()->get("UpdateChannel").toString(), true);
}
else
{
@@ -1600,13 +1640,13 @@ void MainWindow::checkForUpdates()
void MainWindow::on_actionSettings_triggered()
{
- LAUNCHER->ShowGlobalSettings(this, "global-settings");
+ APPLICATION->ShowGlobalSettings(this, "global-settings");
}
void MainWindow::globalSettingsClosed()
{
// FIXME: quick HACK to make this work. improve, optimize.
- LAUNCHER->instances()->loadList();
+ APPLICATION->instances()->loadList();
proxymodel->invalidate();
proxymodel->sort(0);
updateToolsMenu();
@@ -1616,32 +1656,37 @@ void MainWindow::globalSettingsClosed()
void MainWindow::on_actionInstanceSettings_triggered()
{
- LAUNCHER->showInstanceWindow(m_selectedInstance, "settings");
+ APPLICATION->showInstanceWindow(m_selectedInstance, "settings");
}
void MainWindow::on_actionEditInstNotes_triggered()
{
- LAUNCHER->showInstanceWindow(m_selectedInstance, "notes");
+ APPLICATION->showInstanceWindow(m_selectedInstance, "notes");
}
void MainWindow::on_actionWorlds_triggered()
{
- LAUNCHER->showInstanceWindow(m_selectedInstance, "worlds");
+ APPLICATION->showInstanceWindow(m_selectedInstance, "worlds");
+}
+
+void MainWindow::on_actionMods_triggered()
+{
+ APPLICATION->showInstanceWindow(m_selectedInstance, "mods");
}
void MainWindow::on_actionEditInstance_triggered()
{
- LAUNCHER->showInstanceWindow(m_selectedInstance);
+ APPLICATION->showInstanceWindow(m_selectedInstance);
}
void MainWindow::on_actionScreenshots_triggered()
{
- LAUNCHER->showInstanceWindow(m_selectedInstance, "screenshots");
+ APPLICATION->showInstanceWindow(m_selectedInstance, "screenshots");
}
void MainWindow::on_actionManageAccounts_triggered()
{
- LAUNCHER->ShowGlobalSettings(this, "accounts");
+ APPLICATION->ShowGlobalSettings(this, "accounts");
}
void MainWindow::on_actionReportBug_triggered()
@@ -1695,7 +1740,7 @@ void MainWindow::on_actionDeleteInstance_triggered()
)->exec();
if (response == QMessageBox::Yes)
{
- LAUNCHER->instances()->deleteInstance(id);
+ APPLICATION->instances()->deleteInstance(id);
}
}
@@ -1739,12 +1784,25 @@ void MainWindow::on_actionViewSelectedMCFolder_triggered()
}
}
+void MainWindow::on_actionViewSelectedModsFolder_triggered()
+{
+ if (m_selectedInstance)
+ {
+ QString str = m_selectedInstance->modsRoot();
+ if (!FS::ensureFilePathExists(str))
+ {
+ // TODO: report error
+ return;
+ }
+ DesktopServices::openDirectory(QDir(str).absolutePath());
+ }
+}
void MainWindow::closeEvent(QCloseEvent *event)
{
// Save the window state and geometry.
- LAUNCHER->settings()->set("MainWindowState", saveState().toBase64());
- LAUNCHER->settings()->set("MainWindowGeometry", saveGeometry().toBase64());
+ APPLICATION->settings()->set("MainWindowState", saveState().toBase64());
+ APPLICATION->settings()->set("MainWindowGeometry", saveGeometry().toBase64());
event->accept();
emit isClosing();
}
@@ -1763,7 +1821,7 @@ void MainWindow::instanceActivated(QModelIndex index)
if (!index.isValid())
return;
QString id = index.data(InstanceList::InstanceIDRole).toString();
- InstancePtr inst = LAUNCHER->instances()->getInstanceById(id);
+ InstancePtr inst = APPLICATION->instances()->getInstanceById(id);
if (!inst)
return;
@@ -1778,24 +1836,24 @@ void MainWindow::on_actionLaunchInstance_triggered()
}
if(m_selectedInstance->isRunning())
{
- LAUNCHER->kill(m_selectedInstance);
+ APPLICATION->kill(m_selectedInstance);
}
else
{
- LAUNCHER->launch(m_selectedInstance);
+ APPLICATION->launch(m_selectedInstance);
}
}
void MainWindow::activateInstance(InstancePtr instance)
{
- LAUNCHER->launch(instance);
+ APPLICATION->launch(instance);
}
void MainWindow::on_actionLaunchInstanceOffline_triggered()
{
if (m_selectedInstance)
{
- LAUNCHER->launch(m_selectedInstance, false);
+ APPLICATION->launch(m_selectedInstance, false);
}
}
@@ -1819,12 +1877,12 @@ void MainWindow::instanceChanged(const QModelIndex &current, const QModelIndex &
{
if (!current.isValid())
{
- LAUNCHER->settings()->set("SelectedInstance", QString());
+ APPLICATION->settings()->set("SelectedInstance", QString());
selectionBad();
return;
}
QString id = current.data(InstanceList::InstanceIDRole).toString();
- m_selectedInstance = LAUNCHER->instances()->getInstanceById(id);
+ m_selectedInstance = APPLICATION->instances()->getInstanceById(id);
if (m_selectedInstance)
{
ui->instanceToolBar->setEnabled(true);
@@ -1847,12 +1905,12 @@ void MainWindow::instanceChanged(const QModelIndex &current, const QModelIndex &
updateToolsMenu();
- LAUNCHER->settings()->set("SelectedInstance", m_selectedInstance->id());
+ APPLICATION->settings()->set("SelectedInstance", m_selectedInstance->id());
}
else
{
ui->instanceToolBar->setEnabled(false);
- LAUNCHER->settings()->set("SelectedInstance", QString());
+ APPLICATION->settings()->set("SelectedInstance", QString());
selectionBad();
return;
}
@@ -1884,12 +1942,12 @@ void MainWindow::selectionBad()
updateInstanceToolIcon("grass");
// ...and then see if we can enable the previously selected instance
- setSelectedInstanceById(LAUNCHER->settings()->get("SelectedInstance").toString());
+ setSelectedInstanceById(APPLICATION->settings()->get("SelectedInstance").toString());
}
void MainWindow::checkInstancePathForProblems()
{
- QString instanceFolder = LAUNCHER->settings()->get("InstanceDir").toString();
+ QString instanceFolder = APPLICATION->settings()->get("InstanceDir").toString();
if (FS::checkProblemticPathJava(QDir(instanceFolder)))
{
QMessageBox warning(this);
@@ -1928,9 +1986,9 @@ void MainWindow::checkInstancePathForProblems()
void MainWindow::updateStatusCenter()
{
- m_statusCenter->setVisible(LAUNCHER->settings()->get("ShowGlobalGameTime").toBool());
+ m_statusCenter->setVisible(APPLICATION->settings()->get("ShowGlobalGameTime").toBool());
- int timePlayed = LAUNCHER->instances()->getTotalPlayTime();
+ int timePlayed = APPLICATION->instances()->getTotalPlayTime();
if (timePlayed > 0) {
m_statusCenter->setText(tr("Total playtime: %1").arg(Time::prettifyDuration(timePlayed)));
}
diff --git a/launcher/MainWindow.h b/launcher/ui/MainWindow.h
index c2ad46ea..e462c524 100644
--- a/launcher/MainWindow.h
+++ b/launcher/ui/MainWindow.h
@@ -93,6 +93,8 @@ private slots:
void on_actionViewSelectedMCFolder_triggered();
+ void on_actionViewSelectedModsFolder_triggered();
+
void refreshInstances();
void on_actionViewCentralModsFolder_triggered();
@@ -133,6 +135,8 @@ private slots:
void on_actionEditInstNotes_triggered();
+ void on_actionMods_triggered();
+
void on_actionWorlds_triggered();
void on_actionScreenshots_triggered();
@@ -166,7 +170,7 @@ private slots:
void notificationsChanged();
- void activeAccountChanged();
+ void defaultAccountChanged();
void changeActiveAccount();
diff --git a/launcher/dialogs/AboutDialog.cpp b/launcher/ui/dialogs/AboutDialog.cpp
index 0c3f07db..501156d0 100644
--- a/launcher/dialogs/AboutDialog.cpp
+++ b/launcher/ui/dialogs/AboutDialog.cpp
@@ -16,7 +16,7 @@
#include "AboutDialog.h"
#include "ui_AboutDialog.h"
#include <QIcon>
-#include "Launcher.h"
+#include "Application.h"
#include "BuildConfig.h"
#include <net/NetJob.h>
@@ -88,7 +88,7 @@ AboutDialog::AboutDialog(QWidget *parent) : QDialog(parent), ui(new Ui::AboutDia
ui->urlLabel->setOpenExternalLinks(true);
- ui->icon->setPixmap(LAUNCHER->getThemedIcon("logo").pixmap(64));
+ ui->icon->setPixmap(APPLICATION->getThemedIcon("logo").pixmap(64));
ui->title->setText(launcherName);
ui->versionLabel->setText(tr("Version") +": " + BuildConfig.printableVersionString());
@@ -133,10 +133,10 @@ AboutDialog::~AboutDialog()
void AboutDialog::loadPatronList()
{
- netJob.reset(new NetJob("Patreon Patron List"));
+ netJob = new NetJob("Patreon Patron List");
netJob->addNetAction(Net::Download::makeByteArray(QUrl("https://files.multimc.org/patrons.txt"), &dataSink));
connect(netJob.get(), &NetJob::succeeded, this, &AboutDialog::patronListLoaded);
- netJob->start();
+ netJob->start(APPLICATION->network());
}
void AboutDialog::patronListLoaded()
diff --git a/launcher/dialogs/AboutDialog.h b/launcher/ui/dialogs/AboutDialog.h
index c7621c37..cc4b8850 100644
--- a/launcher/dialogs/AboutDialog.h
+++ b/launcher/ui/dialogs/AboutDialog.h
@@ -42,6 +42,6 @@ slots:
private:
Ui::AboutDialog *ui;
- NetJobPtr netJob;
+ NetJob::Ptr netJob;
QByteArray dataSink;
};
diff --git a/launcher/dialogs/AboutDialog.ui b/launcher/ui/dialogs/AboutDialog.ui
index 422e877b..422e877b 100644
--- a/launcher/dialogs/AboutDialog.ui
+++ b/launcher/ui/dialogs/AboutDialog.ui
diff --git a/launcher/dialogs/CopyInstanceDialog.cpp b/launcher/ui/dialogs/CopyInstanceDialog.cpp
index 802016d9..e5113981 100644
--- a/launcher/dialogs/CopyInstanceDialog.cpp
+++ b/launcher/ui/dialogs/CopyInstanceDialog.cpp
@@ -16,11 +16,11 @@
#include <QLayout>
#include <QPushButton>
-#include "Launcher.h"
+#include "Application.h"
#include "CopyInstanceDialog.h"
#include "ui_CopyInstanceDialog.h"
-#include "dialogs/IconPickerDialog.h"
+#include "ui/dialogs/IconPickerDialog.h"
#include "BaseVersion.h"
#include "icons/IconList.h"
@@ -36,16 +36,16 @@ CopyInstanceDialog::CopyInstanceDialog(InstancePtr original, QWidget *parent)
layout()->setSizeConstraint(QLayout::SetFixedSize);
InstIconKey = original->iconKey();
- ui->iconButton->setIcon(LAUNCHER->icons()->getIcon(InstIconKey));
+ ui->iconButton->setIcon(APPLICATION->icons()->getIcon(InstIconKey));
ui->instNameTextBox->setText(original->name());
ui->instNameTextBox->setFocus();
- auto groups = LAUNCHER->instances()->getGroups().toSet();
+ auto groups = APPLICATION->instances()->getGroups().toSet();
auto groupList = QStringList(groups.toList());
groupList.sort(Qt::CaseInsensitive);
groupList.removeOne("");
groupList.push_front("");
ui->groupBox->addItems(groupList);
- int index = groupList.indexOf(LAUNCHER->instances()->getInstanceGroup(m_original->id()));
+ int index = groupList.indexOf(APPLICATION->instances()->getInstanceGroup(m_original->id()));
if(index == -1)
{
index = 0;
@@ -99,7 +99,7 @@ void CopyInstanceDialog::on_iconButton_clicked()
if (dlg.result() == QDialog::Accepted)
{
InstIconKey = dlg.selectedIconKey;
- ui->iconButton->setIcon(LAUNCHER->icons()->getIcon(InstIconKey));
+ ui->iconButton->setIcon(APPLICATION->icons()->getIcon(InstIconKey));
}
}
diff --git a/launcher/dialogs/CopyInstanceDialog.h b/launcher/ui/dialogs/CopyInstanceDialog.h
index bf3cd920..bf3cd920 100644
--- a/launcher/dialogs/CopyInstanceDialog.h
+++ b/launcher/ui/dialogs/CopyInstanceDialog.h
diff --git a/launcher/dialogs/CopyInstanceDialog.ui b/launcher/ui/dialogs/CopyInstanceDialog.ui
index f4b191e2..f4b191e2 100644
--- a/launcher/dialogs/CopyInstanceDialog.ui
+++ b/launcher/ui/dialogs/CopyInstanceDialog.ui
diff --git a/launcher/dialogs/CustomMessageBox.cpp b/launcher/ui/dialogs/CustomMessageBox.cpp
index 19029f68..19029f68 100644
--- a/launcher/dialogs/CustomMessageBox.cpp
+++ b/launcher/ui/dialogs/CustomMessageBox.cpp
diff --git a/launcher/dialogs/CustomMessageBox.h b/launcher/ui/dialogs/CustomMessageBox.h
index 712c6518..712c6518 100644
--- a/launcher/dialogs/CustomMessageBox.h
+++ b/launcher/ui/dialogs/CustomMessageBox.h
diff --git a/launcher/dialogs/EditAccountDialog.cpp b/launcher/ui/dialogs/EditAccountDialog.cpp
index 002c064b..002c064b 100644
--- a/launcher/dialogs/EditAccountDialog.cpp
+++ b/launcher/ui/dialogs/EditAccountDialog.cpp
diff --git a/launcher/dialogs/EditAccountDialog.h b/launcher/ui/dialogs/EditAccountDialog.h
index 6b5eb4aa..6b5eb4aa 100644
--- a/launcher/dialogs/EditAccountDialog.h
+++ b/launcher/ui/dialogs/EditAccountDialog.h
diff --git a/launcher/dialogs/EditAccountDialog.ui b/launcher/ui/dialogs/EditAccountDialog.ui
index e87509bc..e87509bc 100644
--- a/launcher/dialogs/EditAccountDialog.ui
+++ b/launcher/ui/dialogs/EditAccountDialog.ui
diff --git a/launcher/dialogs/ExportInstanceDialog.cpp b/launcher/ui/dialogs/ExportInstanceDialog.cpp
index 639b7043..1a164875 100644
--- a/launcher/dialogs/ExportInstanceDialog.cpp
+++ b/launcher/ui/dialogs/ExportInstanceDialog.cpp
@@ -27,7 +27,7 @@
#include <QSaveFile>
#include "MMCStrings.h"
#include "SeparatorPrefixTree.h"
-#include "Launcher.h"
+#include "Application.h"
#include <icons/IconList.h>
#include <FileSystem.h>
@@ -341,7 +341,7 @@ ExportInstanceDialog::~ExportInstanceDialog()
void SaveIcon(InstancePtr m_instance)
{
auto iconKey = m_instance->iconKey();
- auto iconList = LAUNCHER->icons();
+ auto iconList = APPLICATION->icons();
auto mmcIcon = iconList->icon(iconKey);
if(!mmcIcon || mmcIcon->isBuiltIn()) {
return;
diff --git a/launcher/dialogs/ExportInstanceDialog.h b/launcher/ui/dialogs/ExportInstanceDialog.h
index dea02d1b..dea02d1b 100644
--- a/launcher/dialogs/ExportInstanceDialog.h
+++ b/launcher/ui/dialogs/ExportInstanceDialog.h
diff --git a/launcher/dialogs/ExportInstanceDialog.ui b/launcher/ui/dialogs/ExportInstanceDialog.ui
index bcd4e84a..bcd4e84a 100644
--- a/launcher/dialogs/ExportInstanceDialog.ui
+++ b/launcher/ui/dialogs/ExportInstanceDialog.ui
diff --git a/launcher/dialogs/IconPickerDialog.cpp b/launcher/ui/dialogs/IconPickerDialog.cpp
index a1c432a8..fcb645db 100644
--- a/launcher/dialogs/IconPickerDialog.cpp
+++ b/launcher/ui/dialogs/IconPickerDialog.cpp
@@ -17,12 +17,12 @@
#include <QPushButton>
#include <QFileDialog>
-#include "Launcher.h"
+#include "Application.h"
#include "IconPickerDialog.h"
#include "ui_IconPickerDialog.h"
-#include "instanceview/InstanceDelegate.h"
+#include "ui/instanceview/InstanceDelegate.h"
#include "icons/IconList.h"
#include "icons/IconUtils.h"
@@ -59,7 +59,7 @@ IconPickerDialog::IconPickerDialog(QWidget *parent)
contentsWidget->installEventFilter(this);
- contentsWidget->setModel(LAUNCHER->icons().get());
+ contentsWidget->setModel(APPLICATION->icons().get());
// NOTE: ResetRole forces the button to be on the left, while the OK/Cancel ones are on the right. We win.
auto buttonAdd = ui->buttonBox->addButton(tr("Add Icon"), QDialogButtonBox::ResetRole);
@@ -106,12 +106,12 @@ void IconPickerDialog::addNewIcon()
//: The type of icon files
auto filter = IconUtils::getIconFilter();
QStringList fileNames = QFileDialog::getOpenFileNames(this, selectIcons, QString(), tr("Icons %1").arg(filter));
- LAUNCHER->icons()->installIcons(fileNames);
+ APPLICATION->icons()->installIcons(fileNames);
}
void IconPickerDialog::removeSelectedIcon()
{
- LAUNCHER->icons()->deleteIcon(selectedIconKey);
+ APPLICATION->icons()->deleteIcon(selectedIconKey);
}
void IconPickerDialog::activated(QModelIndex index)
@@ -133,7 +133,7 @@ void IconPickerDialog::selectionChanged(QItemSelection selected, QItemSelection
int IconPickerDialog::execWithSelection(QString selection)
{
- auto list = LAUNCHER->icons();
+ auto list = APPLICATION->icons();
auto contentsWidget = ui->iconView;
selectedIconKey = selection;
@@ -159,5 +159,5 @@ IconPickerDialog::~IconPickerDialog()
void IconPickerDialog::openFolder()
{
- DesktopServices::openDirectory(LAUNCHER->icons()->getDirectory(), true);
+ DesktopServices::openDirectory(APPLICATION->icons()->getDirectory(), true);
}
diff --git a/launcher/dialogs/IconPickerDialog.h b/launcher/ui/dialogs/IconPickerDialog.h
index 9af6a678..9af6a678 100644
--- a/launcher/dialogs/IconPickerDialog.h
+++ b/launcher/ui/dialogs/IconPickerDialog.h
diff --git a/launcher/dialogs/IconPickerDialog.ui b/launcher/ui/dialogs/IconPickerDialog.ui
index c548edfb..c548edfb 100644
--- a/launcher/dialogs/IconPickerDialog.ui
+++ b/launcher/ui/dialogs/IconPickerDialog.ui
diff --git a/launcher/dialogs/LoginDialog.cpp b/launcher/ui/dialogs/LoginDialog.cpp
index bf0806e1..194315a7 100644
--- a/launcher/dialogs/LoginDialog.cpp
+++ b/launcher/ui/dialogs/LoginDialog.cpp
@@ -43,7 +43,7 @@ void LoginDialog::accept()
// Setup the login task and start it
m_account = MinecraftAccount::createFromUsername(ui->userTextBox->text());
- m_loginTask = m_account->login(nullptr, ui->passTextBox->text());
+ m_loginTask = m_account->login(ui->passTextBox->text());
connect(m_loginTask.get(), &Task::failed, this, &LoginDialog::onTaskFailed);
connect(m_loginTask.get(), &Task::succeeded, this, &LoginDialog::onTaskSucceeded);
connect(m_loginTask.get(), &Task::status, this, &LoginDialog::onTaskStatus);
diff --git a/launcher/dialogs/LoginDialog.h b/launcher/ui/dialogs/LoginDialog.h
index 13463640..f8101ff5 100644
--- a/launcher/dialogs/LoginDialog.h
+++ b/launcher/ui/dialogs/LoginDialog.h
@@ -19,6 +19,7 @@
#include <QtCore/QEventLoop>
#include "minecraft/auth/MinecraftAccount.h"
+#include "tasks/Task.h"
namespace Ui
{
@@ -54,5 +55,5 @@ slots:
private:
Ui::LoginDialog *ui;
MinecraftAccountPtr m_account;
- std::shared_ptr<Task> m_loginTask;
+ Task::Ptr m_loginTask;
};
diff --git a/launcher/dialogs/LoginDialog.ui b/launcher/ui/dialogs/LoginDialog.ui
index 8fa4a45d..8fa4a45d 100644
--- a/launcher/dialogs/LoginDialog.ui
+++ b/launcher/ui/dialogs/LoginDialog.ui
diff --git a/launcher/dialogs/MSALoginDialog.cpp b/launcher/ui/dialogs/MSALoginDialog.cpp
index 15c04061..f46aa3b9 100644
--- a/launcher/dialogs/MSALoginDialog.cpp
+++ b/launcher/ui/dialogs/MSALoginDialog.cpp
@@ -37,7 +37,7 @@ int MSALoginDialog::exec() {
// Setup the login task and start it
m_account = MinecraftAccount::createBlankMSA();
- m_loginTask = m_account->loginMSA(nullptr);
+ m_loginTask = m_account->loginMSA();
connect(m_loginTask.get(), &Task::failed, this, &MSALoginDialog::onTaskFailed);
connect(m_loginTask.get(), &Task::succeeded, this, &MSALoginDialog::onTaskSucceeded);
connect(m_loginTask.get(), &Task::status, this, &MSALoginDialog::onTaskStatus);
diff --git a/launcher/dialogs/MSALoginDialog.h b/launcher/ui/dialogs/MSALoginDialog.h
index 3d26a0dd..4cf146ab 100644
--- a/launcher/dialogs/MSALoginDialog.h
+++ b/launcher/ui/dialogs/MSALoginDialog.h
@@ -55,7 +55,7 @@ slots:
private:
Ui::MSALoginDialog *ui;
MinecraftAccountPtr m_account;
- std::shared_ptr<AccountTask> m_loginTask;
+ shared_qobject_ptr<AccountTask> m_loginTask;
QTimer m_externalLoginTimer;
int m_externalLoginElapsed = 0;
int m_externalLoginTimeout = 0;
diff --git a/launcher/dialogs/MSALoginDialog.ui b/launcher/ui/dialogs/MSALoginDialog.ui
index 78cbfb26..78cbfb26 100644
--- a/launcher/dialogs/MSALoginDialog.ui
+++ b/launcher/ui/dialogs/MSALoginDialog.ui
diff --git a/launcher/dialogs/NewComponentDialog.cpp b/launcher/ui/dialogs/NewComponentDialog.cpp
index 1cea54f4..1bbafb0c 100644
--- a/launcher/dialogs/NewComponentDialog.cpp
+++ b/launcher/ui/dialogs/NewComponentDialog.cpp
@@ -13,7 +13,7 @@
* limitations under the License.
*/
-#include "Launcher.h"
+#include "Application.h"
#include "NewComponentDialog.h"
#include "ui_NewComponentDialog.h"
@@ -46,7 +46,7 @@ NewComponentDialog::NewComponentDialog(const QString & initialName, const QStrin
connect(ui->nameTextBox, &QLineEdit::textChanged, this, &NewComponentDialog::updateDialogState);
connect(ui->uidTextBox, &QLineEdit::textChanged, this, &NewComponentDialog::updateDialogState);
- auto groups = LAUNCHER->instances()->getGroups().toSet();
+ auto groups = APPLICATION->instances()->getGroups().toSet();
ui->nameTextBox->setFocus();
originalPlaceholderText = ui->uidTextBox->placeholderText();
diff --git a/launcher/dialogs/NewComponentDialog.h b/launcher/ui/dialogs/NewComponentDialog.h
index 8c790beb..8c790beb 100644
--- a/launcher/dialogs/NewComponentDialog.h
+++ b/launcher/ui/dialogs/NewComponentDialog.h
diff --git a/launcher/dialogs/NewComponentDialog.ui b/launcher/ui/dialogs/NewComponentDialog.ui
index 03b0d222..03b0d222 100644
--- a/launcher/dialogs/NewComponentDialog.ui
+++ b/launcher/ui/dialogs/NewComponentDialog.ui
diff --git a/launcher/dialogs/NewInstanceDialog.cpp b/launcher/ui/dialogs/NewInstanceDialog.cpp
index d18eb3d5..b402839c 100644
--- a/launcher/dialogs/NewInstanceDialog.cpp
+++ b/launcher/ui/dialogs/NewInstanceDialog.cpp
@@ -13,7 +13,7 @@
* limitations under the License.
*/
-#include "Launcher.h"
+#include "Application.h"
#include "NewInstanceDialog.h"
#include "ui_NewInstanceDialog.h"
@@ -32,14 +32,14 @@
#include <QValidator>
#include <QDialogButtonBox>
-#include "widgets/PageContainer.h"
-#include <pages/modplatform/VanillaPage.h>
-#include <pages/modplatform/atlauncher/AtlPage.h>
-#include <pages/modplatform/ftb/FtbPage.h>
-#include <pages/modplatform/legacy_ftb/Page.h>
-#include <pages/modplatform/flame/FlamePage.h>
-#include <pages/modplatform/ImportPage.h>
-#include <pages/modplatform/technic/TechnicPage.h>
+#include "ui/widgets/PageContainer.h"
+#include "ui/pages/modplatform/VanillaPage.h"
+#include "ui/pages/modplatform/atlauncher/AtlPage.h"
+#include "ui/pages/modplatform/ftb/FtbPage.h"
+#include "ui/pages/modplatform/legacy_ftb/Page.h"
+#include "ui/pages/modplatform/flame/FlamePage.h"
+#include "ui/pages/modplatform/ImportPage.h"
+#include "ui/pages/modplatform/technic/TechnicPage.h"
@@ -48,12 +48,12 @@ NewInstanceDialog::NewInstanceDialog(const QString & initialGroup, const QString
{
ui->setupUi(this);
- setWindowIcon(LAUNCHER->getThemedIcon("new"));
+ setWindowIcon(APPLICATION->getThemedIcon("new"));
InstIconKey = "default";
- ui->iconButton->setIcon(LAUNCHER->icons()->getIcon(InstIconKey));
+ ui->iconButton->setIcon(APPLICATION->icons()->getIcon(InstIconKey));
- auto groups = LAUNCHER->instances()->getGroups().toSet();
+ auto groups = APPLICATION->instances()->getGroups().toSet();
auto groupList = QStringList(groups.toList());
groupList.sort(Qt::CaseInsensitive);
groupList.removeOne("");
@@ -105,18 +105,18 @@ NewInstanceDialog::NewInstanceDialog(const QString & initialGroup, const QString
updateDialogState();
- restoreGeometry(QByteArray::fromBase64(LAUNCHER->settings()->get("NewInstanceGeometry").toByteArray()));
+ restoreGeometry(QByteArray::fromBase64(APPLICATION->settings()->get("NewInstanceGeometry").toByteArray()));
}
void NewInstanceDialog::reject()
{
- LAUNCHER->settings()->set("NewInstanceGeometry", saveGeometry().toBase64());
+ APPLICATION->settings()->set("NewInstanceGeometry", saveGeometry().toBase64());
QDialog::reject();
}
void NewInstanceDialog::accept()
{
- LAUNCHER->settings()->set("NewInstanceGeometry", saveGeometry().toBase64());
+ APPLICATION->settings()->set("NewInstanceGeometry", saveGeometry().toBase64());
importIconNow();
QDialog::accept();
}
@@ -155,7 +155,7 @@ void NewInstanceDialog::setSuggestedPack(const QString& name, InstanceTask* task
if(!task)
{
- ui->iconButton->setIcon(LAUNCHER->icons()->getIcon("default"));
+ ui->iconButton->setIcon(APPLICATION->icons()->getIcon("default"));
importIcon = false;
}
@@ -175,7 +175,7 @@ void NewInstanceDialog::setSuggestedIconFromFile(const QString &path, const QStr
void NewInstanceDialog::setSuggestedIcon(const QString &key)
{
- auto icon = LAUNCHER->icons()->getIcon(key);
+ auto icon = APPLICATION->icons()->getIcon(key);
importIcon = false;
ui->iconButton->setIcon(icon);
@@ -234,7 +234,7 @@ void NewInstanceDialog::on_iconButton_clicked()
if (dlg.result() == QDialog::Accepted)
{
InstIconKey = dlg.selectedIconKey;
- ui->iconButton->setIcon(LAUNCHER->icons()->getIcon(InstIconKey));
+ ui->iconButton->setIcon(APPLICATION->icons()->getIcon(InstIconKey));
importIcon = false;
}
}
@@ -247,9 +247,9 @@ void NewInstanceDialog::on_instNameTextBox_textChanged(const QString &arg1)
void NewInstanceDialog::importIconNow()
{
if(importIcon) {
- LAUNCHER->icons()->installIcon(importIconPath, importIconName);
+ APPLICATION->icons()->installIcon(importIconPath, importIconName);
InstIconKey = importIconName;
importIcon = false;
}
- LAUNCHER->settings()->set("NewInstanceGeometry", saveGeometry().toBase64());
+ APPLICATION->settings()->set("NewInstanceGeometry", saveGeometry().toBase64());
}
diff --git a/launcher/dialogs/NewInstanceDialog.h b/launcher/ui/dialogs/NewInstanceDialog.h
index 53abf8cf..ef74634e 100644
--- a/launcher/dialogs/NewInstanceDialog.h
+++ b/launcher/ui/dialogs/NewInstanceDialog.h
@@ -18,7 +18,7 @@
#include <QDialog>
#include "BaseVersion.h"
-#include "pages/BasePageProvider.h"
+#include "ui/pages/BasePageProvider.h"
#include "InstanceTask.h"
namespace Ui
diff --git a/launcher/dialogs/NewInstanceDialog.ui b/launcher/ui/dialogs/NewInstanceDialog.ui
index 7fb19ff5..7fb19ff5 100644
--- a/launcher/dialogs/NewInstanceDialog.ui
+++ b/launcher/ui/dialogs/NewInstanceDialog.ui
diff --git a/launcher/dialogs/NotificationDialog.cpp b/launcher/ui/dialogs/NotificationDialog.cpp
index f2a35ae2..f2a35ae2 100644
--- a/launcher/dialogs/NotificationDialog.cpp
+++ b/launcher/ui/dialogs/NotificationDialog.cpp
diff --git a/launcher/dialogs/NotificationDialog.h b/launcher/ui/dialogs/NotificationDialog.h
index e1cbb9fa..e1cbb9fa 100644
--- a/launcher/dialogs/NotificationDialog.h
+++ b/launcher/ui/dialogs/NotificationDialog.h
diff --git a/launcher/dialogs/NotificationDialog.ui b/launcher/ui/dialogs/NotificationDialog.ui
index 3e6c22bc..3e6c22bc 100644
--- a/launcher/dialogs/NotificationDialog.ui
+++ b/launcher/ui/dialogs/NotificationDialog.ui
diff --git a/launcher/dialogs/ProfileSelectDialog.cpp b/launcher/ui/dialogs/ProfileSelectDialog.cpp
index 1082748f..7882cf45 100644
--- a/launcher/dialogs/ProfileSelectDialog.cpp
+++ b/launcher/ui/dialogs/ProfileSelectDialog.cpp
@@ -14,23 +14,22 @@
*/
#include "ProfileSelectDialog.h"
-#include <SkinUtils.h>
#include "ui_ProfileSelectDialog.h"
#include <QItemSelectionModel>
-
#include <QDebug>
-#include <dialogs/ProgressDialog.h>
+#include "SkinUtils.h"
+#include "Application.h"
-#include <Launcher.h>
+#include "ui/dialogs/ProgressDialog.h"
ProfileSelectDialog::ProfileSelectDialog(const QString &message, int flags, QWidget *parent)
: QDialog(parent), ui(new Ui::ProfileSelectDialog)
{
ui->setupUi(this);
- m_accounts = LAUNCHER->accounts();
+ m_accounts = APPLICATION->accounts();
auto view = ui->listView;
//view->setModel(m_accounts.get());
//view->hideColumn(AccountList::ActiveColumn);
diff --git a/launcher/dialogs/ProfileSelectDialog.h b/launcher/ui/dialogs/ProfileSelectDialog.h
index a4acd9a1..38aa4249 100644
--- a/launcher/dialogs/ProfileSelectDialog.h
+++ b/launcher/ui/dialogs/ProfileSelectDialog.h
@@ -80,7 +80,7 @@ slots:
void on_buttonBox_rejected();
protected:
- std::shared_ptr<AccountList> m_accounts;
+ shared_qobject_ptr<AccountList> m_accounts;
//! The account that was selected when the user clicked OK.
MinecraftAccountPtr m_selected;
diff --git a/launcher/dialogs/ProfileSelectDialog.ui b/launcher/ui/dialogs/ProfileSelectDialog.ui
index e779b51b..e779b51b 100644
--- a/launcher/dialogs/ProfileSelectDialog.ui
+++ b/launcher/ui/dialogs/ProfileSelectDialog.ui
diff --git a/launcher/ui/dialogs/ProfileSetupDialog.cpp b/launcher/ui/dialogs/ProfileSetupDialog.cpp
new file mode 100644
index 00000000..76b6af49
--- /dev/null
+++ b/launcher/ui/dialogs/ProfileSetupDialog.cpp
@@ -0,0 +1,256 @@
+/* Copyright 2013-2021 MultiMC Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ProfileSetupDialog.h"
+#include "ui_ProfileSetupDialog.h"
+
+#include <QPushButton>
+#include <QAction>
+#include <QRegExpValidator>
+#include <QJsonDocument>
+#include <QDebug>
+
+#include "ui/dialogs/ProgressDialog.h"
+
+#include <Application.h>
+#include "minecraft/auth/AuthRequest.h"
+#include "minecraft/auth/Parsers.h"
+
+
+ProfileSetupDialog::ProfileSetupDialog(MinecraftAccountPtr accountToSetup, QWidget *parent)
+ : QDialog(parent), m_accountToSetup(accountToSetup), ui(new Ui::ProfileSetupDialog)
+{
+ ui->setupUi(this);
+ ui->errorLabel->setVisible(false);
+
+ goodIcon = APPLICATION->getThemedIcon("status-good");
+ yellowIcon = APPLICATION->getThemedIcon("status-yellow");
+ badIcon = APPLICATION->getThemedIcon("status-bad");
+
+ QRegExp permittedNames("[a-zA-Z0-9_]{3,16}");
+ auto nameEdit = ui->nameEdit;
+ nameEdit->setValidator(new QRegExpValidator(permittedNames));
+ nameEdit->setClearButtonEnabled(true);
+ validityAction = nameEdit->addAction(yellowIcon, QLineEdit::LeadingPosition);
+ connect(nameEdit, &QLineEdit::textEdited, this, &ProfileSetupDialog::nameEdited);
+
+ checkStartTimer.setSingleShot(true);
+ connect(&checkStartTimer, &QTimer::timeout, this, &ProfileSetupDialog::startCheck);
+
+ setNameStatus(NameStatus::NotSet, QString());
+}
+
+ProfileSetupDialog::~ProfileSetupDialog()
+{
+ delete ui;
+}
+
+void ProfileSetupDialog::on_buttonBox_accepted()
+{
+ setupProfile(currentCheck);
+}
+
+void ProfileSetupDialog::on_buttonBox_rejected()
+{
+ reject();
+}
+
+void ProfileSetupDialog::setNameStatus(ProfileSetupDialog::NameStatus status, QString errorString = QString())
+{
+ nameStatus = status;
+ auto okButton = ui->buttonBox->button(QDialogButtonBox::Ok);
+ switch(nameStatus)
+ {
+ case NameStatus::Available: {
+ validityAction->setIcon(goodIcon);
+ okButton->setEnabled(true);
+ }
+ break;
+ case NameStatus::NotSet:
+ case NameStatus::Pending:
+ validityAction->setIcon(yellowIcon);
+ okButton->setEnabled(false);
+ break;
+ case NameStatus::Exists:
+ case NameStatus::Error:
+ validityAction->setIcon(badIcon);
+ okButton->setEnabled(false);
+ break;
+ }
+ if(!errorString.isEmpty()) {
+ ui->errorLabel->setText(errorString);
+ ui->errorLabel->setVisible(true);
+ }
+ else {
+ ui->errorLabel->setVisible(false);
+ }
+}
+
+void ProfileSetupDialog::nameEdited(const QString& name)
+{
+ if(!ui->nameEdit->hasAcceptableInput()) {
+ setNameStatus(NameStatus::NotSet, tr("Name is too short - must be between 3 and 16 characters long."));
+ return;
+ }
+ scheduleCheck(name);
+}
+
+void ProfileSetupDialog::scheduleCheck(const QString& name) {
+ queuedCheck = name;
+ setNameStatus(NameStatus::Pending);
+ checkStartTimer.start(1000);
+}
+
+void ProfileSetupDialog::startCheck() {
+ if(isChecking) {
+ return;
+ }
+ if(queuedCheck.isNull()) {
+ return;
+ }
+ checkName(queuedCheck);
+}
+
+
+void ProfileSetupDialog::checkName(const QString &name) {
+ if(isChecking) {
+ return;
+ }
+
+ currentCheck = name;
+ isChecking = true;
+
+ auto token = m_accountToSetup->accessToken();
+
+ auto url = QString("https://api.minecraftservices.com/minecraft/profile/name/%1/available").arg(name);
+ QNetworkRequest request = QNetworkRequest(url);
+ request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
+ request.setRawHeader("Accept", "application/json");
+ request.setRawHeader("Authorization", QString("Bearer %1").arg(token).toUtf8());
+
+ AuthRequest *requestor = new AuthRequest(this);
+ connect(requestor, &AuthRequest::finished, this, &ProfileSetupDialog::checkFinished);
+ requestor->get(request);
+}
+
+void ProfileSetupDialog::checkFinished(
+ QNetworkReply::NetworkError error,
+ QByteArray data,
+ QList<QNetworkReply::RawHeaderPair> headers
+) {
+ auto requestor = qobject_cast<AuthRequest *>(QObject::sender());
+ requestor->deleteLater();
+
+ if(error == QNetworkReply::NoError) {
+ auto doc = QJsonDocument::fromJson(data);
+ auto root = doc.object();
+ auto statusValue = root.value("status").toString("INVALID");
+ if(statusValue == "AVAILABLE") {
+ setNameStatus(NameStatus::Available);
+ }
+ else if (statusValue == "DUPLICATE") {
+ setNameStatus(NameStatus::Exists, tr("Minecraft profile with name %1 already exists.").arg(currentCheck));
+ }
+ else if (statusValue == "NOT_ALLOWED") {
+ setNameStatus(NameStatus::Exists, tr("The name %1 is not allowed.").arg(currentCheck));
+ }
+ else {
+ setNameStatus(NameStatus::Error, tr("Unhandled profile name status: %1").arg(statusValue));
+ }
+ }
+ else {
+ setNameStatus(NameStatus::Error, tr("Failed to check name availability."));
+ }
+ isChecking = false;
+}
+
+void ProfileSetupDialog::setupProfile(const QString &profileName) {
+ if(isWorking) {
+ return;
+ }
+
+ auto token = m_accountToSetup->accessToken();
+
+ auto url = QString("https://api.minecraftservices.com/minecraft/profile");
+ QNetworkRequest request = QNetworkRequest(url);
+ request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
+ request.setRawHeader("Accept", "application/json");
+ request.setRawHeader("Authorization", QString("Bearer %1").arg(token).toUtf8());
+
+ QString payloadTemplate("{\"profileName\":\"%1\"}");
+ auto data = payloadTemplate.arg(profileName).toUtf8();
+
+ AuthRequest *requestor = new AuthRequest(this);
+ connect(requestor, &AuthRequest::finished, this, &ProfileSetupDialog::setupProfileFinished);
+ requestor->post(request, data);
+ isWorking = true;
+
+ auto button = ui->buttonBox->button(QDialogButtonBox::Cancel);
+ button->setEnabled(false);
+}
+
+namespace {
+
+struct MojangError{
+ static MojangError fromJSON(QByteArray data) {
+ MojangError out;
+ out.error = QString::fromUtf8(data);
+ auto doc = QJsonDocument::fromJson(data, &out.parseError);
+ auto object = doc.object();
+
+ out.fullyParsed = true;
+ out.fullyParsed &= Parsers::getString(object.value("path"), out.path);
+ out.fullyParsed &= Parsers::getString(object.value("error"), out.error);
+ out.fullyParsed &= Parsers::getString(object.value("errorMessage"), out.errorMessage);
+
+ return out;
+ }
+
+ QString rawError;
+ QJsonParseError parseError;
+ bool fullyParsed;
+
+ QString path;
+ QString error;
+ QString errorMessage;
+};
+
+}
+
+void ProfileSetupDialog::setupProfileFinished(
+ QNetworkReply::NetworkError error,
+ QByteArray data,
+ QList<QNetworkReply::RawHeaderPair> headers
+) {
+ auto requestor = qobject_cast<AuthRequest *>(QObject::sender());
+ requestor->deleteLater();
+
+ isWorking = false;
+ if(error == QNetworkReply::NoError) {
+ /*
+ * data contains the profile in the response
+ * ... we could parse it and update the account, but let's just return back to the normal login flow instead...
+ */
+ accept();
+ }
+ else {
+ auto parsedError = MojangError::fromJSON(data);
+ ui->errorLabel->setVisible(true);
+ ui->errorLabel->setText(tr("The server returned the following error:") + "\n\n" + parsedError.errorMessage);
+ qDebug() << parsedError.rawError;
+ auto button = ui->buttonBox->button(QDialogButtonBox::Cancel);
+ button->setEnabled(true);
+ }
+}
diff --git a/launcher/ui/dialogs/ProfileSetupDialog.h b/launcher/ui/dialogs/ProfileSetupDialog.h
new file mode 100644
index 00000000..6f413ebd
--- /dev/null
+++ b/launcher/ui/dialogs/ProfileSetupDialog.h
@@ -0,0 +1,88 @@
+/* Copyright 2013-2021 MultiMC Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <QDialog>
+#include <QIcon>
+#include <QTimer>
+#include <QNetworkReply>
+
+#include <memory>
+#include <minecraft/auth/MinecraftAccount.h>
+
+namespace Ui
+{
+class ProfileSetupDialog;
+}
+
+class ProfileSetupDialog : public QDialog
+{
+ Q_OBJECT
+public:
+
+ explicit ProfileSetupDialog(MinecraftAccountPtr accountToSetup, QWidget *parent = 0);
+ ~ProfileSetupDialog();
+
+ enum class NameStatus
+ {
+ NotSet,
+ Pending,
+ Available,
+ Exists,
+ Error
+ } nameStatus = NameStatus::NotSet;
+
+private slots:
+ void on_buttonBox_accepted();
+ void on_buttonBox_rejected();
+
+ void nameEdited(const QString &name);
+ void checkFinished(
+ QNetworkReply::NetworkError error,
+ QByteArray data,
+ QList<QNetworkReply::RawHeaderPair> headers
+ );
+ void startCheck();
+
+ void setupProfileFinished(
+ QNetworkReply::NetworkError error,
+ QByteArray data,
+ QList<QNetworkReply::RawHeaderPair> headers
+ );
+protected:
+ void scheduleCheck(const QString &name);
+ void checkName(const QString &name);
+ void setNameStatus(NameStatus status, QString errorString);
+
+ void setupProfile(const QString & profileName);
+
+private:
+ MinecraftAccountPtr m_accountToSetup;
+ Ui::ProfileSetupDialog *ui;
+ QIcon goodIcon;
+ QIcon yellowIcon;
+ QIcon badIcon;
+ QAction * validityAction = nullptr;
+
+ QString queuedCheck;
+
+ bool isChecking = false;
+ bool isWorking = false;
+ QString currentCheck;
+
+ QTimer checkStartTimer;
+};
+
diff --git a/launcher/ui/dialogs/ProfileSetupDialog.ui b/launcher/ui/dialogs/ProfileSetupDialog.ui
new file mode 100644
index 00000000..9dbabb4b
--- /dev/null
+++ b/launcher/ui/dialogs/ProfileSetupDialog.ui
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ProfileSetupDialog</class>
+ <widget class="QDialog" name="ProfileSetupDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>615</width>
+ <height>208</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Choose Minecraft name</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0" colspan="2">
+ <widget class="QLabel" name="descriptionLabel">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>You just need to take one more step to be able to play Minecraft on this account.
+
+Choose your name carefully:</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ <property name="buddy">
+ <cstring>nameEdit</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLineEdit" name="nameEdit"/>
+ </item>
+ <item row="4" column="0" colspan="2">
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="errorLabel">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string notr="true">Errors go here</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ <property name="openExternalLinks">
+ <bool>true</bool>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <tabstops>
+ <tabstop>nameEdit</tabstop>
+ </tabstops>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/launcher/dialogs/ProgressDialog.cpp b/launcher/ui/dialogs/ProgressDialog.cpp
index 4b092859..4b092859 100644
--- a/launcher/dialogs/ProgressDialog.cpp
+++ b/launcher/ui/dialogs/ProgressDialog.cpp
diff --git a/launcher/dialogs/ProgressDialog.h b/launcher/ui/dialogs/ProgressDialog.h
index b28ad4fa..b28ad4fa 100644
--- a/launcher/dialogs/ProgressDialog.h
+++ b/launcher/ui/dialogs/ProgressDialog.h
diff --git a/launcher/dialogs/ProgressDialog.ui b/launcher/ui/dialogs/ProgressDialog.ui
index 04b8fef3..04b8fef3 100644
--- a/launcher/dialogs/ProgressDialog.ui
+++ b/launcher/ui/dialogs/ProgressDialog.ui
diff --git a/launcher/dialogs/SkinUploadDialog.cpp b/launcher/ui/dialogs/SkinUploadDialog.cpp
index 97478f4b..6a5a324f 100644
--- a/launcher/dialogs/SkinUploadDialog.cpp
+++ b/launcher/ui/dialogs/SkinUploadDialog.cpp
@@ -3,14 +3,15 @@
#include <QPainter>
#include <FileSystem.h>
+
#include <minecraft/services/SkinUpload.h>
+#include <minecraft/services/CapeChange.h>
#include <tasks/SequentialTask.h>
#include "SkinUploadDialog.h"
#include "ui_SkinUploadDialog.h"
#include "ProgressDialog.h"
#include "CustomMessageBox.h"
-#include <minecraft/services/CapeChange.h>
void SkinUploadDialog::on_buttonBox_rejected()
{
@@ -19,16 +20,6 @@ void SkinUploadDialog::on_buttonBox_rejected()
void SkinUploadDialog::on_buttonBox_accepted()
{
- AuthSessionPtr session = std::make_shared<AuthSession>();
- auto login = m_acct->refresh(session);
- ProgressDialog prog(this);
- if (prog.execWithTask((Task*)login.get()) != QDialog::Accepted)
- {
- //FIXME: recover with password prompt
- CustomMessageBox::selectable(this, tr("Skin Upload"), tr("Failed to login!"), QMessageBox::Warning)->exec();
- close();
- return;
- }
QString fileName;
QString input = ui->skinPathTextBox->text();
QRegExp urlPrefixMatcher("^([a-z]+)://.+$");
@@ -90,11 +81,12 @@ void SkinUploadDialog::on_buttonBox_accepted()
{
model = SkinUpload::ALEX;
}
+ ProgressDialog prog(this);
SequentialTask skinUpload;
- skinUpload.addTask(std::make_shared<SkinUpload>(this, session, FS::read(fileName), model));
+ skinUpload.addTask(shared_qobject_ptr<SkinUpload>(new SkinUpload(this, m_acct->accessToken(), FS::read(fileName), model)));
auto selectedCape = ui->capeCombo->currentData().toString();
- if(selectedCape != session->m_accountPtr->accountData()->minecraftProfile.currentCape) {
- skinUpload.addTask(std::make_shared<CapeChange>(this, session, selectedCape));
+ if(selectedCape != m_acct->accountData()->minecraftProfile.currentCape) {
+ skinUpload.addTask(shared_qobject_ptr<CapeChange>(new CapeChange(this, m_acct->accessToken(), selectedCape)));
}
if (prog.execWithTask(&skinUpload) != QDialog::Accepted)
{
diff --git a/launcher/dialogs/SkinUploadDialog.h b/launcher/ui/dialogs/SkinUploadDialog.h
index 84d17dc6..84d17dc6 100644
--- a/launcher/dialogs/SkinUploadDialog.h
+++ b/launcher/ui/dialogs/SkinUploadDialog.h
diff --git a/launcher/dialogs/SkinUploadDialog.ui b/launcher/ui/dialogs/SkinUploadDialog.ui
index f4b0ed0a..f4b0ed0a 100644
--- a/launcher/dialogs/SkinUploadDialog.ui
+++ b/launcher/ui/dialogs/SkinUploadDialog.ui
diff --git a/launcher/dialogs/UpdateDialog.cpp b/launcher/ui/dialogs/UpdateDialog.cpp
index ca3bd915..4a6a1fdd 100644
--- a/launcher/dialogs/UpdateDialog.cpp
+++ b/launcher/ui/dialogs/UpdateDialog.cpp
@@ -1,7 +1,7 @@
#include "UpdateDialog.h"
#include "ui_UpdateDialog.h"
#include <QDebug>
-#include "Launcher.h"
+#include "Application.h"
#include <settings/SettingsObject.h>
#include <Json.h>
@@ -11,7 +11,7 @@
UpdateDialog::UpdateDialog(bool hasUpdate, QWidget *parent) : QDialog(parent), ui(new Ui::UpdateDialog)
{
ui->setupUi(this);
- auto channel = LAUNCHER->settings()->get("UpdateChannel").toString();
+ auto channel = APPLICATION->settings()->get("UpdateChannel").toString();
if(hasUpdate)
{
ui->label->setText(tr("A new %1 update is available!").arg(channel));
@@ -24,7 +24,7 @@ UpdateDialog::UpdateDialog(bool hasUpdate, QWidget *parent) : QDialog(parent), u
}
ui->changelogBrowser->setHtml(tr("<center><h1>Loading changelog...</h1></center>"));
loadChangelog();
- restoreGeometry(QByteArray::fromBase64(LAUNCHER->settings()->get("UpdateDialogGeometry").toByteArray()));
+ restoreGeometry(QByteArray::fromBase64(APPLICATION->settings()->get("UpdateDialogGeometry").toByteArray()));
}
UpdateDialog::~UpdateDialog()
@@ -33,7 +33,7 @@ UpdateDialog::~UpdateDialog()
void UpdateDialog::loadChangelog()
{
- auto channel = LAUNCHER->settings()->get("UpdateChannel").toString();
+ auto channel = APPLICATION->settings()->get("UpdateChannel").toString();
dljob.reset(new NetJob("Changelog"));
QString url;
if(channel == "stable")
@@ -49,7 +49,7 @@ void UpdateDialog::loadChangelog()
dljob->addNetAction(Net::Download::makeByteArray(QUrl(url), &changelogData));
connect(dljob.get(), &NetJob::succeeded, this, &UpdateDialog::changelogLoaded);
connect(dljob.get(), &NetJob::failed, this, &UpdateDialog::changelogFailed);
- dljob->start();
+ dljob->start(APPLICATION->network());
}
QString reprocessMarkdown(QByteArray markdown)
@@ -65,7 +65,7 @@ QString reprocessMarkdown(QByteArray markdown)
QString reprocessCommits(QByteArray json)
{
- auto channel = LAUNCHER->settings()->get("UpdateChannel").toString();
+ auto channel = APPLICATION->settings()->get("UpdateChannel").toString();
try
{
QString result;
@@ -177,6 +177,6 @@ void UpdateDialog::on_btnUpdateNow_clicked()
void UpdateDialog::closeEvent(QCloseEvent* evt)
{
- LAUNCHER->settings()->set("UpdateDialogGeometry", saveGeometry().toBase64());
+ APPLICATION->settings()->set("UpdateDialogGeometry", saveGeometry().toBase64());
QDialog::closeEvent(evt);
}
diff --git a/launcher/dialogs/UpdateDialog.h b/launcher/ui/dialogs/UpdateDialog.h
index ae1799c3..07cbe09f 100644
--- a/launcher/dialogs/UpdateDialog.h
+++ b/launcher/ui/dialogs/UpdateDialog.h
@@ -62,6 +62,6 @@ protected:
private:
Ui::UpdateDialog *ui;
QByteArray changelogData;
- NetJobPtr dljob;
+ NetJob::Ptr dljob;
ChangelogType m_changelogType = CHANGELOG_MARKDOWN;
};
diff --git a/launcher/dialogs/UpdateDialog.ui b/launcher/ui/dialogs/UpdateDialog.ui
index b0b3dd83..b0b3dd83 100644
--- a/launcher/dialogs/UpdateDialog.ui
+++ b/launcher/ui/dialogs/UpdateDialog.ui
diff --git a/launcher/dialogs/VersionSelectDialog.cpp b/launcher/ui/dialogs/VersionSelectDialog.cpp
index 82eb70f4..70ef72d6 100644
--- a/launcher/dialogs/VersionSelectDialog.cpp
+++ b/launcher/ui/dialogs/VersionSelectDialog.cpp
@@ -20,17 +20,17 @@
#include <QtWidgets/QHBoxLayout>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QVBoxLayout>
+#include <QDebug>
-#include <dialogs/ProgressDialog.h>
-#include "CustomMessageBox.h"
+#include "ui/dialogs/ProgressDialog.h"
+#include "ui/widgets/VersionSelectWidget.h"
+#include "ui/dialogs/CustomMessageBox.h"
-#include <BaseVersion.h>
-#include <BaseVersionList.h>
-#include <tasks/Task.h>
-#include <QDebug>
-#include "Launcher.h"
-#include <VersionProxyModel.h>
-#include <widgets/VersionSelectWidget.h>
+#include "BaseVersion.h"
+#include "BaseVersionList.h"
+#include "tasks/Task.h"
+#include "Application.h"
+#include "VersionProxyModel.h"
VersionSelectDialog::VersionSelectDialog(BaseVersionList *vlist, QString title, QWidget *parent, bool cancelable)
: QDialog(parent)
diff --git a/launcher/dialogs/VersionSelectDialog.h b/launcher/ui/dialogs/VersionSelectDialog.h
index ed30d3f3..ed30d3f3 100644
--- a/launcher/dialogs/VersionSelectDialog.h
+++ b/launcher/ui/dialogs/VersionSelectDialog.h
diff --git a/launcher/instanceview/AccessibleInstanceView.cpp b/launcher/ui/instanceview/AccessibleInstanceView.cpp
index 7de3ac72..7de3ac72 100644
--- a/launcher/instanceview/AccessibleInstanceView.cpp
+++ b/launcher/ui/instanceview/AccessibleInstanceView.cpp
diff --git a/launcher/instanceview/AccessibleInstanceView.h b/launcher/ui/instanceview/AccessibleInstanceView.h
index 9bfd1745..9bfd1745 100644
--- a/launcher/instanceview/AccessibleInstanceView.h
+++ b/launcher/ui/instanceview/AccessibleInstanceView.h
diff --git a/launcher/instanceview/AccessibleInstanceView_p.h b/launcher/ui/instanceview/AccessibleInstanceView_p.h
index 26462f51..26462f51 100644
--- a/launcher/instanceview/AccessibleInstanceView_p.h
+++ b/launcher/ui/instanceview/AccessibleInstanceView_p.h
diff --git a/launcher/instanceview/InstanceDelegate.cpp b/launcher/ui/instanceview/InstanceDelegate.cpp
index 3c4ca63f..3c4ca63f 100644
--- a/launcher/instanceview/InstanceDelegate.cpp
+++ b/launcher/ui/instanceview/InstanceDelegate.cpp
diff --git a/launcher/instanceview/InstanceDelegate.h b/launcher/ui/instanceview/InstanceDelegate.h
index d95279f3..d95279f3 100644
--- a/launcher/instanceview/InstanceDelegate.h
+++ b/launcher/ui/instanceview/InstanceDelegate.h
diff --git a/launcher/instanceview/InstanceProxyModel.cpp b/launcher/ui/instanceview/InstanceProxyModel.cpp
index 76434bd4..d8de93ed 100644
--- a/launcher/instanceview/InstanceProxyModel.cpp
+++ b/launcher/ui/instanceview/InstanceProxyModel.cpp
@@ -16,7 +16,7 @@
#include "InstanceProxyModel.h"
#include "InstanceView.h"
-#include "Launcher.h"
+#include "Application.h"
#include <BaseInstance.h>
#include <icons/IconList.h>
@@ -34,7 +34,7 @@ QVariant InstanceProxyModel::data(const QModelIndex & index, int role) const
QVariant data = QSortFilterProxyModel::data(index, role);
if(role == Qt::DecorationRole)
{
- return QVariant(LAUNCHER->icons()->getIcon(data.toString()));
+ return QVariant(APPLICATION->icons()->getIcon(data.toString()));
}
return data;
}
@@ -59,7 +59,7 @@ bool InstanceProxyModel::subSortLessThan(const QModelIndex &left, const QModelIn
{
BaseInstance *pdataLeft = static_cast<BaseInstance *>(left.internalPointer());
BaseInstance *pdataRight = static_cast<BaseInstance *>(right.internalPointer());
- QString sortMode = LAUNCHER->settings()->get("InstSortMode").toString();
+ QString sortMode = APPLICATION->settings()->get("InstSortMode").toString();
if (sortMode == "LastLaunch")
{
return pdataLeft->lastLaunch() > pdataRight->lastLaunch();
diff --git a/launcher/instanceview/InstanceProxyModel.h b/launcher/ui/instanceview/InstanceProxyModel.h
index bba8d2b5..bba8d2b5 100644
--- a/launcher/instanceview/InstanceProxyModel.h
+++ b/launcher/ui/instanceview/InstanceProxyModel.h
diff --git a/launcher/instanceview/InstanceView.cpp b/launcher/ui/instanceview/InstanceView.cpp
index 80dfb6f2..1f044866 100644
--- a/launcher/instanceview/InstanceView.cpp
+++ b/launcher/ui/instanceview/InstanceView.cpp
@@ -30,7 +30,7 @@
#include "VisualGroup.h"
#include <QDebug>
-#include <Launcher.h>
+#include <Application.h>
#include <InstanceList.h>
@@ -628,7 +628,7 @@ void InstanceView::dropEvent(QDropEvent *event)
return;
}
auto instanceId = QString::fromUtf8(mimedata->data("application/x-instanceid"));
- auto instanceList = LAUNCHER->instances().get();
+ auto instanceList = APPLICATION->instances().get();
instanceList->setInstanceGroup(instanceId, group->text);
event->setDropAction(Qt::MoveAction);
event->accept();
diff --git a/launcher/instanceview/InstanceView.h b/launcher/ui/instanceview/InstanceView.h
index 406362e6..406362e6 100644
--- a/launcher/instanceview/InstanceView.h
+++ b/launcher/ui/instanceview/InstanceView.h
diff --git a/launcher/instanceview/VisualGroup.cpp b/launcher/ui/instanceview/VisualGroup.cpp
index 8991fb2d..8991fb2d 100644
--- a/launcher/instanceview/VisualGroup.cpp
+++ b/launcher/ui/instanceview/VisualGroup.cpp
diff --git a/launcher/instanceview/VisualGroup.h b/launcher/ui/instanceview/VisualGroup.h
index 5a743aa1..5a743aa1 100644
--- a/launcher/instanceview/VisualGroup.h
+++ b/launcher/ui/instanceview/VisualGroup.h
diff --git a/launcher/pagedialog/PageDialog.cpp b/launcher/ui/pagedialog/PageDialog.cpp
index 79d7acd3..18d61dc2 100644
--- a/launcher/pagedialog/PageDialog.cpp
+++ b/launcher/ui/pagedialog/PageDialog.cpp
@@ -20,10 +20,11 @@
#include <QVBoxLayout>
#include <QKeyEvent>
-#include "Launcher.h"
+#include "Application.h"
#include "settings/SettingsObject.h"
-#include "widgets/IconLabel.h"
-#include "widgets/PageContainer.h"
+
+#include "ui/widgets/IconLabel.h"
+#include "ui/widgets/PageContainer.h"
PageDialog::PageDialog(BasePageProvider *pageProvider, QString defaultId, QWidget *parent)
: QDialog(parent)
@@ -45,7 +46,7 @@ PageDialog::PageDialog(BasePageProvider *pageProvider, QString defaultId, QWidge
connect(buttons->button(QDialogButtonBox::Close), SIGNAL(clicked()), this, SLOT(close()));
connect(buttons->button(QDialogButtonBox::Help), SIGNAL(clicked()), m_container, SLOT(help()));
- restoreGeometry(QByteArray::fromBase64(LAUNCHER->settings()->get("PagedGeometry").toByteArray()));
+ restoreGeometry(QByteArray::fromBase64(APPLICATION->settings()->get("PagedGeometry").toByteArray()));
}
void PageDialog::closeEvent(QCloseEvent *event)
@@ -54,7 +55,7 @@ void PageDialog::closeEvent(QCloseEvent *event)
if (m_container->prepareToClose())
{
qDebug() << "Paged dialog close approved";
- LAUNCHER->settings()->set("PagedGeometry", saveGeometry().toBase64());
+ APPLICATION->settings()->set("PagedGeometry", saveGeometry().toBase64());
qDebug() << "Paged dialog geometry saved";
QDialog::closeEvent(event);
}
diff --git a/launcher/pagedialog/PageDialog.h b/launcher/ui/pagedialog/PageDialog.h
index 1029bc30..00d8b725 100644
--- a/launcher/pagedialog/PageDialog.h
+++ b/launcher/ui/pagedialog/PageDialog.h
@@ -16,7 +16,7 @@
#pragma once
#include <QDialog>
-#include "pages/BasePageProvider.h"
+#include "ui/pages/BasePageProvider.h"
class PageContainer;
class PageDialog : public QDialog
diff --git a/launcher/pages/BasePage.h b/launcher/ui/pages/BasePage.h
index 408965d0..408965d0 100644
--- a/launcher/pages/BasePage.h
+++ b/launcher/ui/pages/BasePage.h
diff --git a/launcher/pages/BasePageContainer.h b/launcher/ui/pages/BasePageContainer.h
index f8c7adeb..f8c7adeb 100644
--- a/launcher/pages/BasePageContainer.h
+++ b/launcher/ui/pages/BasePageContainer.h
diff --git a/launcher/pages/BasePageProvider.h b/launcher/ui/pages/BasePageProvider.h
index 7bfaaf3b..873e8dce 100644
--- a/launcher/pages/BasePageProvider.h
+++ b/launcher/ui/pages/BasePageProvider.h
@@ -15,7 +15,7 @@
#pragma once
-#include "pages/BasePage.h"
+#include "ui/pages/BasePage.h"
#include <memory>
#include <functional>
diff --git a/launcher/pages/global/AccountListPage.cpp b/launcher/ui/pages/global/AccountListPage.cpp
index 4f8b8e9c..d3eb2655 100644
--- a/launcher/pages/global/AccountListPage.cpp
+++ b/launcher/ui/pages/global/AccountListPage.cpp
@@ -22,20 +22,20 @@
#include <QDebug>
#include "net/NetJob.h"
-#include "Env.h"
-#include "dialogs/ProgressDialog.h"
-#include "dialogs/LoginDialog.h"
-#include "dialogs/CustomMessageBox.h"
-#include "dialogs/SkinUploadDialog.h"
+#include "ui/dialogs/ProgressDialog.h"
+#include "ui/dialogs/LoginDialog.h"
+#include "ui/dialogs/MSALoginDialog.h"
+#include "ui/dialogs/CustomMessageBox.h"
+#include "ui/dialogs/SkinUploadDialog.h"
+
#include "tasks/Task.h"
#include "minecraft/auth/AccountTask.h"
#include "minecraft/services/SkinDelete.h"
-#include "Launcher.h"
+#include "Application.h"
#include "BuildConfig.h"
-#include <dialogs/MSALoginDialog.h>
#include "Secrets.h"
@@ -50,7 +50,7 @@ AccountListPage::AccountListPage(QWidget *parent)
ui->listView->setEmptyMode(VersionListView::String);
ui->listView->setContextMenuPolicy(Qt::CustomContextMenu);
- m_accounts = LAUNCHER->accounts();
+ m_accounts = APPLICATION->accounts();
ui->listView->setModel(m_accounts.get());
ui->listView->header()->setSectionResizeMode(0, QHeaderView::Stretch);
@@ -68,7 +68,8 @@ AccountListPage::AccountListPage(QWidget *parent)
connect(ui->listView, &VersionListView::customContextMenuRequested, this, &AccountListPage::ShowContextMenu);
connect(m_accounts.get(), &AccountList::listChanged, this, &AccountListPage::listChanged);
- connect(m_accounts.get(), &AccountList::activeAccountChanged, this, &AccountListPage::listChanged);
+ connect(m_accounts.get(), &AccountList::listActivityChanged, this, &AccountListPage::listChanged);
+ connect(m_accounts.get(), &AccountList::defaultAccountChanged, this, &AccountListPage::listChanged);
updateButtonStates();
@@ -117,11 +118,11 @@ void AccountListPage::on_actionAddMojang_triggered()
tr("Please enter your Mojang account email and password to add your account.")
);
- if (account != nullptr)
+ if (account)
{
m_accounts->addAccount(account);
if (m_accounts->count() == 1) {
- m_accounts->setActiveAccount(account->profileId());
+ m_accounts->setDefaultAccount(account);
}
}
}
@@ -145,11 +146,11 @@ void AccountListPage::on_actionAddMicrosoft_triggered()
tr("Please enter your Mojang account email and password to add your account.")
);
- if (account != nullptr)
+ if (account)
{
m_accounts->addAccount(account);
if (m_accounts->count() == 1) {
- m_accounts->setActiveAccount(account->profileId());
+ m_accounts->setDefaultAccount(account);
}
}
}
@@ -169,13 +170,7 @@ void AccountListPage::on_actionRefresh_triggered() {
if (selection.size() > 0) {
QModelIndex selected = selection.first();
MinecraftAccountPtr account = selected.data(AccountList::PointerRole).value<MinecraftAccountPtr>();
- AuthSessionPtr session = std::make_shared<AuthSession>();
- auto task = account->refresh(session);
- if (task) {
- ProgressDialog progDialog(this);
- progDialog.execWithTask(task.get());
- // TODO: respond to results of the task
- }
+ m_accounts->requestRefresh(account->internalId());
}
}
@@ -187,27 +182,34 @@ void AccountListPage::on_actionSetDefault_triggered()
{
QModelIndex selected = selection.first();
MinecraftAccountPtr account = selected.data(AccountList::PointerRole).value<MinecraftAccountPtr>();
- m_accounts->setActiveAccount(account->profileId());
+ m_accounts->setDefaultAccount(account);
}
}
void AccountListPage::on_actionNoDefault_triggered()
{
- m_accounts->setActiveAccount("");
+ m_accounts->setDefaultAccount(nullptr);
}
void AccountListPage::updateButtonStates()
{
// If there is no selection, disable buttons that require something selected.
QModelIndexList selection = ui->listView->selectionModel()->selectedIndexes();
+ bool hasSelection = selection.size() > 0;
+ bool accountIsReady = false;
+ if (hasSelection)
+ {
+ QModelIndex selected = selection.first();
+ MinecraftAccountPtr account = selected.data(AccountList::PointerRole).value<MinecraftAccountPtr>();
+ accountIsReady = !account->isActive();
+ }
+ ui->actionRemove->setEnabled(accountIsReady);
+ ui->actionSetDefault->setEnabled(accountIsReady);
+ ui->actionUploadSkin->setEnabled(accountIsReady);
+ ui->actionDeleteSkin->setEnabled(accountIsReady);
+ ui->actionRefresh->setEnabled(accountIsReady);
- ui->actionRemove->setEnabled(selection.size() > 0);
- ui->actionSetDefault->setEnabled(selection.size() > 0);
- ui->actionUploadSkin->setEnabled(selection.size() > 0);
- ui->actionDeleteSkin->setEnabled(selection.size() > 0);
- ui->actionRefresh->setEnabled(selection.size() > 0);
-
- if(m_accounts->activeAccount().get() == nullptr) {
+ if(m_accounts->defaultAccount().get() == nullptr) {
ui->actionNoDefault->setEnabled(false);
ui->actionNoDefault->setChecked(true);
}
@@ -215,7 +217,6 @@ void AccountListPage::updateButtonStates()
ui->actionNoDefault->setEnabled(true);
ui->actionNoDefault->setChecked(false);
}
-
}
void AccountListPage::on_actionUploadSkin_triggered()
@@ -237,15 +238,9 @@ void AccountListPage::on_actionDeleteSkin_triggered()
return;
QModelIndex selected = selection.first();
- AuthSessionPtr session = std::make_shared<AuthSession>();
MinecraftAccountPtr account = selected.data(AccountList::PointerRole).value<MinecraftAccountPtr>();
- auto login = account->refresh(session);
ProgressDialog prog(this);
- if (prog.execWithTask((Task*)login.get()) != QDialog::Accepted) {
- CustomMessageBox::selectable(this, tr("Skin Delete"), tr("Failed to login!"), QMessageBox::Warning)->exec();
- return;
- }
- auto deleteSkinTask = std::make_shared<SkinDelete>(this, session);
+ auto deleteSkinTask = std::make_shared<SkinDelete>(this, account->accessToken());
if (prog.execWithTask((Task*)deleteSkinTask.get()) != QDialog::Accepted) {
CustomMessageBox::selectable(this, tr("Skin Delete"), tr("Failed to delete current skin!"), QMessageBox::Warning)->exec();
return;
diff --git a/launcher/pages/global/AccountListPage.h b/launcher/ui/pages/global/AccountListPage.h
index ee81acd1..1c65e708 100644
--- a/launcher/pages/global/AccountListPage.h
+++ b/launcher/ui/pages/global/AccountListPage.h
@@ -18,10 +18,10 @@
#include <QMainWindow>
#include <memory>
-#include "pages/BasePage.h"
+#include "ui/pages/BasePage.h"
#include "minecraft/auth/AccountList.h"
-#include "Launcher.h"
+#include "Application.h"
namespace Ui
{
@@ -43,10 +43,10 @@ public:
}
QIcon icon() const override
{
- auto icon = LAUNCHER->getThemedIcon("accounts");
+ auto icon = APPLICATION->getThemedIcon("accounts");
if(icon.isNull())
{
- icon = LAUNCHER->getThemedIcon("noaccount");
+ icon = APPLICATION->getThemedIcon("noaccount");
}
return icon;
}
@@ -80,6 +80,6 @@ protected slots:
private:
void changeEvent(QEvent * event) override;
QMenu * createPopupMenu() override;
- std::shared_ptr<AccountList> m_accounts;
+ shared_qobject_ptr<AccountList> m_accounts;
Ui::AccountListPage *ui;
};
diff --git a/launcher/pages/global/AccountListPage.ui b/launcher/ui/pages/global/AccountListPage.ui
index 8af23a2f..29738c02 100644
--- a/launcher/pages/global/AccountListPage.ui
+++ b/launcher/ui/pages/global/AccountListPage.ui
@@ -116,12 +116,12 @@
<customwidget>
<class>VersionListView</class>
<extends>QTreeView</extends>
- <header>widgets/VersionListView.h</header>
+ <header>ui/widgets/VersionListView.h</header>
</customwidget>
<customwidget>
<class>WideBar</class>
<extends>QToolBar</extends>
- <header>widgets/WideBar.h</header>
+ <header>ui/widgets/WideBar.h</header>
</customwidget>
</customwidgets>
<resources/>
diff --git a/launcher/pages/global/CustomCommandsPage.cpp b/launcher/ui/pages/global/CustomCommandsPage.cpp
index 8a5c3445..8541e3c1 100644
--- a/launcher/pages/global/CustomCommandsPage.cpp
+++ b/launcher/ui/pages/global/CustomCommandsPage.cpp
@@ -32,7 +32,7 @@ bool CustomCommandsPage::apply()
void CustomCommandsPage::applySettings()
{
- auto s = LAUNCHER->settings();
+ auto s = APPLICATION->settings();
s->set("PreLaunchCommand", commands->prelaunchCommand());
s->set("WrapperCommand", commands->wrapperCommand());
s->set("PostExitCommand", commands->postexitCommand());
@@ -40,7 +40,7 @@ void CustomCommandsPage::applySettings()
void CustomCommandsPage::loadSettings()
{
- auto s = LAUNCHER->settings();
+ auto s = APPLICATION->settings();
commands->initialize(
false,
true,
diff --git a/launcher/pages/global/CustomCommandsPage.h b/launcher/ui/pages/global/CustomCommandsPage.h
index ac69a997..a1155e0e 100644
--- a/launcher/pages/global/CustomCommandsPage.h
+++ b/launcher/ui/pages/global/CustomCommandsPage.h
@@ -18,9 +18,9 @@
#include <memory>
#include <QDialog>
-#include "pages/BasePage.h"
-#include <Launcher.h>
-#include "widgets/CustomCommands.h"
+#include "ui/pages/BasePage.h"
+#include <Application.h>
+#include "ui/widgets/CustomCommands.h"
class CustomCommandsPage : public QWidget, public BasePage
{
@@ -36,7 +36,7 @@ public:
}
QIcon icon() const override
{
- return LAUNCHER->getThemedIcon("custom-commands");
+ return APPLICATION->getThemedIcon("custom-commands");
}
QString id() const override
{
diff --git a/launcher/pages/global/ExternalToolsPage.cpp b/launcher/ui/pages/global/ExternalToolsPage.cpp
index 7e1a915f..41d900aa 100644
--- a/launcher/pages/global/ExternalToolsPage.cpp
+++ b/launcher/ui/pages/global/ExternalToolsPage.cpp
@@ -24,7 +24,7 @@
#include "settings/SettingsObject.h"
#include "tools/BaseProfiler.h"
#include <FileSystem.h>
-#include "Launcher.h"
+#include "Application.h"
#include <tools/MCEditTool.h>
ExternalToolsPage::ExternalToolsPage(QWidget *parent) :
@@ -51,7 +51,7 @@ ExternalToolsPage::~ExternalToolsPage()
void ExternalToolsPage::loadSettings()
{
- auto s = LAUNCHER->settings();
+ auto s = APPLICATION->settings();
ui->jprofilerPathEdit->setText(s->get("JProfilerPath").toString());
ui->jvisualvmPathEdit->setText(s->get("JVisualVMPath").toString());
ui->mceditPathEdit->setText(s->get("MCEditPath").toString());
@@ -61,7 +61,7 @@ void ExternalToolsPage::loadSettings()
}
void ExternalToolsPage::applySettings()
{
- auto s = LAUNCHER->settings();
+ auto s = APPLICATION->settings();
s->set("JProfilerPath", ui->jprofilerPathEdit->text());
s->set("JVisualVMPath", ui->jvisualvmPathEdit->text());
@@ -93,7 +93,7 @@ void ExternalToolsPage::on_jprofilerPathBtn_clicked()
break;
}
QString cooked_dir = FS::NormalizePath(raw_dir);
- if (!LAUNCHER->profilers()["jprofiler"]->check(cooked_dir, &error))
+ if (!APPLICATION->profilers()["jprofiler"]->check(cooked_dir, &error))
{
QMessageBox::critical(this, tr("Error"), tr("Error while checking JProfiler install:\n%1").arg(error));
continue;
@@ -108,7 +108,7 @@ void ExternalToolsPage::on_jprofilerPathBtn_clicked()
void ExternalToolsPage::on_jprofilerCheckBtn_clicked()
{
QString error;
- if (!LAUNCHER->profilers()["jprofiler"]->check(ui->jprofilerPathEdit->text(), &error))
+ if (!APPLICATION->profilers()["jprofiler"]->check(ui->jprofilerPathEdit->text(), &error))
{
QMessageBox::critical(this, tr("Error"), tr("Error while checking JProfiler install:\n%1").arg(error));
}
@@ -130,7 +130,7 @@ void ExternalToolsPage::on_jvisualvmPathBtn_clicked()
break;
}
QString cooked_dir = FS::NormalizePath(raw_dir);
- if (!LAUNCHER->profilers()["jvisualvm"]->check(cooked_dir, &error))
+ if (!APPLICATION->profilers()["jvisualvm"]->check(cooked_dir, &error))
{
QMessageBox::critical(this, tr("Error"), tr("Error while checking JVisualVM install:\n%1").arg(error));
continue;
@@ -145,7 +145,7 @@ void ExternalToolsPage::on_jvisualvmPathBtn_clicked()
void ExternalToolsPage::on_jvisualvmCheckBtn_clicked()
{
QString error;
- if (!LAUNCHER->profilers()["jvisualvm"]->check(ui->jvisualvmPathEdit->text(), &error))
+ if (!APPLICATION->profilers()["jvisualvm"]->check(ui->jvisualvmPathEdit->text(), &error))
{
QMessageBox::critical(this, tr("Error"), tr("Error while checking JVisualVM install:\n%1").arg(error));
}
@@ -171,7 +171,7 @@ void ExternalToolsPage::on_mceditPathBtn_clicked()
break;
}
QString cooked_dir = FS::NormalizePath(raw_dir);
- if (!LAUNCHER->mcedit()->check(cooked_dir, error))
+ if (!APPLICATION->mcedit()->check(cooked_dir, error))
{
QMessageBox::critical(this, tr("Error"), tr("Error while checking MCEdit install:\n%1").arg(error));
continue;
@@ -186,7 +186,7 @@ void ExternalToolsPage::on_mceditPathBtn_clicked()
void ExternalToolsPage::on_mceditCheckBtn_clicked()
{
QString error;
- if (!LAUNCHER->mcedit()->check(ui->mceditPathEdit->text(), error))
+ if (!APPLICATION->mcedit()->check(ui->mceditPathEdit->text(), error))
{
QMessageBox::critical(this, tr("Error"), tr("Error while checking MCEdit install:\n%1").arg(error));
}
diff --git a/launcher/pages/global/ExternalToolsPage.h b/launcher/ui/pages/global/ExternalToolsPage.h
index 1d99273a..5ae6148d 100644
--- a/launcher/pages/global/ExternalToolsPage.h
+++ b/launcher/ui/pages/global/ExternalToolsPage.h
@@ -17,8 +17,8 @@
#include <QWidget>
-#include "pages/BasePage.h"
-#include <Launcher.h>
+#include "ui/pages/BasePage.h"
+#include <Application.h>
namespace Ui {
class ExternalToolsPage;
@@ -38,10 +38,10 @@ public:
}
QIcon icon() const override
{
- auto icon = LAUNCHER->getThemedIcon("externaltools");
+ auto icon = APPLICATION->getThemedIcon("externaltools");
if(icon.isNull())
{
- icon = LAUNCHER->getThemedIcon("loadermods");
+ icon = APPLICATION->getThemedIcon("loadermods");
}
return icon;
}
diff --git a/launcher/pages/global/ExternalToolsPage.ui b/launcher/ui/pages/global/ExternalToolsPage.ui
index e79e9388..e79e9388 100644
--- a/launcher/pages/global/ExternalToolsPage.ui
+++ b/launcher/ui/pages/global/ExternalToolsPage.ui
diff --git a/launcher/pages/global/JavaPage.cpp b/launcher/ui/pages/global/JavaPage.cpp
index dd158fcd..bd79f11a 100644
--- a/launcher/pages/global/JavaPage.cpp
+++ b/launcher/ui/pages/global/JavaPage.cpp
@@ -22,14 +22,14 @@
#include <QDir>
#include <QTabBar>
-#include "dialogs/VersionSelectDialog.h"
+#include "ui/dialogs/VersionSelectDialog.h"
#include "java/JavaUtils.h"
#include "java/JavaInstallList.h"
#include "settings/SettingsObject.h"
#include <FileSystem.h>
-#include "Launcher.h"
+#include "Application.h"
#include <sys.h>
JavaPage::JavaPage(QWidget *parent) : QWidget(parent), ui(new Ui::JavaPage)
@@ -55,7 +55,7 @@ bool JavaPage::apply()
void JavaPage::applySettings()
{
- auto s = LAUNCHER->settings();
+ auto s = APPLICATION->settings();
// Memory
int min = ui->minMemSpinBox->value();
@@ -79,7 +79,7 @@ void JavaPage::applySettings()
}
void JavaPage::loadSettings()
{
- auto s = LAUNCHER->settings();
+ auto s = APPLICATION->settings();
// Memory
int min = s->get("MinMemAlloc").toInt();
int max = s->get("MaxMemAlloc").toInt();
@@ -104,7 +104,7 @@ void JavaPage::on_javaDetectBtn_clicked()
{
JavaInstallPtr java;
- VersionSelectDialog vselect(LAUNCHER->javalist().get(), tr("Select a Java version"), this, true);
+ VersionSelectDialog vselect(APPLICATION->javalist().get(), tr("Select a Java version"), this, true);
vselect.setResizeOn(2);
vselect.exec();
diff --git a/launcher/pages/global/JavaPage.h b/launcher/ui/pages/global/JavaPage.h
index 93a586cd..8f9b3323 100644
--- a/launcher/pages/global/JavaPage.h
+++ b/launcher/ui/pages/global/JavaPage.h
@@ -17,9 +17,9 @@
#include <memory>
#include <QDialog>
-#include "pages/BasePage.h"
+#include "ui/pages/BasePage.h"
#include "JavaCommon.h"
-#include <Launcher.h>
+#include <Application.h>
#include <QObjectPtr.h>
class SettingsObject;
@@ -43,7 +43,7 @@ public:
}
QIcon icon() const override
{
- return LAUNCHER->getThemedIcon("java");
+ return APPLICATION->getThemedIcon("java");
}
QString id() const override
{
diff --git a/launcher/pages/global/JavaPage.ui b/launcher/ui/pages/global/JavaPage.ui
index b67e9994..b67e9994 100644
--- a/launcher/pages/global/JavaPage.ui
+++ b/launcher/ui/pages/global/JavaPage.ui
diff --git a/launcher/pages/global/LanguagePage.cpp b/launcher/ui/pages/global/LanguagePage.cpp
index 409bf7d0..359fdeeb 100644
--- a/launcher/pages/global/LanguagePage.cpp
+++ b/launcher/ui/pages/global/LanguagePage.cpp
@@ -1,6 +1,6 @@
#include "LanguagePage.h"
-#include "widgets/LanguageSelectionWidget.h"
+#include "ui/widgets/LanguageSelectionWidget.h"
#include <QVBoxLayout>
LanguagePage::LanguagePage(QWidget* parent) :
@@ -26,7 +26,7 @@ bool LanguagePage::apply()
void LanguagePage::applySettings()
{
- auto settings = LAUNCHER->settings();
+ auto settings = APPLICATION->settings();
QString key = mainWidget->getSelectedLanguageKey();
settings->set("Language", key);
}
diff --git a/launcher/pages/global/LanguagePage.h b/launcher/ui/pages/global/LanguagePage.h
index 22db8f94..b1dd05ad 100644
--- a/launcher/pages/global/LanguagePage.h
+++ b/launcher/ui/pages/global/LanguagePage.h
@@ -16,8 +16,8 @@
#pragma once
#include <memory>
-#include "pages/BasePage.h"
-#include <Launcher.h>
+#include "ui/pages/BasePage.h"
+#include <Application.h>
#include <QWidget>
class LanguageSelectionWidget;
@@ -36,7 +36,7 @@ public:
}
QIcon icon() const override
{
- return LAUNCHER->getThemedIcon("language");
+ return APPLICATION->getThemedIcon("language");
}
QString id() const override
{
diff --git a/launcher/pages/global/LauncherPage.cpp b/launcher/ui/pages/global/LauncherPage.cpp
index 5f8d87d8..2eb73e44 100644
--- a/launcher/pages/global/LauncherPage.cpp
+++ b/launcher/ui/pages/global/LauncherPage.cpp
@@ -25,9 +25,9 @@
#include "settings/SettingsObject.h"
#include <FileSystem.h>
-#include "Launcher.h"
+#include "Application.h"
#include "BuildConfig.h"
-#include "themes/ITheme.h"
+#include "ui/themes/ITheme.h"
#include <QApplication>
#include <QProcess>
@@ -53,20 +53,20 @@ LauncherPage::LauncherPage(QWidget *parent) : QWidget(parent), ui(new Ui::Launch
defaultFormat = new QTextCharFormat(ui->fontPreview->currentCharFormat());
- m_languageModel = LAUNCHER->translations();
+ m_languageModel = APPLICATION->translations();
loadSettings();
if(BuildConfig.UPDATER_ENABLED)
{
- QObject::connect(LAUNCHER->updateChecker().get(), &UpdateChecker::channelListLoaded, this, &LauncherPage::refreshUpdateChannelList);
+ QObject::connect(APPLICATION->updateChecker().get(), &UpdateChecker::channelListLoaded, this, &LauncherPage::refreshUpdateChannelList);
- if (LAUNCHER->updateChecker()->hasChannels())
+ if (APPLICATION->updateChecker()->hasChannels())
{
refreshUpdateChannelList();
}
else
{
- LAUNCHER->updateChecker()->updateChanList(false);
+ APPLICATION->updateChecker()->updateChanList(false);
}
}
else
@@ -171,7 +171,7 @@ void LauncherPage::refreshUpdateChannelList()
QObject::disconnect(ui->updateChannelComboBox, SIGNAL(currentIndexChanged(int)), this,
SLOT(updateChannelSelectionChanged(int)));
- QList<UpdateChecker::ChannelListEntry> channelList = LAUNCHER->updateChecker()->getChannelList();
+ QList<UpdateChecker::ChannelListEntry> channelList = APPLICATION->updateChecker()->getChannelList();
ui->updateChannelComboBox->clear();
int selection = -1;
for (int i = 0; i < channelList.count(); i++)
@@ -216,7 +216,7 @@ void LauncherPage::updateChannelSelectionChanged(int index)
void LauncherPage::refreshUpdateChannelDesc()
{
// Get the channel list.
- QList<UpdateChecker::ChannelListEntry> channelList = LAUNCHER->updateChecker()->getChannelList();
+ QList<UpdateChecker::ChannelListEntry> channelList = APPLICATION->updateChecker()->getChannelList();
int selectedIndex = ui->updateChannelComboBox->currentIndex();
if (selectedIndex < 0)
{
@@ -237,7 +237,7 @@ void LauncherPage::refreshUpdateChannelDesc()
void LauncherPage::applySettings()
{
- auto s = LAUNCHER->settings();
+ auto s = APPLICATION->settings();
if (ui->resetNotificationsBtn->isChecked())
{
@@ -283,7 +283,7 @@ void LauncherPage::applySettings()
if(original != s->get("IconTheme"))
{
- LAUNCHER->setIconTheme(s->get("IconTheme").toString());
+ APPLICATION->setIconTheme(s->get("IconTheme").toString());
}
auto originalAppTheme = s->get("ApplicationTheme").toString();
@@ -291,7 +291,7 @@ void LauncherPage::applySettings()
if(originalAppTheme != newAppTheme)
{
s->set("ApplicationTheme", newAppTheme);
- LAUNCHER->setApplicationTheme(newAppTheme, false);
+ APPLICATION->setApplicationTheme(newAppTheme, false);
}
// Console settings
@@ -330,7 +330,7 @@ void LauncherPage::applySettings()
}
void LauncherPage::loadSettings()
{
- auto s = LAUNCHER->settings();
+ auto s = APPLICATION->settings();
// Updates
ui->autoUpdateCheckBox->setChecked(s->get("AutoUpdate").toBool());
m_currentUpdateChannel = s->get("UpdateChannel").toString();
@@ -375,7 +375,7 @@ void LauncherPage::loadSettings()
{
auto currentTheme = s->get("ApplicationTheme").toString();
- auto themes = LAUNCHER->getValidApplicationThemes();
+ auto themes = APPLICATION->getValidApplicationThemes();
int idx = 0;
for(auto &theme: themes)
{
@@ -392,12 +392,12 @@ void LauncherPage::loadSettings()
ui->showConsoleCheck->setChecked(s->get("ShowConsole").toBool());
ui->autoCloseConsoleCheck->setChecked(s->get("AutoCloseConsole").toBool());
ui->showConsoleErrorCheck->setChecked(s->get("ShowConsoleOnError").toBool());
- QString fontFamily = LAUNCHER->settings()->get("ConsoleFont").toString();
+ QString fontFamily = APPLICATION->settings()->get("ConsoleFont").toString();
QFont consoleFont(fontFamily);
ui->consoleFont->setCurrentFont(consoleFont);
bool conversionOk = true;
- int fontSize = LAUNCHER->settings()->get("ConsoleFontSize").toInt(&conversionOk);
+ int fontSize = APPLICATION->settings()->get("ConsoleFontSize").toInt(&conversionOk);
if(!conversionOk)
{
fontSize = 11;
diff --git a/launcher/pages/global/LauncherPage.h b/launcher/ui/pages/global/LauncherPage.h
index e622ec48..4d0cf3c9 100644
--- a/launcher/pages/global/LauncherPage.h
+++ b/launcher/ui/pages/global/LauncherPage.h
@@ -19,9 +19,9 @@
#include <QDialog>
#include "java/JavaChecker.h"
-#include "pages/BasePage.h"
-#include <Launcher.h>
-#include "ColorCache.h"
+#include "ui/pages/BasePage.h"
+#include <Application.h>
+#include "ui/ColorCache.h"
#include <translations/TranslationsModel.h>
class QTextCharFormat;
@@ -46,7 +46,7 @@ public:
}
QIcon icon() const override
{
- return LAUNCHER->getThemedIcon("launcher");
+ return APPLICATION->getThemedIcon("launcher");
}
QString id() const override
{
diff --git a/launcher/pages/global/LauncherPage.ui b/launcher/ui/pages/global/LauncherPage.ui
index 62a66d73..62a66d73 100644
--- a/launcher/pages/global/LauncherPage.ui
+++ b/launcher/ui/pages/global/LauncherPage.ui
diff --git a/launcher/pages/global/MinecraftPage.cpp b/launcher/ui/pages/global/MinecraftPage.cpp
index 342941f4..c763f8ac 100644
--- a/launcher/pages/global/MinecraftPage.cpp
+++ b/launcher/ui/pages/global/MinecraftPage.cpp
@@ -21,7 +21,7 @@
#include <QTabBar>
#include "settings/SettingsObject.h"
-#include "Launcher.h"
+#include "Application.h"
MinecraftPage::MinecraftPage(QWidget *parent) : QWidget(parent), ui(new Ui::MinecraftPage)
{
@@ -56,7 +56,7 @@ void MinecraftPage::on_maximizedCheckBox_clicked(bool checked)
void MinecraftPage::applySettings()
{
- auto s = LAUNCHER->settings();
+ auto s = APPLICATION->settings();
// Window Size
s->set("LaunchMaximized", ui->maximizedCheckBox->isChecked());
@@ -75,7 +75,7 @@ void MinecraftPage::applySettings()
void MinecraftPage::loadSettings()
{
- auto s = LAUNCHER->settings();
+ auto s = APPLICATION->settings();
// Window Size
ui->maximizedCheckBox->setChecked(s->get("LaunchMaximized").toBool());
diff --git a/launcher/pages/global/MinecraftPage.h b/launcher/ui/pages/global/MinecraftPage.h
index 0fc6cc8e..42626d94 100644
--- a/launcher/pages/global/MinecraftPage.h
+++ b/launcher/ui/pages/global/MinecraftPage.h
@@ -19,8 +19,8 @@
#include <QDialog>
#include "java/JavaChecker.h"
-#include "pages/BasePage.h"
-#include <Launcher.h>
+#include "ui/pages/BasePage.h"
+#include <Application.h>
class SettingsObject;
@@ -43,7 +43,7 @@ public:
}
QIcon icon() const override
{
- return LAUNCHER->getThemedIcon("minecraft");
+ return APPLICATION->getThemedIcon("minecraft");
}
QString id() const override
{
diff --git a/launcher/pages/global/MinecraftPage.ui b/launcher/ui/pages/global/MinecraftPage.ui
index 857b8cfb..857b8cfb 100644
--- a/launcher/pages/global/MinecraftPage.ui
+++ b/launcher/ui/pages/global/MinecraftPage.ui
diff --git a/launcher/pages/global/PasteEEPage.cpp b/launcher/ui/pages/global/PasteEEPage.cpp
index 9f7a7efb..4b375d9a 100644
--- a/launcher/pages/global/PasteEEPage.cpp
+++ b/launcher/ui/pages/global/PasteEEPage.cpp
@@ -23,7 +23,7 @@
#include "settings/SettingsObject.h"
#include "tools/BaseProfiler.h"
-#include "Launcher.h"
+#include "Application.h"
PasteEEPage::PasteEEPage(QWidget *parent) :
QWidget(parent),
@@ -42,7 +42,7 @@ PasteEEPage::~PasteEEPage()
void PasteEEPage::loadSettings()
{
- auto s = LAUNCHER->settings();
+ auto s = APPLICATION->settings();
QString keyToUse = s->get("PasteEEAPIKey").toString();
if(keyToUse == "multimc")
{
@@ -57,7 +57,7 @@ void PasteEEPage::loadSettings()
void PasteEEPage::applySettings()
{
- auto s = LAUNCHER->settings();
+ auto s = APPLICATION->settings();
QString pasteKeyToUse;
if (ui->customButton->isChecked())
diff --git a/launcher/pages/global/PasteEEPage.h b/launcher/ui/pages/global/PasteEEPage.h
index c99cd51e..a1c7d434 100644
--- a/launcher/pages/global/PasteEEPage.h
+++ b/launcher/ui/pages/global/PasteEEPage.h
@@ -17,8 +17,8 @@
#include <QWidget>
-#include "pages/BasePage.h"
-#include <Launcher.h>
+#include "ui/pages/BasePage.h"
+#include <Application.h>
namespace Ui {
class PasteEEPage;
@@ -38,7 +38,7 @@ public:
}
QIcon icon() const override
{
- return LAUNCHER->getThemedIcon("log");
+ return APPLICATION->getThemedIcon("log");
}
QString id() const override
{
diff --git a/launcher/pages/global/PasteEEPage.ui b/launcher/ui/pages/global/PasteEEPage.ui
index 10883781..10883781 100644
--- a/launcher/pages/global/PasteEEPage.ui
+++ b/launcher/ui/pages/global/PasteEEPage.ui
diff --git a/launcher/pages/global/ProxyPage.cpp b/launcher/ui/pages/global/ProxyPage.cpp
index d4e767e1..5bc8199e 100644
--- a/launcher/pages/global/ProxyPage.cpp
+++ b/launcher/ui/pages/global/ProxyPage.cpp
@@ -19,8 +19,8 @@
#include <QTabBar>
#include "settings/SettingsObject.h"
-#include "Launcher.h"
-#include "Env.h"
+#include "Application.h"
+#include "Application.h"
ProxyPage::ProxyPage(QWidget *parent) : QWidget(parent), ui(new Ui::ProxyPage)
{
@@ -58,7 +58,7 @@ void ProxyPage::proxyChanged(int)
void ProxyPage::applySettings()
{
- auto s = LAUNCHER->settings();
+ auto s = APPLICATION->settings();
// Proxy
QString proxyType = "None";
@@ -77,12 +77,17 @@ void ProxyPage::applySettings()
s->set("ProxyUser", ui->proxyUserEdit->text());
s->set("ProxyPass", ui->proxyPassEdit->text());
- ENV.updateProxySettings(proxyType, ui->proxyAddrEdit->text(), ui->proxyPortEdit->value(),
- ui->proxyUserEdit->text(), ui->proxyPassEdit->text());
+ APPLICATION->updateProxySettings(
+ proxyType,
+ ui->proxyAddrEdit->text(),
+ ui->proxyPortEdit->value(),
+ ui->proxyUserEdit->text(),
+ ui->proxyPassEdit->text()
+ );
}
void ProxyPage::loadSettings()
{
- auto s = LAUNCHER->settings();
+ auto s = APPLICATION->settings();
// Proxy
QString proxyType = s->get("ProxyType").toString();
if (proxyType == "Default")
diff --git a/launcher/pages/global/ProxyPage.h b/launcher/ui/pages/global/ProxyPage.h
index 90c33c9d..6698c349 100644
--- a/launcher/pages/global/ProxyPage.h
+++ b/launcher/ui/pages/global/ProxyPage.h
@@ -18,8 +18,8 @@
#include <memory>
#include <QDialog>
-#include "pages/BasePage.h"
-#include <Launcher.h>
+#include "ui/pages/BasePage.h"
+#include <Application.h>
namespace Ui
{
@@ -40,7 +40,7 @@ public:
}
QIcon icon() const override
{
- return LAUNCHER->getThemedIcon("proxy");
+ return APPLICATION->getThemedIcon("proxy");
}
QString id() const override
{
diff --git a/launcher/pages/global/ProxyPage.ui b/launcher/ui/pages/global/ProxyPage.ui
index 347fa86c..347fa86c 100644
--- a/launcher/pages/global/ProxyPage.ui
+++ b/launcher/ui/pages/global/ProxyPage.ui
diff --git a/launcher/pages/instance/GameOptionsPage.cpp b/launcher/ui/pages/instance/GameOptionsPage.cpp
index 782f2ab3..782f2ab3 100644
--- a/launcher/pages/instance/GameOptionsPage.cpp
+++ b/launcher/ui/pages/instance/GameOptionsPage.cpp
diff --git a/launcher/pages/instance/GameOptionsPage.h b/launcher/ui/pages/instance/GameOptionsPage.h
index ca7e31b1..878903eb 100644
--- a/launcher/pages/instance/GameOptionsPage.h
+++ b/launcher/ui/pages/instance/GameOptionsPage.h
@@ -18,8 +18,8 @@
#include <QWidget>
#include <QString>
-#include "pages/BasePage.h"
-#include <Launcher.h>
+#include "ui/pages/BasePage.h"
+#include <Application.h>
namespace Ui
{
@@ -46,7 +46,7 @@ public:
}
virtual QIcon icon() const override
{
- return LAUNCHER->getThemedIcon("settings");
+ return APPLICATION->getThemedIcon("settings");
}
virtual QString id() const override
{
diff --git a/launcher/pages/instance/GameOptionsPage.ui b/launcher/ui/pages/instance/GameOptionsPage.ui
index f0a5ce0e..f0a5ce0e 100644
--- a/launcher/pages/instance/GameOptionsPage.ui
+++ b/launcher/ui/pages/instance/GameOptionsPage.ui
diff --git a/launcher/pages/instance/InstanceSettingsPage.cpp b/launcher/ui/pages/instance/InstanceSettingsPage.cpp
index c83832c6..b0e18af4 100644
--- a/launcher/pages/instance/InstanceSettingsPage.cpp
+++ b/launcher/ui/pages/instance/InstanceSettingsPage.cpp
@@ -5,14 +5,17 @@
#include <QDialog>
#include <QMessageBox>
-#include "dialogs/VersionSelectDialog.h"
+#include <sys.h>
+
+#include "ui/dialogs/VersionSelectDialog.h"
+#include "ui/widgets/CustomCommands.h"
+
#include "JavaCommon.h"
-#include "Launcher.h"
+#include "Application.h"
+
+#include "java/JavaInstallList.h"
+#include "FileSystem.h"
-#include <java/JavaInstallList.h>
-#include <FileSystem.h>
-#include <sys.h>
-#include <widgets/CustomCommands.h>
InstanceSettingsPage::InstanceSettingsPage(BaseInstance *inst, QWidget *parent)
: QWidget(parent), ui(new Ui::InstanceSettingsPage), m_instance(inst)
@@ -22,8 +25,8 @@ InstanceSettingsPage::InstanceSettingsPage(BaseInstance *inst, QWidget *parent)
auto sysMB = Sys::getSystemRam() / Sys::mebibyte;
ui->maxMemSpinBox->setMaximum(sysMB);
connect(ui->openGlobalJavaSettingsButton, &QCommandLinkButton::clicked, this, &InstanceSettingsPage::globalSettingsButtonClicked);
- connect(LAUNCHER, &Launcher::globalSettingsAboutToOpen, this, &InstanceSettingsPage::applySettings);
- connect(LAUNCHER, &Launcher::globalSettingsClosed, this, &InstanceSettingsPage::loadSettings);
+ connect(APPLICATION, &Application::globalSettingsAboutToOpen, this, &InstanceSettingsPage::applySettings);
+ connect(APPLICATION, &Application::globalSettingsClosed, this, &InstanceSettingsPage::loadSettings);
loadSettings();
}
@@ -41,13 +44,13 @@ void InstanceSettingsPage::globalSettingsButtonClicked(bool)
{
switch(ui->settingsTabs->currentIndex()) {
case 0:
- LAUNCHER->ShowGlobalSettings(this, "java-settings");
+ APPLICATION->ShowGlobalSettings(this, "java-settings");
return;
case 1:
- LAUNCHER->ShowGlobalSettings(this, "minecraft-settings");
+ APPLICATION->ShowGlobalSettings(this, "minecraft-settings");
return;
case 2:
- LAUNCHER->ShowGlobalSettings(this, "custom-commands");
+ APPLICATION->ShowGlobalSettings(this, "custom-commands");
return;
}
}
@@ -278,7 +281,7 @@ void InstanceSettingsPage::on_javaDetectBtn_clicked()
{
JavaInstallPtr java;
- VersionSelectDialog vselect(LAUNCHER->javalist().get(), tr("Select a Java version"), this, true);
+ VersionSelectDialog vselect(APPLICATION->javalist().get(), tr("Select a Java version"), this, true);
vselect.setResizeOn(2);
vselect.exec();
diff --git a/launcher/pages/instance/InstanceSettingsPage.h b/launcher/ui/pages/instance/InstanceSettingsPage.h
index a039101c..5c8c8e66 100644
--- a/launcher/pages/instance/InstanceSettingsPage.h
+++ b/launcher/ui/pages/instance/InstanceSettingsPage.h
@@ -20,9 +20,9 @@
#include "java/JavaChecker.h"
#include "BaseInstance.h"
#include <QObjectPtr.h>
-#include "pages/BasePage.h"
+#include "ui/pages/BasePage.h"
#include "JavaCommon.h"
-#include "Launcher.h"
+#include "Application.h"
class JavaChecker;
namespace Ui
@@ -43,7 +43,7 @@ public:
}
virtual QIcon icon() const override
{
- return LAUNCHER->getThemedIcon("instance-settings");
+ return APPLICATION->getThemedIcon("instance-settings");
}
virtual QString id() const override
{
diff --git a/launcher/pages/instance/InstanceSettingsPage.ui b/launcher/ui/pages/instance/InstanceSettingsPage.ui
index 35cd7335..729f8e2a 100644
--- a/launcher/pages/instance/InstanceSettingsPage.ui
+++ b/launcher/ui/pages/instance/InstanceSettingsPage.ui
@@ -511,7 +511,7 @@
<customwidget>
<class>CustomCommands</class>
<extends>QWidget</extends>
- <header>widgets/CustomCommands.h</header>
+ <header>ui/widgets/CustomCommands.h</header>
<container>1</container>
</customwidget>
</customwidgets>
diff --git a/launcher/pages/instance/LegacyUpgradePage.cpp b/launcher/ui/pages/instance/LegacyUpgradePage.cpp
index b12174fa..cb78af02 100644
--- a/launcher/pages/instance/LegacyUpgradePage.cpp
+++ b/launcher/ui/pages/instance/LegacyUpgradePage.cpp
@@ -4,9 +4,10 @@
#include "InstanceList.h"
#include "minecraft/legacy/LegacyInstance.h"
#include "minecraft/legacy/LegacyUpgradeTask.h"
-#include "Launcher.h"
-#include "dialogs/CustomMessageBox.h"
-#include "dialogs/ProgressDialog.h"
+#include "Application.h"
+
+#include "ui/dialogs/CustomMessageBox.h"
+#include "ui/dialogs/ProgressDialog.h"
LegacyUpgradePage::LegacyUpgradePage(InstancePtr inst, QWidget *parent)
: QWidget(parent), ui(new Ui::LegacyUpgradePage), m_inst(inst)
@@ -38,9 +39,9 @@ void LegacyUpgradePage::on_upgradeButton_clicked()
QString newName = tr("%1 (Migrated)").arg(m_inst->name());
auto upgradeTask = new LegacyUpgradeTask(m_inst);
upgradeTask->setName(newName);
- upgradeTask->setGroup(LAUNCHER->instances()->getInstanceGroup(m_inst->id()));
+ upgradeTask->setGroup(APPLICATION->instances()->getInstanceGroup(m_inst->id()));
upgradeTask->setIcon(m_inst->iconKey());
- unique_qobject_ptr<Task> task(LAUNCHER->instances()->wrapInstanceTask(upgradeTask));
+ unique_qobject_ptr<Task> task(APPLICATION->instances()->wrapInstanceTask(upgradeTask));
runModalTask(task.get());
}
diff --git a/launcher/pages/instance/LegacyUpgradePage.h b/launcher/ui/pages/instance/LegacyUpgradePage.h
index d8e98f6b..7c51956b 100644
--- a/launcher/pages/instance/LegacyUpgradePage.h
+++ b/launcher/ui/pages/instance/LegacyUpgradePage.h
@@ -18,8 +18,8 @@
#include <QWidget>
#include "minecraft/legacy/LegacyInstance.h"
-#include "pages/BasePage.h"
-#include <Launcher.h>
+#include "ui/pages/BasePage.h"
+#include <Application.h>
#include "tasks/Task.h"
namespace Ui
@@ -40,7 +40,7 @@ public:
}
virtual QIcon icon() const override
{
- return LAUNCHER->getThemedIcon("checkupdate");
+ return APPLICATION->getThemedIcon("checkupdate");
}
virtual QString id() const override
{
diff --git a/launcher/pages/instance/LegacyUpgradePage.ui b/launcher/ui/pages/instance/LegacyUpgradePage.ui
index 085919e3..085919e3 100644
--- a/launcher/pages/instance/LegacyUpgradePage.ui
+++ b/launcher/ui/pages/instance/LegacyUpgradePage.ui
diff --git a/launcher/pages/instance/LogPage.cpp b/launcher/ui/pages/instance/LogPage.cpp
index 2846dc51..b66c6cc7 100644
--- a/launcher/pages/instance/LogPage.cpp
+++ b/launcher/ui/pages/instance/LogPage.cpp
@@ -1,16 +1,18 @@
#include "LogPage.h"
#include "ui_LogPage.h"
-#include "Launcher.h"
+#include "Application.h"
#include <QIcon>
#include <QScrollBar>
#include <QShortcut>
#include "launch/LaunchTask.h"
-#include <settings/Setting.h>
-#include "GuiUtil.h"
-#include <ColorCache.h>
+#include "settings/Setting.h"
+
+#include "ui/GuiUtil.h"
+#include "ui/ColorCache.h"
+
#include <BuildConfig.h>
class LogFormatProxyModel : public QIdentityProxyModel
@@ -125,9 +127,9 @@ LogPage::LogPage(InstancePtr instance, QWidget *parent)
// set up fonts in the log proxy
{
- QString fontFamily = LAUNCHER->settings()->get("ConsoleFont").toString();
+ QString fontFamily = APPLICATION->settings()->get("ConsoleFont").toString();
bool conversionOk = false;
- int fontSize = LAUNCHER->settings()->get("ConsoleFontSize").toInt(&conversionOk);
+ int fontSize = APPLICATION->settings()->get("ConsoleFontSize").toInt(&conversionOk);
if(!conversionOk)
{
fontSize = 11;
diff --git a/launcher/pages/instance/LogPage.h b/launcher/ui/pages/instance/LogPage.h
index 285296cd..cab25563 100644
--- a/launcher/pages/instance/LogPage.h
+++ b/launcher/ui/pages/instance/LogPage.h
@@ -19,8 +19,8 @@
#include "BaseInstance.h"
#include "launch/LaunchTask.h"
-#include "pages/BasePage.h"
-#include <Launcher.h>
+#include "ui/pages/BasePage.h"
+#include <Application.h>
namespace Ui
{
@@ -42,7 +42,7 @@ public:
}
virtual QIcon icon() const override
{
- return LAUNCHER->getThemedIcon("log");
+ return APPLICATION->getThemedIcon("log");
}
virtual QString id() const override
{
diff --git a/launcher/pages/instance/LogPage.ui b/launcher/ui/pages/instance/LogPage.ui
index 4843d7c3..ccfc1551 100644
--- a/launcher/pages/instance/LogPage.ui
+++ b/launcher/ui/pages/instance/LogPage.ui
@@ -163,7 +163,7 @@
<customwidget>
<class>LogView</class>
<extends>QPlainTextEdit</extends>
- <header>widgets/LogView.h</header>
+ <header>ui/widgets/LogView.h</header>
</customwidget>
</customwidgets>
<tabstops>
diff --git a/launcher/pages/instance/ModFolderPage.cpp b/launcher/ui/pages/instance/ModFolderPage.cpp
index caa81958..e63b1434 100644
--- a/launcher/pages/instance/ModFolderPage.cpp
+++ b/launcher/ui/pages/instance/ModFolderPage.cpp
@@ -21,17 +21,20 @@
#include <QKeyEvent>
#include <QAbstractItemModel>
#include <QMenu>
+#include <QSortFilterProxyModel>
+
+#include "Application.h"
+
+#include "ui/dialogs/CustomMessageBox.h"
+#include "ui/GuiUtil.h"
+
+#include "DesktopServices.h"
-#include "Launcher.h"
-#include "dialogs/CustomMessageBox.h"
-#include <GuiUtil.h>
#include "minecraft/mod/ModFolderModel.h"
#include "minecraft/mod/Mod.h"
#include "minecraft/VersionFilterData.h"
#include "minecraft/PackProfile.h"
-#include <DesktopServices.h>
-#include <QSortFilterProxyModel>
#include "Version.h"
namespace {
@@ -301,7 +304,7 @@ void ModFolderPage::on_actionAdd_triggered()
tr("Select %1",
"Select whatever type of files the page contains. Example: 'Loader Mods'")
.arg(m_displayName),
- m_fileSelectionFilter.arg(m_displayName), LAUNCHER->settings()->get("CentralModsDir").toString(),
+ m_fileSelectionFilter.arg(m_displayName), APPLICATION->settings()->get("CentralModsDir").toString(),
this->parentWidget());
if (!list.empty())
{
diff --git a/launcher/pages/instance/ModFolderPage.h b/launcher/ui/pages/instance/ModFolderPage.h
index 38fcc6a5..8ef7559b 100644
--- a/launcher/pages/instance/ModFolderPage.h
+++ b/launcher/ui/pages/instance/ModFolderPage.h
@@ -18,8 +18,9 @@
#include <QMainWindow>
#include "minecraft/MinecraftInstance.h"
-#include "pages/BasePage.h"
-#include <Launcher.h>
+#include "ui/pages/BasePage.h"
+
+#include <Application.h>
class ModFolderModel;
namespace Ui
@@ -54,7 +55,7 @@ public:
}
virtual QIcon icon() const override
{
- return LAUNCHER->getThemedIcon(m_iconName);
+ return APPLICATION->getThemedIcon(m_iconName);
}
virtual QString id() const override
{
diff --git a/launcher/pages/instance/ModFolderPage.ui b/launcher/ui/pages/instance/ModFolderPage.ui
index 954a0167..0fb51e84 100644
--- a/launcher/pages/instance/ModFolderPage.ui
+++ b/launcher/ui/pages/instance/ModFolderPage.ui
@@ -141,18 +141,18 @@
<customwidget>
<class>ModListView</class>
<extends>QTreeView</extends>
- <header>widgets/ModListView.h</header>
+ <header>ui/widgets/ModListView.h</header>
</customwidget>
<customwidget>
<class>MCModInfoFrame</class>
<extends>QFrame</extends>
- <header>widgets/MCModInfoFrame.h</header>
+ <header>ui/widgets/MCModInfoFrame.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>WideBar</class>
<extends>QToolBar</extends>
- <header>widgets/WideBar.h</header>
+ <header>ui/widgets/WideBar.h</header>
</customwidget>
</customwidgets>
<tabstops>
diff --git a/launcher/pages/instance/NotesPage.cpp b/launcher/ui/pages/instance/NotesPage.cpp
index fa966c91..fa966c91 100644
--- a/launcher/pages/instance/NotesPage.cpp
+++ b/launcher/ui/pages/instance/NotesPage.cpp
diff --git a/launcher/pages/instance/NotesPage.h b/launcher/ui/pages/instance/NotesPage.h
index 1bdb352d..539401ee 100644
--- a/launcher/pages/instance/NotesPage.h
+++ b/launcher/ui/pages/instance/NotesPage.h
@@ -18,8 +18,8 @@
#include <QWidget>
#include "BaseInstance.h"
-#include "pages/BasePage.h"
-#include <Launcher.h>
+#include "ui/pages/BasePage.h"
+#include <Application.h>
namespace Ui
{
@@ -39,9 +39,9 @@ public:
}
virtual QIcon icon() const override
{
- auto icon = LAUNCHER->getThemedIcon("notes");
+ auto icon = APPLICATION->getThemedIcon("notes");
if(icon.isNull())
- icon = LAUNCHER->getThemedIcon("news");
+ icon = APPLICATION->getThemedIcon("news");
return icon;
}
virtual QString id() const override
diff --git a/launcher/pages/instance/NotesPage.ui b/launcher/ui/pages/instance/NotesPage.ui
index 67cb261c..67cb261c 100644
--- a/launcher/pages/instance/NotesPage.ui
+++ b/launcher/ui/pages/instance/NotesPage.ui
diff --git a/launcher/pages/instance/OtherLogsPage.cpp b/launcher/ui/pages/instance/OtherLogsPage.cpp
index 31cd44ed..0131c5c1 100644
--- a/launcher/pages/instance/OtherLogsPage.cpp
+++ b/launcher/ui/pages/instance/OtherLogsPage.cpp
@@ -18,7 +18,8 @@
#include <QMessageBox>
-#include "GuiUtil.h"
+#include "ui/GuiUtil.h"
+
#include "RecursiveFileSystemWatcher.h"
#include <GZip.h>
#include <FileSystem.h>
@@ -129,9 +130,9 @@ void OtherLogsPage::on_btnReload_clicked()
{
auto setPlainText = [&](const QString & text)
{
- QString fontFamily = LAUNCHER->settings()->get("ConsoleFont").toString();
+ QString fontFamily = APPLICATION->settings()->get("ConsoleFont").toString();
bool conversionOk = false;
- int fontSize = LAUNCHER->settings()->get("ConsoleFontSize").toInt(&conversionOk);
+ int fontSize = APPLICATION->settings()->get("ConsoleFontSize").toInt(&conversionOk);
if(!conversionOk)
{
fontSize = 11;
diff --git a/launcher/pages/instance/OtherLogsPage.h b/launcher/ui/pages/instance/OtherLogsPage.h
index 25f127f6..b2b2a91b 100644
--- a/launcher/pages/instance/OtherLogsPage.h
+++ b/launcher/ui/pages/instance/OtherLogsPage.h
@@ -17,8 +17,8 @@
#include <QWidget>
-#include "pages/BasePage.h"
-#include <Launcher.h>
+#include "ui/pages/BasePage.h"
+#include <Application.h>
#include <pathmatcher/IPathMatcher.h>
namespace Ui
@@ -46,7 +46,7 @@ public:
}
QIcon icon() const override
{
- return LAUNCHER->getThemedIcon("log");
+ return APPLICATION->getThemedIcon("log");
}
QString helpPage() const override
{
diff --git a/launcher/pages/instance/OtherLogsPage.ui b/launcher/ui/pages/instance/OtherLogsPage.ui
index 56ff3b62..56ff3b62 100644
--- a/launcher/pages/instance/OtherLogsPage.ui
+++ b/launcher/ui/pages/instance/OtherLogsPage.ui
diff --git a/launcher/pages/instance/ResourcePackPage.h b/launcher/ui/pages/instance/ResourcePackPage.h
index 1486bf52..1486bf52 100644
--- a/launcher/pages/instance/ResourcePackPage.h
+++ b/launcher/ui/pages/instance/ResourcePackPage.h
diff --git a/launcher/pages/instance/ScreenshotsPage.cpp b/launcher/ui/pages/instance/ScreenshotsPage.cpp
index 172e2eb3..06c4379f 100644
--- a/launcher/pages/instance/ScreenshotsPage.cpp
+++ b/launcher/ui/pages/instance/ScreenshotsPage.cpp
@@ -15,10 +15,11 @@
#include <QKeyEvent>
#include <QMenu>
-#include <Launcher.h>
+#include <Application.h>
+
+#include "ui/dialogs/ProgressDialog.h"
+#include "ui/dialogs/CustomMessageBox.h"
-#include "dialogs/ProgressDialog.h"
-#include "dialogs/CustomMessageBox.h"
#include "net/NetJob.h"
#include "screenshots/ImgurUpload.h"
#include "screenshots/ImgurAlbumCreation.h"
@@ -104,7 +105,7 @@ public:
{
m_thumbnailingPool.setMaxThreadCount(4);
m_thumbnailCache = std::make_shared<SharedIconCache>();
- m_thumbnailCache->add("placeholder", LAUNCHER->getThemedIcon("screenshot-placeholder"));
+ m_thumbnailCache->add("placeholder", APPLICATION->getThemedIcon("screenshot-placeholder"));
connect(&watcher, SIGNAL(fileChanged(QString)), SLOT(fileChanged(QString)));
// FIXME: the watched file set is not updated when files are removed
}
@@ -302,8 +303,8 @@ void ScreenshotsPage::on_actionUpload_triggered()
if (selection.isEmpty())
return;
- QList<ScreenshotPtr> uploaded;
- auto job = NetJobPtr(new NetJob("Screenshot Upload"));
+ QList<ScreenShot::Ptr> uploaded;
+ auto job = NetJob::Ptr(new NetJob("Screenshot Upload"));
if(selection.size() < 2)
{
auto item = selection.at(0);
@@ -344,11 +345,11 @@ void ScreenshotsPage::on_actionUpload_triggered()
job->addNetAction(ImgurUpload::make(screenshot));
}
SequentialTask task;
- auto albumTask = NetJobPtr(new NetJob("Imgur Album Creation"));
+ auto albumTask = NetJob::Ptr(new NetJob("Imgur Album Creation"));
auto imgurAlbum = ImgurAlbumCreation::make(uploaded);
albumTask->addNetAction(imgurAlbum);
- task.addTask(job.unwrap());
- task.addTask(albumTask.unwrap());
+ task.addTask(job);
+ task.addTask(albumTask);
m_uploadActive = true;
ProgressDialog prog(this);
if (prog.execWithTask(&task) != QDialog::Accepted)
diff --git a/launcher/pages/instance/ScreenshotsPage.h b/launcher/ui/pages/instance/ScreenshotsPage.h
index 01f26642..d2f44837 100644
--- a/launcher/pages/instance/ScreenshotsPage.h
+++ b/launcher/ui/pages/instance/ScreenshotsPage.h
@@ -17,8 +17,8 @@
#include <QMainWindow>
-#include "pages/BasePage.h"
-#include <Launcher.h>
+#include "ui/pages/BasePage.h"
+#include <Application.h>
class QFileSystemModel;
class QIdentityProxyModel;
@@ -53,7 +53,7 @@ public:
}
virtual QIcon icon() const override
{
- return LAUNCHER->getThemedIcon("screenshots");
+ return APPLICATION->getThemedIcon("screenshots");
}
virtual QString id() const override
{
diff --git a/launcher/pages/instance/ScreenshotsPage.ui b/launcher/ui/pages/instance/ScreenshotsPage.ui
index f11f4cd4..ec461087 100644
--- a/launcher/pages/instance/ScreenshotsPage.ui
+++ b/launcher/ui/pages/instance/ScreenshotsPage.ui
@@ -79,7 +79,7 @@
<customwidget>
<class>WideBar</class>
<extends>QToolBar</extends>
- <header>widgets/WideBar.h</header>
+ <header>ui/widgets/WideBar.h</header>
</customwidget>
</customwidgets>
<resources/>
diff --git a/launcher/pages/instance/ServersPage.cpp b/launcher/ui/pages/instance/ServersPage.cpp
index 6c55fdac..8116d2bf 100644
--- a/launcher/pages/instance/ServersPage.cpp
+++ b/launcher/ui/pages/instance/ServersPage.cpp
@@ -324,7 +324,7 @@ public:
if(px.loadFromData(bytes))
return QIcon(px);
}
- return LAUNCHER->getThemedIcon("unknown_server");
+ return APPLICATION->getThemedIcon("unknown_server");
}
case Qt::DisplayRole:
return m_servers[row].m_name;
@@ -762,7 +762,7 @@ void ServersPage::on_actionMove_Down_triggered()
void ServersPage::on_actionJoin_triggered()
{
const auto &address = m_model->at(currentServer)->m_address;
- LAUNCHER->launch(m_inst, true, nullptr, std::make_shared<MinecraftServerTarget>(MinecraftServerTarget::parse(address)));
+ APPLICATION->launch(m_inst, true, nullptr, std::make_shared<MinecraftServerTarget>(MinecraftServerTarget::parse(address)));
}
#include "ServersPage.moc"
diff --git a/launcher/pages/instance/ServersPage.h b/launcher/ui/pages/instance/ServersPage.h
index 63f3b9e3..d91da2ae 100644
--- a/launcher/pages/instance/ServersPage.h
+++ b/launcher/ui/pages/instance/ServersPage.h
@@ -18,8 +18,8 @@
#include <QMainWindow>
#include <QString>
-#include "pages/BasePage.h"
-#include <Launcher.h>
+#include "ui/pages/BasePage.h"
+#include <Application.h>
namespace Ui
{
@@ -47,7 +47,7 @@ public:
}
virtual QIcon icon() const override
{
- return LAUNCHER->getThemedIcon("unknown_server");
+ return APPLICATION->getThemedIcon("unknown_server");
}
virtual QString id() const override
{
diff --git a/launcher/pages/instance/ServersPage.ui b/launcher/ui/pages/instance/ServersPage.ui
index d89b7cba..e8f79cf2 100644
--- a/launcher/pages/instance/ServersPage.ui
+++ b/launcher/ui/pages/instance/ServersPage.ui
@@ -180,7 +180,7 @@
<customwidget>
<class>WideBar</class>
<extends>QToolBar</extends>
- <header>widgets/WideBar.h</header>
+ <header>ui/widgets/WideBar.h</header>
</customwidget>
</customwidgets>
<tabstops>
diff --git a/launcher/pages/instance/ShaderPackPage.h b/launcher/ui/pages/instance/ShaderPackPage.h
index 36724992..36724992 100644
--- a/launcher/pages/instance/ShaderPackPage.h
+++ b/launcher/ui/pages/instance/ShaderPackPage.h
diff --git a/launcher/pages/instance/TexturePackPage.h b/launcher/ui/pages/instance/TexturePackPage.h
index 3f04997d..3f04997d 100644
--- a/launcher/pages/instance/TexturePackPage.h
+++ b/launcher/ui/pages/instance/TexturePackPage.h
diff --git a/launcher/pages/instance/VersionPage.cpp b/launcher/ui/pages/instance/VersionPage.cpp
index 103f0c7a..6e57909b 100644
--- a/launcher/pages/instance/VersionPage.cpp
+++ b/launcher/ui/pages/instance/VersionPage.cpp
@@ -13,30 +13,29 @@
* limitations under the License.
*/
-#include "Launcher.h"
+#include "Application.h"
#include <QMessageBox>
#include <QLabel>
#include <QEvent>
#include <QKeyEvent>
#include <QMenu>
-
-#include "VersionPage.h"
-#include "ui_VersionPage.h"
-
-#include "dialogs/CustomMessageBox.h"
-#include "dialogs/VersionSelectDialog.h"
-#include "dialogs/NewComponentDialog.h"
-
-#include "dialogs/ProgressDialog.h"
-#include <GuiUtil.h>
-
#include <QAbstractItemModel>
#include <QMessageBox>
#include <QListView>
#include <QString>
#include <QUrl>
+#include "VersionPage.h"
+#include "ui_VersionPage.h"
+
+#include "ui/dialogs/CustomMessageBox.h"
+#include "ui/dialogs/VersionSelectDialog.h"
+#include "ui/dialogs/NewComponentDialog.h"
+#include "ui/dialogs/ProgressDialog.h"
+
+#include "ui/GuiUtil.h"
+
#include "minecraft/PackProfile.h"
#include "minecraft/auth/AccountList.h"
#include "minecraft/mod/Mod.h"
@@ -45,8 +44,8 @@
#include "Version.h"
#include "DesktopServices.h"
-#include <meta/Index.h>
-#include <meta/VersionList.h>
+#include "meta/Index.h"
+#include "meta/VersionList.h"
class IconProxy : public QIdentityProxyModel
{
@@ -70,14 +69,14 @@ public:
auto string = var.toString();
if(string == "warning")
{
- return LAUNCHER->getThemedIcon("status-yellow");
+ return APPLICATION->getThemedIcon("status-yellow");
}
else if(string == "error")
{
- return LAUNCHER->getThemedIcon("status-bad");
+ return APPLICATION->getThemedIcon("status-bad");
}
}
- return LAUNCHER->getThemedIcon("status-good");
+ return APPLICATION->getThemedIcon("status-good");
}
return var;
}
@@ -93,7 +92,7 @@ private:
QIcon VersionPage::icon() const
{
- return LAUNCHER->icons()->getIcon(m_inst->iconKey());
+ return APPLICATION->icons()->getIcon(m_inst->iconKey());
}
bool VersionPage::shouldDisplay() const
{
@@ -216,9 +215,6 @@ void VersionPage::updateVersionControls()
bool supportsFabric = minecraftVersion >= Version("1.14");
ui->actionInstall_Fabric->setEnabled(controlsEnabled && supportsFabric);
- bool supportsForge = minecraftVersion <= Version("1.16.5");
- ui->actionInstall_Forge->setEnabled(controlsEnabled && supportsForge);
-
bool supportsLiteLoader = minecraftVersion <= Version("1.12.2");
ui->actionInstall_LiteLoader->setEnabled(controlsEnabled && supportsLiteLoader);
@@ -297,7 +293,7 @@ void VersionPage::on_actionInstall_mods_triggered()
void VersionPage::on_actionAdd_to_Minecraft_jar_triggered()
{
- auto list = GuiUtil::BrowseForFiles("jarmod", tr("Select jar mods"), tr("Minecraft.jar mods (*.zip *.jar)"), LAUNCHER->settings()->get("CentralModsDir").toString(), this->parentWidget());
+ auto list = GuiUtil::BrowseForFiles("jarmod", tr("Select jar mods"), tr("Minecraft.jar mods (*.zip *.jar)"), APPLICATION->settings()->get("CentralModsDir").toString(), this->parentWidget());
if(!list.empty())
{
m_profile->installJarMods(list);
@@ -307,7 +303,7 @@ void VersionPage::on_actionAdd_to_Minecraft_jar_triggered()
void VersionPage::on_actionReplace_Minecraft_jar_triggered()
{
- auto jarPath = GuiUtil::BrowseForFile("jar", tr("Select jar"), tr("Minecraft.jar replacement (*.jar)"), LAUNCHER->settings()->get("CentralModsDir").toString(), this->parentWidget());
+ auto jarPath = GuiUtil::BrowseForFile("jar", tr("Select jar"), tr("Minecraft.jar replacement (*.jar)"), APPLICATION->settings()->get("CentralModsDir").toString(), this->parentWidget());
if(!jarPath.isEmpty())
{
m_profile->installCustomJar(jarPath);
@@ -395,7 +391,7 @@ void VersionPage::on_actionChange_version_triggered()
void VersionPage::on_actionDownload_All_triggered()
{
- if (!LAUNCHER->accounts()->anyAccountIsValid())
+ if (!APPLICATION->accounts()->anyAccountIsValid())
{
CustomMessageBox::selectable(
this, tr("Error"),
@@ -420,7 +416,7 @@ void VersionPage::on_actionDownload_All_triggered()
void VersionPage::on_actionInstall_Forge_triggered()
{
- auto vlist = ENV.metadataIndex()->get("net.minecraftforge");
+ auto vlist = APPLICATION->metadataIndex()->get("net.minecraftforge");
if(!vlist)
{
return;
@@ -449,7 +445,7 @@ void VersionPage::on_actionInstall_Forge_triggered()
void VersionPage::on_actionInstall_Fabric_triggered()
{
- auto vlist = ENV.metadataIndex()->get("net.fabricmc.fabric-loader");
+ auto vlist = APPLICATION->metadataIndex()->get("net.fabricmc.fabric-loader");
if(!vlist)
{
return;
@@ -494,7 +490,7 @@ void VersionPage::on_actionAdd_Empty_triggered()
void VersionPage::on_actionInstall_LiteLoader_triggered()
{
- auto vlist = ENV.metadataIndex()->get("com.mumfrey.liteloader");
+ auto vlist = APPLICATION->metadataIndex()->get("com.mumfrey.liteloader");
if(!vlist)
{
return;
@@ -614,7 +610,7 @@ void VersionPage::on_actionEdit_triggered()
qWarning() << "file" << filename << "can't be opened for editing, doesn't exist!";
return;
}
- LAUNCHER->openJsonEditor(filename);
+ APPLICATION->openJsonEditor(filename);
}
void VersionPage::on_actionRevert_triggered()
diff --git a/launcher/pages/instance/VersionPage.h b/launcher/ui/pages/instance/VersionPage.h
index b5b4a6f5..b5ce4064 100644
--- a/launcher/pages/instance/VersionPage.h
+++ b/launcher/ui/pages/instance/VersionPage.h
@@ -19,7 +19,7 @@
#include "minecraft/MinecraftInstance.h"
#include "minecraft/PackProfile.h"
-#include "pages/BasePage.h"
+#include "ui/pages/BasePage.h"
namespace Ui
{
diff --git a/launcher/pages/instance/VersionPage.ui b/launcher/ui/pages/instance/VersionPage.ui
index 84d06e2e..a4990ff3 100644
--- a/launcher/pages/instance/VersionPage.ui
+++ b/launcher/ui/pages/instance/VersionPage.ui
@@ -266,18 +266,18 @@
<customwidget>
<class>ModListView</class>
<extends>QTreeView</extends>
- <header>widgets/ModListView.h</header>
+ <header>ui/widgets/ModListView.h</header>
</customwidget>
<customwidget>
<class>MCModInfoFrame</class>
<extends>QFrame</extends>
- <header>widgets/MCModInfoFrame.h</header>
+ <header>ui/widgets/MCModInfoFrame.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>WideBar</class>
<extends>QToolBar</extends>
- <header>widgets/WideBar.h</header>
+ <header>ui/widgets/WideBar.h</header>
</customwidget>
</customwidgets>
<resources/>
diff --git a/launcher/pages/instance/WorldListPage.cpp b/launcher/ui/pages/instance/WorldListPage.cpp
index d25f23a8..d2bf63bd 100644
--- a/launcher/pages/instance/WorldListPage.cpp
+++ b/launcher/ui/pages/instance/WorldListPage.cpp
@@ -16,7 +16,7 @@
#include "WorldListPage.h"
#include "ui_WorldListPage.h"
#include "minecraft/WorldList.h"
-#include <DesktopServices.h>
+
#include <QEvent>
#include <QMenu>
#include <QKeyEvent>
@@ -24,12 +24,16 @@
#include <QMessageBox>
#include <QTreeView>
#include <QInputDialog>
-#include <tools/MCEditTool.h>
-
-#include "Launcher.h"
-#include <GuiUtil.h>
#include <QProcess>
-#include <FileSystem.h>
+
+#include "tools/MCEditTool.h"
+#include "FileSystem.h"
+
+#include "ui/GuiUtil.h"
+#include "DesktopServices.h"
+
+#include "Application.h"
+
class WorldListProxyModel : public QSortFilterProxyModel
{
@@ -48,7 +52,7 @@ public:
auto iconFile = worlds->data(sourceIndex, WorldList::IconFileRole).toString();
if(iconFile.isNull()) {
// NOTE: Minecraft uses the same placeholder for servers AND worlds
- return LAUNCHER->getThemedIcon("unknown_server");
+ return APPLICATION->getThemedIcon("unknown_server");
}
return QIcon(iconFile);
}
@@ -218,7 +222,7 @@ void WorldListPage::on_actionCopy_Seed_triggered()
return;
}
int64_t seed = m_worlds->data(index, WorldList::SeedRole).toLongLong();
- LAUNCHER->clipboard()->setText(QString::number(seed));
+ APPLICATION->clipboard()->setText(QString::number(seed));
}
void WorldListPage::on_actionMCEdit_triggered()
@@ -226,7 +230,7 @@ void WorldListPage::on_actionMCEdit_triggered()
if(m_mceditStarting)
return;
- auto mcedit = LAUNCHER->mcedit();
+ auto mcedit = APPLICATION->mcedit();
const QString mceditPath = mcedit->path();
diff --git a/launcher/pages/instance/WorldListPage.h b/launcher/ui/pages/instance/WorldListPage.h
index b90d7ad1..e07d5794 100644
--- a/launcher/pages/instance/WorldListPage.h
+++ b/launcher/ui/pages/instance/WorldListPage.h
@@ -18,8 +18,8 @@
#include <QMainWindow>
#include "minecraft/MinecraftInstance.h"
-#include "pages/BasePage.h"
-#include <Launcher.h>
+#include "ui/pages/BasePage.h"
+#include <Application.h>
#include <LoggedProcess.h>
class WorldList;
@@ -46,7 +46,7 @@ public:
}
virtual QIcon icon() const override
{
- return LAUNCHER->getThemedIcon("worlds");
+ return APPLICATION->getThemedIcon("worlds");
}
virtual QString id() const override
{
diff --git a/launcher/pages/instance/WorldListPage.ui b/launcher/ui/pages/instance/WorldListPage.ui
index ed078d94..7c68bfae 100644
--- a/launcher/pages/instance/WorldListPage.ui
+++ b/launcher/ui/pages/instance/WorldListPage.ui
@@ -153,7 +153,7 @@
<customwidget>
<class>WideBar</class>
<extends>QToolBar</extends>
- <header>widgets/WideBar.h</header>
+ <header>ui/widgets/WideBar.h</header>
</customwidget>
</customwidgets>
<resources/>
diff --git a/launcher/pages/modplatform/ImportPage.cpp b/launcher/ui/pages/modplatform/ImportPage.cpp
index dd02e839..c9e24ead 100644
--- a/launcher/pages/modplatform/ImportPage.cpp
+++ b/launcher/ui/pages/modplatform/ImportPage.cpp
@@ -1,11 +1,13 @@
#include "ImportPage.h"
#include "ui_ImportPage.h"
-#include "Launcher.h"
-#include "dialogs/NewInstanceDialog.h"
#include <QFileDialog>
#include <QValidator>
-#include <InstanceImportTask.h>
+
+#include "ui/dialogs/NewInstanceDialog.h"
+
+#include "InstanceImportTask.h"
+
class UrlValidator : public QValidator
{
diff --git a/launcher/pages/modplatform/ImportPage.h b/launcher/ui/pages/modplatform/ImportPage.h
index cc8a0d1f..aba4def0 100644
--- a/launcher/pages/modplatform/ImportPage.h
+++ b/launcher/ui/pages/modplatform/ImportPage.h
@@ -17,8 +17,8 @@
#include <QWidget>
-#include "pages/BasePage.h"
-#include <Launcher.h>
+#include "ui/pages/BasePage.h"
+#include <Application.h>
#include "tasks/Task.h"
namespace Ui
@@ -41,7 +41,7 @@ public:
}
virtual QIcon icon() const override
{
- return LAUNCHER->getThemedIcon("viewfolder");
+ return APPLICATION->getThemedIcon("viewfolder");
}
virtual QString id() const override
{
diff --git a/launcher/pages/modplatform/ImportPage.ui b/launcher/ui/pages/modplatform/ImportPage.ui
index eb63cbe9..eb63cbe9 100644
--- a/launcher/pages/modplatform/ImportPage.ui
+++ b/launcher/ui/pages/modplatform/ImportPage.ui
diff --git a/launcher/pages/modplatform/VanillaPage.cpp b/launcher/ui/pages/modplatform/VanillaPage.cpp
index 1cf5bbc7..5c58c1f1 100644
--- a/launcher/pages/modplatform/VanillaPage.cpp
+++ b/launcher/ui/pages/modplatform/VanillaPage.cpp
@@ -1,16 +1,15 @@
#include "VanillaPage.h"
#include "ui_VanillaPage.h"
-#include "Launcher.h"
-
-#include <meta/Index.h>
-#include <meta/VersionList.h>
-#include <dialogs/NewInstanceDialog.h>
-#include <Filter.h>
-#include <Env.h>
-#include <InstanceCreationTask.h>
#include <QTabBar>
+#include "Application.h"
+#include "meta/Index.h"
+#include "meta/VersionList.h"
+#include "ui/dialogs/NewInstanceDialog.h"
+#include "Filter.h"
+#include "InstanceCreationTask.h"
+
VanillaPage::VanillaPage(NewInstanceDialog *dialog, QWidget *parent)
: QWidget(parent), dialog(dialog), ui(new Ui::VanillaPage)
{
@@ -31,7 +30,7 @@ void VanillaPage::openedImpl()
{
if(!initialized)
{
- auto vlist = ENV.metadataIndex()->get("net.minecraft");
+ auto vlist = APPLICATION->metadataIndex()->get("net.minecraft");
ui->versionList->initialize(vlist.get());
initialized = true;
}
diff --git a/launcher/pages/modplatform/VanillaPage.h b/launcher/ui/pages/modplatform/VanillaPage.h
index e090d8bb..fd4c2daa 100644
--- a/launcher/pages/modplatform/VanillaPage.h
+++ b/launcher/ui/pages/modplatform/VanillaPage.h
@@ -17,8 +17,8 @@
#include <QWidget>
-#include "pages/BasePage.h"
-#include <Launcher.h>
+#include "ui/pages/BasePage.h"
+#include <Application.h>
#include "tasks/Task.h"
namespace Ui
@@ -41,7 +41,7 @@ public:
}
virtual QIcon icon() const override
{
- return LAUNCHER->getThemedIcon("minecraft");
+ return APPLICATION->getThemedIcon("minecraft");
}
virtual QString id() const override
{
diff --git a/launcher/pages/modplatform/VanillaPage.ui b/launcher/ui/pages/modplatform/VanillaPage.ui
index 47effc86..870ff161 100644
--- a/launcher/pages/modplatform/VanillaPage.ui
+++ b/launcher/ui/pages/modplatform/VanillaPage.ui
@@ -150,7 +150,7 @@
<customwidget>
<class>VersionSelectWidget</class>
<extends>QWidget</extends>
- <header>widgets/VersionSelectWidget.h</header>
+ <header>ui/widgets/VersionSelectWidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
diff --git a/launcher/pages/modplatform/atlauncher/AtlFilterModel.cpp b/launcher/ui/pages/modplatform/atlauncher/AtlFilterModel.cpp
index b5d8f22b..b5d8f22b 100644
--- a/launcher/pages/modplatform/atlauncher/AtlFilterModel.cpp
+++ b/launcher/ui/pages/modplatform/atlauncher/AtlFilterModel.cpp
diff --git a/launcher/pages/modplatform/atlauncher/AtlFilterModel.h b/launcher/ui/pages/modplatform/atlauncher/AtlFilterModel.h
index bd72ad91..bd72ad91 100644
--- a/launcher/pages/modplatform/atlauncher/AtlFilterModel.h
+++ b/launcher/ui/pages/modplatform/atlauncher/AtlFilterModel.h
diff --git a/launcher/pages/modplatform/atlauncher/AtlListModel.cpp b/launcher/ui/pages/modplatform/atlauncher/AtlListModel.cpp
index 99d12601..e8c6deee 100644
--- a/launcher/pages/modplatform/atlauncher/AtlListModel.cpp
+++ b/launcher/ui/pages/modplatform/atlauncher/AtlListModel.cpp
@@ -1,8 +1,7 @@
#include "AtlListModel.h"
#include <BuildConfig.h>
-#include <Launcher.h>
-#include <Env.h>
+#include <Application.h>
#include <Json.h>
namespace Atl {
@@ -48,7 +47,7 @@ QVariant ListModel::data(const QModelIndex &index, int role) const
{
return (m_logoMap.value(pack.safeName));
}
- auto icon = LAUNCHER->getThemedIcon("atlauncher-placeholder");
+ auto icon = APPLICATION->getThemedIcon("atlauncher-placeholder");
auto url = QString(BuildConfig.ATL_DOWNLOAD_SERVER_URL + "launcher/images/%1.png").arg(pack.safeName.toLower());
((ListModel *)this)->requestLogo(pack.safeName, url);
@@ -75,7 +74,7 @@ void ListModel::request()
auto url = QString(BuildConfig.ATL_DOWNLOAD_SERVER_URL + "launcher/json/packsnew.json");
netJob->addNetAction(Net::Download::makeByteArray(QUrl(url), &response));
jobPtr = netJob;
- jobPtr->start();
+ jobPtr->start(APPLICATION->network());
QObject::connect(netJob, &NetJob::succeeded, this, &ListModel::requestFinished);
QObject::connect(netJob, &NetJob::failed, this, &ListModel::requestFailed);
@@ -134,7 +133,7 @@ void ListModel::getLogo(const QString &logo, const QString &logoUrl, LogoCallbac
{
if(m_logoMap.contains(logo))
{
- callback(ENV.metacache()->resolveEntry("ATLauncherPacks", QString("logos/%1").arg(logo.section(".", 0, 0)))->getFullPath());
+ callback(APPLICATION->metacache()->resolveEntry("ATLauncherPacks", QString("logos/%1").arg(logo.section(".", 0, 0)))->getFullPath());
}
else
{
@@ -167,7 +166,7 @@ void ListModel::requestLogo(QString file, QString url)
return;
}
- MetaEntryPtr entry = ENV.metacache()->resolveEntry("ATLauncherPacks", QString("logos/%1").arg(file.section(".", 0, 0)));
+ MetaEntryPtr entry = APPLICATION->metacache()->resolveEntry("ATLauncherPacks", QString("logos/%1").arg(file.section(".", 0, 0)));
NetJob *job = new NetJob(QString("ATLauncher Icon Download %1").arg(file));
job->addNetAction(Net::Download::makeCached(QUrl(url), entry));
@@ -186,7 +185,7 @@ void ListModel::requestLogo(QString file, QString url)
emit logoFailed(file);
});
- job->start();
+ job->start(APPLICATION->network());
m_loadingLogos.append(file);
}
diff --git a/launcher/pages/modplatform/atlauncher/AtlListModel.h b/launcher/ui/pages/modplatform/atlauncher/AtlListModel.h
index 2d30a64e..79aa8180 100644
--- a/launcher/pages/modplatform/atlauncher/AtlListModel.h
+++ b/launcher/ui/pages/modplatform/atlauncher/AtlListModel.h
@@ -45,7 +45,7 @@ private:
LogoMap m_logoMap;
QMap<QString, LogoCallback> waitingCallbacks;
- NetJobPtr jobPtr;
+ NetJob::Ptr jobPtr;
QByteArray response;
};
diff --git a/launcher/pages/modplatform/atlauncher/AtlOptionalModDialog.cpp b/launcher/ui/pages/modplatform/atlauncher/AtlOptionalModDialog.cpp
index 14bbd18b..14bbd18b 100644
--- a/launcher/pages/modplatform/atlauncher/AtlOptionalModDialog.cpp
+++ b/launcher/ui/pages/modplatform/atlauncher/AtlOptionalModDialog.cpp
diff --git a/launcher/pages/modplatform/atlauncher/AtlOptionalModDialog.h b/launcher/ui/pages/modplatform/atlauncher/AtlOptionalModDialog.h
index a1df43f6..a1df43f6 100644
--- a/launcher/pages/modplatform/atlauncher/AtlOptionalModDialog.h
+++ b/launcher/ui/pages/modplatform/atlauncher/AtlOptionalModDialog.h
diff --git a/launcher/pages/modplatform/atlauncher/AtlOptionalModDialog.ui b/launcher/ui/pages/modplatform/atlauncher/AtlOptionalModDialog.ui
index 5d3193a4..4c5c2ec5 100644
--- a/launcher/pages/modplatform/atlauncher/AtlOptionalModDialog.ui
+++ b/launcher/ui/pages/modplatform/atlauncher/AtlOptionalModDialog.ui
@@ -57,7 +57,7 @@
<customwidget>
<class>ModListView</class>
<extends>QTreeView</extends>
- <header>widgets/ModListView.h</header>
+ <header>ui/widgets/ModListView.h</header>
</customwidget>
</customwidgets>
<resources/>
diff --git a/launcher/pages/modplatform/atlauncher/AtlPage.cpp b/launcher/ui/pages/modplatform/atlauncher/AtlPage.cpp
index cdf5cc86..5f6a1396 100644
--- a/launcher/pages/modplatform/atlauncher/AtlPage.cpp
+++ b/launcher/ui/pages/modplatform/atlauncher/AtlPage.cpp
@@ -1,11 +1,13 @@
#include "AtlPage.h"
#include "ui_AtlPage.h"
-#include "dialogs/NewInstanceDialog.h"
+#include "modplatform/atlauncher/ATLPackInstallTask.h"
+
#include "AtlOptionalModDialog.h"
-#include <modplatform/atlauncher/ATLPackInstallTask.h>
+#include "ui/dialogs/NewInstanceDialog.h"
+#include "ui/dialogs/VersionSelectDialog.h"
+
#include <BuildConfig.h>
-#include <dialogs/VersionSelectDialog.h>
AtlPage::AtlPage(NewInstanceDialog* dialog, QWidget *parent)
: QWidget(parent), ui(new Ui::AtlPage), dialog(dialog)
@@ -133,7 +135,7 @@ QVector<QString> AtlPage::chooseOptionalMods(QVector<ATLauncher::VersionMod> mod
}
QString AtlPage::chooseVersion(Meta::VersionListPtr vlist, QString minecraftVersion) {
- VersionSelectDialog vselect(vlist.get(), "Choose Version", LAUNCHER->activeWindow(), false);
+ VersionSelectDialog vselect(vlist.get(), "Choose Version", APPLICATION->activeWindow(), false);
if (minecraftVersion != Q_NULLPTR) {
vselect.setExactFilter(BaseVersionList::ParentVersionRole, minecraftVersion);
vselect.setEmptyString(tr("No versions are currently available for Minecraft %1").arg(minecraftVersion));
diff --git a/launcher/pages/modplatform/atlauncher/AtlPage.h b/launcher/ui/pages/modplatform/atlauncher/AtlPage.h
index 84c40656..b95b3d9e 100644
--- a/launcher/pages/modplatform/atlauncher/AtlPage.h
+++ b/launcher/ui/pages/modplatform/atlauncher/AtlPage.h
@@ -21,8 +21,8 @@
#include <QWidget>
#include <modplatform/atlauncher/ATLPackInstallTask.h>
-#include "Launcher.h"
-#include "pages/BasePage.h"
+#include "Application.h"
+#include "ui/pages/BasePage.h"
#include "tasks/Task.h"
namespace Ui
@@ -45,7 +45,7 @@ public:
}
virtual QIcon icon() const override
{
- return LAUNCHER->getThemedIcon("atlauncher");
+ return APPLICATION->getThemedIcon("atlauncher");
}
virtual QString id() const override
{
diff --git a/launcher/pages/modplatform/atlauncher/AtlPage.ui b/launcher/ui/pages/modplatform/atlauncher/AtlPage.ui
index 9085766a..9085766a 100644
--- a/launcher/pages/modplatform/atlauncher/AtlPage.ui
+++ b/launcher/ui/pages/modplatform/atlauncher/AtlPage.ui
diff --git a/launcher/pages/modplatform/flame/FlameModel.cpp b/launcher/ui/pages/modplatform/flame/FlameModel.cpp
index 6dd29d21..a05ab641 100644
--- a/launcher/pages/modplatform/flame/FlameModel.cpp
+++ b/launcher/ui/pages/modplatform/flame/FlameModel.cpp
@@ -1,5 +1,5 @@
#include "FlameModel.h"
-#include "Launcher.h"
+#include "Application.h"
#include <Json.h>
#include <MMCStrings.h>
@@ -9,7 +9,6 @@
#include <QLabel>
#include <RWStorage.h>
-#include <Env.h>
namespace Flame {
@@ -62,7 +61,7 @@ QVariant ListModel::data(const QModelIndex &index, int role) const
{
return (m_logoMap.value(pack.logoName));
}
- QIcon icon = LAUNCHER->getThemedIcon("screenshot-placeholder");
+ QIcon icon = APPLICATION->getThemedIcon("screenshot-placeholder");
((ListModel *)this)->requestLogo(pack.logoName, pack.logoUrl);
return icon;
}
@@ -100,7 +99,7 @@ void ListModel::requestLogo(QString logo, QString url)
return;
}
- MetaEntryPtr entry = ENV.metacache()->resolveEntry("FlamePacks", QString("logos/%1").arg(logo.section(".", 0, 0)));
+ MetaEntryPtr entry = APPLICATION->metacache()->resolveEntry("FlamePacks", QString("logos/%1").arg(logo.section(".", 0, 0)));
NetJob *job = new NetJob(QString("Flame Icon Download %1").arg(logo));
job->addNetAction(Net::Download::makeCached(QUrl(url), entry));
@@ -119,7 +118,7 @@ void ListModel::requestLogo(QString logo, QString url)
emit logoFailed(logo);
});
- job->start();
+ job->start(APPLICATION->network());
m_loadingLogos.append(logo);
}
@@ -128,7 +127,7 @@ void ListModel::getLogo(const QString &logo, const QString &logoUrl, LogoCallbac
{
if(m_logoMap.contains(logo))
{
- callback(ENV.metacache()->resolveEntry("FlamePacks", QString("logos/%1").arg(logo.section(".", 0, 0)))->getFullPath());
+ callback(APPLICATION->metacache()->resolveEntry("FlamePacks", QString("logos/%1").arg(logo.section(".", 0, 0)))->getFullPath());
}
else
{
@@ -172,7 +171,7 @@ void ListModel::performPaginatedSearch()
).arg(nextSearchOffset).arg(currentSearchTerm).arg(currentSort);
netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), &response));
jobPtr = netJob;
- jobPtr->start();
+ jobPtr->start(APPLICATION->network());
QObject::connect(netJob, &NetJob::succeeded, this, &ListModel::searchRequestFinished);
QObject::connect(netJob, &NetJob::failed, this, &ListModel::searchRequestFailed);
}
diff --git a/launcher/pages/modplatform/flame/FlameModel.h b/launcher/ui/pages/modplatform/flame/FlameModel.h
index 24383db0..536f6add 100644
--- a/launcher/pages/modplatform/flame/FlameModel.h
+++ b/launcher/ui/pages/modplatform/flame/FlameModel.h
@@ -69,7 +69,7 @@ private:
ResetRequested,
Finished
} searchState = None;
- NetJobPtr jobPtr;
+ NetJob::Ptr jobPtr;
QByteArray response;
};
diff --git a/launcher/pages/modplatform/flame/FlamePage.cpp b/launcher/ui/pages/modplatform/flame/FlamePage.cpp
index 8f798df6..cb1185f7 100644
--- a/launcher/pages/modplatform/flame/FlamePage.cpp
+++ b/launcher/ui/pages/modplatform/flame/FlamePage.cpp
@@ -1,13 +1,14 @@
#include "FlamePage.h"
#include "ui_FlamePage.h"
-#include "Launcher.h"
-#include <Json.h>
-#include "dialogs/NewInstanceDialog.h"
-#include <InstanceImportTask.h>
-#include "FlameModel.h"
#include <QKeyEvent>
+#include "Application.h"
+#include "Json.h"
+#include "ui/dialogs/NewInstanceDialog.h"
+#include "InstanceImportTask.h"
+#include "FlameModel.h"
+
FlamePage::FlamePage(NewInstanceDialog* dialog, QWidget *parent)
: QWidget(parent), ui(new Ui::FlamePage), dialog(dialog)
{
@@ -112,7 +113,7 @@ void FlamePage::onSelectionChanged(QModelIndex first, QModelIndex second)
std::shared_ptr<QByteArray> response = std::make_shared<QByteArray>();
int addonId = current.addonId;
netJob->addNetAction(Net::Download::makeByteArray(QString("https://addons-ecs.forgesvc.net/api/v2/addon/%1/files").arg(addonId), response.get()));
-
+
QObject::connect(netJob, &NetJob::succeeded, this, [this, response]
{
QJsonParseError parse_error;
@@ -139,7 +140,7 @@ void FlamePage::onSelectionChanged(QModelIndex first, QModelIndex second)
suggestCurrent();
});
- netJob->start();
+ netJob->start(APPLICATION->network());
}
else
{
diff --git a/launcher/pages/modplatform/flame/FlamePage.h b/launcher/ui/pages/modplatform/flame/FlamePage.h
index c3d2630a..5cfe21dc 100644
--- a/launcher/pages/modplatform/flame/FlamePage.h
+++ b/launcher/ui/pages/modplatform/flame/FlamePage.h
@@ -17,8 +17,8 @@
#include <QWidget>
-#include "pages/BasePage.h"
-#include <Launcher.h>
+#include "ui/pages/BasePage.h"
+#include <Application.h>
#include "tasks/Task.h"
#include <modplatform/flame/FlamePackIndex.h>
@@ -46,7 +46,7 @@ public:
}
virtual QIcon icon() const override
{
- return LAUNCHER->getThemedIcon("flame");
+ return APPLICATION->getThemedIcon("flame");
}
virtual QString id() const override
{
diff --git a/launcher/pages/modplatform/flame/FlamePage.ui b/launcher/ui/pages/modplatform/flame/FlamePage.ui
index 9723815a..9723815a 100644
--- a/launcher/pages/modplatform/flame/FlamePage.ui
+++ b/launcher/ui/pages/modplatform/flame/FlamePage.ui
diff --git a/launcher/pages/modplatform/ftb/FtbFilterModel.cpp b/launcher/ui/pages/modplatform/ftb/FtbFilterModel.cpp
index 793b8769..793b8769 100644
--- a/launcher/pages/modplatform/ftb/FtbFilterModel.cpp
+++ b/launcher/ui/pages/modplatform/ftb/FtbFilterModel.cpp
diff --git a/launcher/pages/modplatform/ftb/FtbFilterModel.h b/launcher/ui/pages/modplatform/ftb/FtbFilterModel.h
index 2e712c7d..2e712c7d 100644
--- a/launcher/pages/modplatform/ftb/FtbFilterModel.h
+++ b/launcher/ui/pages/modplatform/ftb/FtbFilterModel.h
diff --git a/launcher/pages/modplatform/ftb/FtbListModel.cpp b/launcher/ui/pages/modplatform/ftb/FtbListModel.cpp
index c4c2c83e..59cd0b85 100644
--- a/launcher/pages/modplatform/ftb/FtbListModel.cpp
+++ b/launcher/ui/pages/modplatform/ftb/FtbListModel.cpp
@@ -1,8 +1,7 @@
#include "FtbListModel.h"
#include "BuildConfig.h"
-#include "Env.h"
-#include "Launcher.h"
+#include "Application.h"
#include "Json.h"
#include <QPainter>
@@ -46,7 +45,7 @@ QVariant ListModel::data(const QModelIndex &index, int role) const
}
else if(role == Qt::DecorationRole)
{
- QIcon placeholder = LAUNCHER->getThemedIcon("screenshot-placeholder");
+ QIcon placeholder = APPLICATION->getThemedIcon("screenshot-placeholder");
auto iter = m_logoMap.find(pack.name);
if (iter != m_logoMap.end()) {
@@ -78,7 +77,7 @@ void ListModel::getLogo(const QString &logo, const QString &logoUrl, LogoCallbac
{
if(m_logoMap.contains(logo))
{
- callback(ENV.metacache()->resolveEntry("ModpacksCHPacks", QString("logos/%1").arg(logo.section(".", 0, 0)))->getFullPath());
+ callback(APPLICATION->metacache()->resolveEntry("ModpacksCHPacks", QString("logos/%1").arg(logo.section(".", 0, 0)))->getFullPath());
}
else
{
@@ -96,7 +95,7 @@ void ListModel::request()
auto url = QString(BuildConfig.MODPACKSCH_API_BASE_URL + "public/modpack/all");
netJob->addNetAction(Net::Download::makeByteArray(QUrl(url), &response));
jobPtr = netJob;
- jobPtr->start();
+ jobPtr->start(APPLICATION->network());
QObject::connect(netJob, &NetJob::succeeded, this, &ListModel::requestFinished);
QObject::connect(netJob, &NetJob::failed, this, &ListModel::requestFailed);
@@ -140,7 +139,7 @@ void ListModel::requestPack()
.arg(currentPack);
netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), &response));
jobPtr = netJob;
- jobPtr->start();
+ jobPtr->start(APPLICATION->network());
QObject::connect(netJob, &NetJob::succeeded, this, &ListModel::packRequestFinished);
QObject::connect(netJob, &NetJob::failed, this, &ListModel::packRequestFailed);
@@ -252,7 +251,7 @@ void ListModel::requestLogo(QString logo, QString url)
return;
}
- MetaEntryPtr entry = ENV.metacache()->resolveEntry("ModpacksCHPacks", QString("logos/%1").arg(logo.section(".", 0, 0)));
+ MetaEntryPtr entry = APPLICATION->metacache()->resolveEntry("ModpacksCHPacks", QString("logos/%1").arg(logo.section(".", 0, 0)));
bool stale = entry->isStale();
@@ -273,7 +272,7 @@ void ListModel::requestLogo(QString logo, QString url)
auto &newLogoEntry = m_logoMap[logo];
newLogoEntry.downloadJob = job;
newLogoEntry.fullpath = fullPath;
- job->start();
+ job->start(APPLICATION->network());
}
}
diff --git a/launcher/pages/modplatform/ftb/FtbListModel.h b/launcher/ui/pages/modplatform/ftb/FtbListModel.h
index 2d6e91da..e2b73c25 100644
--- a/launcher/pages/modplatform/ftb/FtbListModel.h
+++ b/launcher/ui/pages/modplatform/ftb/FtbListModel.h
@@ -10,7 +10,7 @@ namespace Ftb {
struct Logo {
QString fullpath;
- NetJobPtr downloadJob;
+ NetJob::Ptr downloadJob;
QIcon result;
bool failed = false;
};
@@ -52,7 +52,7 @@ private:
QList<ModpacksCH::Modpack> modpacks;
LogoMap m_logoMap;
- NetJobPtr jobPtr;
+ NetJob::Ptr jobPtr;
int currentPack;
QList<int> remainingPacks;
QByteArray response;
diff --git a/launcher/pages/modplatform/ftb/FtbPage.cpp b/launcher/ui/pages/modplatform/ftb/FtbPage.cpp
index 620a56d8..a82de1d6 100644
--- a/launcher/pages/modplatform/ftb/FtbPage.cpp
+++ b/launcher/ui/pages/modplatform/ftb/FtbPage.cpp
@@ -3,7 +3,7 @@
#include <QKeyEvent>
-#include "dialogs/NewInstanceDialog.h"
+#include "ui/dialogs/NewInstanceDialog.h"
#include "modplatform/modpacksch/FTBPackInstallTask.h"
#include "HoeDown.h"
diff --git a/launcher/pages/modplatform/ftb/FtbPage.h b/launcher/ui/pages/modplatform/ftb/FtbPage.h
index 0a4a6cea..28a189f0 100644
--- a/launcher/pages/modplatform/ftb/FtbPage.h
+++ b/launcher/ui/pages/modplatform/ftb/FtbPage.h
@@ -20,8 +20,8 @@
#include <QWidget>
-#include "Launcher.h"
-#include "pages/BasePage.h"
+#include "Application.h"
+#include "ui/pages/BasePage.h"
#include "tasks/Task.h"
namespace Ui
@@ -44,7 +44,7 @@ public:
}
virtual QIcon icon() const override
{
- return LAUNCHER->getThemedIcon("ftb_logo");
+ return APPLICATION->getThemedIcon("ftb_logo");
}
virtual QString id() const override
{
diff --git a/launcher/pages/modplatform/ftb/FtbPage.ui b/launcher/ui/pages/modplatform/ftb/FtbPage.ui
index e9c783e3..e9c783e3 100644
--- a/launcher/pages/modplatform/ftb/FtbPage.ui
+++ b/launcher/ui/pages/modplatform/ftb/FtbPage.ui
diff --git a/launcher/pages/modplatform/legacy_ftb/ListModel.cpp b/launcher/ui/pages/modplatform/legacy_ftb/ListModel.cpp
index 78063c5f..5fa932b7 100644
--- a/launcher/pages/modplatform/legacy_ftb/ListModel.cpp
+++ b/launcher/ui/pages/modplatform/legacy_ftb/ListModel.cpp
@@ -1,5 +1,5 @@
#include "ListModel.h"
-#include "Launcher.h"
+#include "Application.h"
#include <MMCStrings.h>
#include <Version.h>
@@ -8,7 +8,6 @@
#include <QLabel>
#include <RWStorage.h>
-#include <Env.h>
#include <BuildConfig.h>
@@ -130,7 +129,7 @@ QVariant ListModel::data(const QModelIndex &index, int role) const
{
return (m_logoMap.value(pack.logo));
}
- QIcon icon = LAUNCHER->getThemedIcon("screenshot-placeholder");
+ QIcon icon = APPLICATION->getThemedIcon("screenshot-placeholder");
((ListModel *)this)->requestLogo(pack.logo);
return icon;
}
@@ -216,7 +215,7 @@ void ListModel::requestLogo(QString file)
return;
}
- MetaEntryPtr entry = ENV.metacache()->resolveEntry("FTBPacks", QString("logos/%1").arg(file.section(".", 0, 0)));
+ MetaEntryPtr entry = APPLICATION->metacache()->resolveEntry("FTBPacks", QString("logos/%1").arg(file.section(".", 0, 0)));
NetJob *job = new NetJob(QString("FTB Icon Download for %1").arg(file));
job->addNetAction(Net::Download::makeCached(QUrl(QString(BuildConfig.LEGACY_FTB_CDN_BASE_URL + "static/%1").arg(file)), entry));
@@ -235,7 +234,7 @@ void ListModel::requestLogo(QString file)
emit logoFailed(file);
});
- job->start();
+ job->start(APPLICATION->network());
m_loadingLogos.append(file);
}
@@ -244,7 +243,7 @@ void ListModel::getLogo(const QString &logo, LogoCallback callback)
{
if(m_logoMap.contains(logo))
{
- callback(ENV.metacache()->resolveEntry("FTBPacks", QString("logos/%1").arg(logo.section(".", 0, 0)))->getFullPath());
+ callback(APPLICATION->metacache()->resolveEntry("FTBPacks", QString("logos/%1").arg(logo.section(".", 0, 0)))->getFullPath());
}
else
{
diff --git a/launcher/pages/modplatform/legacy_ftb/ListModel.h b/launcher/ui/pages/modplatform/legacy_ftb/ListModel.h
index c55df000..c55df000 100644
--- a/launcher/pages/modplatform/legacy_ftb/ListModel.h
+++ b/launcher/ui/pages/modplatform/legacy_ftb/ListModel.h
diff --git a/launcher/pages/modplatform/legacy_ftb/Page.cpp b/launcher/ui/pages/modplatform/legacy_ftb/Page.cpp
index 6b6a7dcd..891704de 100644
--- a/launcher/pages/modplatform/legacy_ftb/Page.cpp
+++ b/launcher/ui/pages/modplatform/legacy_ftb/Page.cpp
@@ -3,9 +3,11 @@
#include <QInputDialog>
-#include "Launcher.h"
-#include "dialogs/CustomMessageBox.h"
-#include "dialogs/NewInstanceDialog.h"
+#include "Application.h"
+
+#include "ui/dialogs/CustomMessageBox.h"
+#include "ui/dialogs/NewInstanceDialog.h"
+
#include "modplatform/legacy_ftb/PackFetchTask.h"
#include "modplatform/legacy_ftb/PackInstallTask.h"
#include "modplatform/legacy_ftb/PrivatePackManager.h"
@@ -16,7 +18,7 @@ namespace LegacyFTB {
Page::Page(NewInstanceDialog* dialog, QWidget *parent)
: QWidget(parent), dialog(dialog), ui(new Ui::Page)
{
- ftbFetchTask.reset(new PackFetchTask());
+ ftbFetchTask.reset(new PackFetchTask(APPLICATION->network()));
ftbPrivatePacks.reset(new PrivatePackManager());
ui->setupUi(this);
@@ -133,7 +135,7 @@ void Page::suggestCurrent()
return;
}
- dialog->setSuggestedPack(selected.name, new PackInstallTask(selected, selectedVersion));
+ dialog->setSuggestedPack(selected.name, new PackInstallTask(APPLICATION->network(), selected, selectedVersion));
QString editedLogoName;
if(selected.logo.toLower().startsWith("ftb"))
{
diff --git a/launcher/pages/modplatform/legacy_ftb/Page.h b/launcher/ui/pages/modplatform/legacy_ftb/Page.h
index 6159cd9d..d8225e11 100644
--- a/launcher/pages/modplatform/legacy_ftb/Page.h
+++ b/launcher/ui/pages/modplatform/legacy_ftb/Page.h
@@ -19,8 +19,8 @@
#include <QTreeView>
#include <QTextBrowser>
-#include "pages/BasePage.h"
-#include <Launcher.h>
+#include "ui/pages/BasePage.h"
+#include <Application.h>
#include "tasks/Task.h"
#include "modplatform/legacy_ftb/PackHelpers.h"
#include "modplatform/legacy_ftb/PackFetchTask.h"
@@ -54,7 +54,7 @@ public:
}
QIcon icon() const override
{
- return LAUNCHER->getThemedIcon("ftb_logo");
+ return APPLICATION->getThemedIcon("ftb_logo");
}
QString id() const override
{
diff --git a/launcher/pages/modplatform/legacy_ftb/Page.ui b/launcher/ui/pages/modplatform/legacy_ftb/Page.ui
index 15e5d432..15e5d432 100644
--- a/launcher/pages/modplatform/legacy_ftb/Page.ui
+++ b/launcher/ui/pages/modplatform/legacy_ftb/Page.ui
diff --git a/launcher/pages/modplatform/technic/TechnicData.h b/launcher/ui/pages/modplatform/technic/TechnicData.h
index 50fd75e8..50fd75e8 100644
--- a/launcher/pages/modplatform/technic/TechnicData.h
+++ b/launcher/ui/pages/modplatform/technic/TechnicData.h
diff --git a/launcher/pages/modplatform/technic/TechnicModel.cpp b/launcher/ui/pages/modplatform/technic/TechnicModel.cpp
index cac6fef1..63c2d4c4 100644
--- a/launcher/pages/modplatform/technic/TechnicModel.cpp
+++ b/launcher/ui/pages/modplatform/technic/TechnicModel.cpp
@@ -14,8 +14,7 @@
*/
#include "TechnicModel.h"
-#include "Env.h"
-#include "Launcher.h"
+#include "Application.h"
#include "Json.h"
#include <QIcon>
@@ -47,7 +46,7 @@ QVariant Technic::ListModel::data(const QModelIndex& index, int role) const
{
return (m_logoMap.value(pack.logoName));
}
- QIcon icon = LAUNCHER->getThemedIcon("screenshot-placeholder");
+ QIcon icon = APPLICATION->getThemedIcon("screenshot-placeholder");
((ListModel *)this)->requestLogo(pack.logoName, pack.logoUrl);
return icon;
}
@@ -105,7 +104,7 @@ void Technic::ListModel::performSearch()
}
netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), &response));
jobPtr = netJob;
- jobPtr->start();
+ jobPtr->start(APPLICATION->network());
QObject::connect(netJob, &NetJob::succeeded, this, &ListModel::searchRequestFinished);
QObject::connect(netJob, &NetJob::failed, this, &ListModel::searchRequestFailed);
}
@@ -163,7 +162,7 @@ void Technic::ListModel::getLogo(const QString& logo, const QString& logoUrl, Te
{
if(m_logoMap.contains(logo))
{
- callback(ENV.metacache()->resolveEntry("TechnicPacks", QString("logos/%1").arg(logo))->getFullPath());
+ callback(APPLICATION->metacache()->resolveEntry("TechnicPacks", QString("logos/%1").arg(logo))->getFullPath());
}
else
{
@@ -216,7 +215,7 @@ void Technic::ListModel::requestLogo(QString logo, QString url)
return;
}
- MetaEntryPtr entry = ENV.metacache()->resolveEntry("TechnicPacks", QString("logos/%1").arg(logo));
+ MetaEntryPtr entry = APPLICATION->metacache()->resolveEntry("TechnicPacks", QString("logos/%1").arg(logo));
NetJob *job = new NetJob(QString("Technic Icon Download %1").arg(logo));
job->addNetAction(Net::Download::makeCached(QUrl(url), entry));
@@ -232,7 +231,7 @@ void Technic::ListModel::requestLogo(QString logo, QString url)
logoFailed(logo);
});
- job->start();
+ job->start(APPLICATION->network());
m_loadingLogos.append(logo);
}
diff --git a/launcher/pages/modplatform/technic/TechnicModel.h b/launcher/ui/pages/modplatform/technic/TechnicModel.h
index 82a03842..e80e6e7c 100644
--- a/launcher/pages/modplatform/technic/TechnicModel.h
+++ b/launcher/ui/pages/modplatform/technic/TechnicModel.h
@@ -63,7 +63,7 @@ private:
ResetRequested,
Finished
} searchState = None;
- NetJobPtr jobPtr;
+ NetJob::Ptr jobPtr;
QByteArray response;
};
diff --git a/launcher/pages/modplatform/technic/TechnicPage.cpp b/launcher/ui/pages/modplatform/technic/TechnicPage.cpp
index 4f27e685..ac69675c 100644
--- a/launcher/pages/modplatform/technic/TechnicPage.cpp
+++ b/launcher/ui/pages/modplatform/technic/TechnicPage.cpp
@@ -16,14 +16,17 @@
#include "TechnicPage.h"
#include "ui_TechnicPage.h"
-#include "Launcher.h"
-#include "dialogs/NewInstanceDialog.h"
-#include "TechnicModel.h"
#include <QKeyEvent>
+
+#include "ui/dialogs/NewInstanceDialog.h"
+
+#include "TechnicModel.h"
#include "modplatform/technic/SingleZipPackInstallTask.h"
#include "modplatform/technic/SolderPackInstallTask.h"
#include "Json.h"
+#include "Application.h"
+
TechnicPage::TechnicPage(NewInstanceDialog* dialog, QWidget *parent)
: QWidget(parent), ui(new Ui::TechnicPage), dialog(dialog)
{
@@ -164,7 +167,7 @@ void TechnicPage::suggestCurrent()
current.metadataLoaded = true;
metadataLoaded();
});
- netJob->start();
+ netJob->start(APPLICATION->network());
}
// expects current.metadataLoaded to be true
@@ -193,6 +196,6 @@ void TechnicPage::metadataLoaded()
else
{
while (current.url.endsWith('/')) current.url.chop(1);
- dialog->setSuggestedPack(current.name, new Technic::SolderPackInstallTask(current.url + "/modpack/" + current.slug, current.minecraftVersion));
+ dialog->setSuggestedPack(current.name, new Technic::SolderPackInstallTask(APPLICATION->network(), current.url + "/modpack/" + current.slug, current.minecraftVersion));
}
}
diff --git a/launcher/pages/modplatform/technic/TechnicPage.h b/launcher/ui/pages/modplatform/technic/TechnicPage.h
index f0619a52..21695dd0 100644
--- a/launcher/pages/modplatform/technic/TechnicPage.h
+++ b/launcher/ui/pages/modplatform/technic/TechnicPage.h
@@ -17,8 +17,8 @@
#include <QWidget>
-#include "pages/BasePage.h"
-#include <Launcher.h>
+#include "ui/pages/BasePage.h"
+#include <Application.h>
#include "tasks/Task.h"
#include "TechnicData.h"
@@ -46,7 +46,7 @@ public:
}
virtual QIcon icon() const override
{
- return LAUNCHER->getThemedIcon("technic");
+ return APPLICATION->getThemedIcon("technic");
}
virtual QString id() const override
{
diff --git a/launcher/pages/modplatform/technic/TechnicPage.ui b/launcher/ui/pages/modplatform/technic/TechnicPage.ui
index 2ca45dd2..dde685d9 100644
--- a/launcher/pages/modplatform/technic/TechnicPage.ui
+++ b/launcher/ui/pages/modplatform/technic/TechnicPage.ui
@@ -81,7 +81,7 @@
<customwidget>
<class>MCModInfoFrame</class>
<extends>QFrame</extends>
- <header>widgets/MCModInfoFrame.h</header>
+ <header>ui/widgets/MCModInfoFrame.h</header>
<container>1</container>
</customwidget>
</customwidgets>
diff --git a/launcher/setupwizard/AnalyticsWizardPage.cpp b/launcher/ui/setupwizard/AnalyticsWizardPage.cpp
index f1d7b006..3db2f6dc 100644
--- a/launcher/setupwizard/AnalyticsWizardPage.cpp
+++ b/launcher/ui/setupwizard/AnalyticsWizardPage.cpp
@@ -1,5 +1,5 @@
#include "AnalyticsWizardPage.h"
-#include <Launcher.h>
+#include <Application.h>
#include <QVBoxLayout>
#include <QTextBrowser>
@@ -33,8 +33,8 @@ AnalyticsWizardPage::~AnalyticsWizardPage()
bool AnalyticsWizardPage::validatePage()
{
- auto settings = LAUNCHER->settings();
- auto analytics = LAUNCHER->analytics();
+ auto settings = APPLICATION->settings();
+ auto analytics = APPLICATION->analytics();
auto status = checkBox->isChecked();
settings->set("AnalyticsSeen", analytics->version());
settings->set("Analytics", status);
diff --git a/launcher/setupwizard/AnalyticsWizardPage.h b/launcher/ui/setupwizard/AnalyticsWizardPage.h
index c451db2c..c451db2c 100644
--- a/launcher/setupwizard/AnalyticsWizardPage.h
+++ b/launcher/ui/setupwizard/AnalyticsWizardPage.h
diff --git a/launcher/setupwizard/BaseWizardPage.h b/launcher/ui/setupwizard/BaseWizardPage.h
index 72dbecfd..72dbecfd 100644
--- a/launcher/setupwizard/BaseWizardPage.h
+++ b/launcher/ui/setupwizard/BaseWizardPage.h
diff --git a/launcher/setupwizard/JavaWizardPage.cpp b/launcher/ui/setupwizard/JavaWizardPage.cpp
index a60090ce..63b3d480 100644
--- a/launcher/setupwizard/JavaWizardPage.cpp
+++ b/launcher/ui/setupwizard/JavaWizardPage.cpp
@@ -1,5 +1,5 @@
#include "JavaWizardPage.h"
-#include <Launcher.h>
+#include "Application.h"
#include <QVBoxLayout>
#include <QGroupBox>
@@ -8,16 +8,18 @@
#include <QLineEdit>
#include <QPushButton>
#include <QToolButton>
-#include <widgets/VersionSelectWidget.h>
-#include <FileSystem.h>
+#include <QFileDialog>
-#include <java/JavaInstall.h>
-#include <dialogs/CustomMessageBox.h>
-#include <java/JavaUtils.h>
#include <sys.h>
-#include <QFileDialog>
-#include <JavaCommon.h>
-#include "widgets/JavaSettingsWidget.h"
+
+#include "FileSystem.h"
+#include "java/JavaInstall.h"
+#include "java/JavaUtils.h"
+#include "JavaCommon.h"
+
+#include "ui/widgets/VersionSelectWidget.h"
+#include "ui/dialogs/CustomMessageBox.h"
+#include "ui/widgets/JavaSettingsWidget.h"
JavaWizardPage::JavaWizardPage(QWidget *parent)
@@ -55,7 +57,7 @@ bool JavaWizardPage::wantsRefreshButton()
bool JavaWizardPage::validatePage()
{
- auto settings = LAUNCHER->settings();
+ auto settings = APPLICATION->settings();
auto result = m_java_widget->validate();
switch(result)
{
@@ -71,7 +73,7 @@ bool JavaWizardPage::validatePage()
case JavaSettingsWidget::ValidationStatus::JavaBad:
{
// Memory
- auto s = LAUNCHER->settings();
+ auto s = APPLICATION->settings();
s->set("MinMemAlloc", m_java_widget->minHeapSize());
s->set("MaxMemAlloc", m_java_widget->maxHeapSize());
if (m_java_widget->permGenEnabled())
diff --git a/launcher/setupwizard/JavaWizardPage.h b/launcher/ui/setupwizard/JavaWizardPage.h
index 0d749039..0d749039 100644
--- a/launcher/setupwizard/JavaWizardPage.h
+++ b/launcher/ui/setupwizard/JavaWizardPage.h
diff --git a/launcher/setupwizard/LanguageWizardPage.cpp b/launcher/ui/setupwizard/LanguageWizardPage.cpp
index e352ccca..072df10d 100644
--- a/launcher/setupwizard/LanguageWizardPage.cpp
+++ b/launcher/ui/setupwizard/LanguageWizardPage.cpp
@@ -1,8 +1,8 @@
#include "LanguageWizardPage.h"
-#include <Launcher.h>
+#include <Application.h>
#include <translations/TranslationsModel.h>
-#include "widgets/LanguageSelectionWidget.h"
+#include "ui/widgets/LanguageSelectionWidget.h"
#include <QVBoxLayout>
#include <BuildConfig.h>
@@ -29,13 +29,13 @@ bool LanguageWizardPage::wantsRefreshButton()
void LanguageWizardPage::refresh()
{
- auto translations = LAUNCHER->translations();
+ auto translations = APPLICATION->translations();
translations->downloadIndex();
}
bool LanguageWizardPage::validatePage()
{
- auto settings = LAUNCHER->settings();
+ auto settings = APPLICATION->settings();
QString key = mainWidget->getSelectedLanguageKey();
settings->set("Language", key);
return true;
diff --git a/launcher/setupwizard/LanguageWizardPage.h b/launcher/ui/setupwizard/LanguageWizardPage.h
index 45a0e5c0..45a0e5c0 100644
--- a/launcher/setupwizard/LanguageWizardPage.h
+++ b/launcher/ui/setupwizard/LanguageWizardPage.h
diff --git a/launcher/setupwizard/SetupWizard.cpp b/launcher/ui/setupwizard/SetupWizard.cpp
index 46b2ef79..5af5ba91 100644
--- a/launcher/setupwizard/SetupWizard.cpp
+++ b/launcher/ui/setupwizard/SetupWizard.cpp
@@ -5,7 +5,7 @@
#include "AnalyticsWizardPage.h"
#include "translations/TranslationsModel.h"
-#include <Launcher.h>
+#include <Application.h>
#include <FileSystem.h>
#include <ganalytics.h>
diff --git a/launcher/setupwizard/SetupWizard.h b/launcher/ui/setupwizard/SetupWizard.h
index 9b8adb4d..9b8adb4d 100644
--- a/launcher/setupwizard/SetupWizard.h
+++ b/launcher/ui/setupwizard/SetupWizard.h
diff --git a/launcher/themes/BrightTheme.cpp b/launcher/ui/themes/BrightTheme.cpp
index b9188bdd..b9188bdd 100644
--- a/launcher/themes/BrightTheme.cpp
+++ b/launcher/ui/themes/BrightTheme.cpp
diff --git a/launcher/themes/BrightTheme.h b/launcher/ui/themes/BrightTheme.h
index c61f52d5..c61f52d5 100644
--- a/launcher/themes/BrightTheme.h
+++ b/launcher/ui/themes/BrightTheme.h
diff --git a/launcher/themes/CustomTheme.cpp b/launcher/ui/themes/CustomTheme.cpp
index 3e3e27de..3e3e27de 100644
--- a/launcher/themes/CustomTheme.cpp
+++ b/launcher/ui/themes/CustomTheme.cpp
diff --git a/launcher/themes/CustomTheme.h b/launcher/ui/themes/CustomTheme.h
index d216895d..d216895d 100644
--- a/launcher/themes/CustomTheme.h
+++ b/launcher/ui/themes/CustomTheme.h
diff --git a/launcher/themes/DarkTheme.cpp b/launcher/ui/themes/DarkTheme.cpp
index 31ecd559..31ecd559 100644
--- a/launcher/themes/DarkTheme.cpp
+++ b/launcher/ui/themes/DarkTheme.cpp
diff --git a/launcher/themes/DarkTheme.h b/launcher/ui/themes/DarkTheme.h
index 9bd2f343..9bd2f343 100644
--- a/launcher/themes/DarkTheme.h
+++ b/launcher/ui/themes/DarkTheme.h
diff --git a/launcher/themes/FusionTheme.cpp b/launcher/ui/themes/FusionTheme.cpp
index cf3286ba..cf3286ba 100644
--- a/launcher/themes/FusionTheme.cpp
+++ b/launcher/ui/themes/FusionTheme.cpp
diff --git a/launcher/themes/FusionTheme.h b/launcher/ui/themes/FusionTheme.h
index ee34245a..ee34245a 100644
--- a/launcher/themes/FusionTheme.h
+++ b/launcher/ui/themes/FusionTheme.h
diff --git a/launcher/themes/ITheme.cpp b/launcher/ui/themes/ITheme.cpp
index 321b0d9b..7247b444 100644
--- a/launcher/themes/ITheme.cpp
+++ b/launcher/ui/themes/ITheme.cpp
@@ -2,7 +2,7 @@
#include "rainbow.h"
#include <QStyleFactory>
#include <QDir>
-#include "Launcher.h"
+#include "Application.h"
void ITheme::apply(bool)
{
@@ -13,11 +13,11 @@ void ITheme::apply(bool)
}
if(hasStyleSheet())
{
- LAUNCHER->setStyleSheet(appStyleSheet());
+ APPLICATION->setStyleSheet(appStyleSheet());
}
else
{
- LAUNCHER->setStyleSheet(QString());
+ APPLICATION->setStyleSheet(QString());
}
QDir::setSearchPaths("theme", searchPaths());
}
diff --git a/launcher/themes/ITheme.h b/launcher/ui/themes/ITheme.h
index c2347cf6..c2347cf6 100644
--- a/launcher/themes/ITheme.h
+++ b/launcher/ui/themes/ITheme.h
diff --git a/launcher/themes/SystemTheme.cpp b/launcher/ui/themes/SystemTheme.cpp
index 49b1afaa..49b1afaa 100644
--- a/launcher/themes/SystemTheme.cpp
+++ b/launcher/ui/themes/SystemTheme.cpp
diff --git a/launcher/themes/SystemTheme.h b/launcher/ui/themes/SystemTheme.h
index fe450600..fe450600 100644
--- a/launcher/themes/SystemTheme.h
+++ b/launcher/ui/themes/SystemTheme.h
diff --git a/launcher/widgets/Common.cpp b/launcher/ui/widgets/Common.cpp
index f72f3596..f72f3596 100644
--- a/launcher/widgets/Common.cpp
+++ b/launcher/ui/widgets/Common.cpp
diff --git a/launcher/widgets/Common.h b/launcher/ui/widgets/Common.h
index b3fbe1a0..b3fbe1a0 100644
--- a/launcher/widgets/Common.h
+++ b/launcher/ui/widgets/Common.h
diff --git a/launcher/widgets/CustomCommands.cpp b/launcher/ui/widgets/CustomCommands.cpp
index 24bdc07d..24bdc07d 100644
--- a/launcher/widgets/CustomCommands.cpp
+++ b/launcher/ui/widgets/CustomCommands.cpp
diff --git a/launcher/widgets/CustomCommands.h b/launcher/ui/widgets/CustomCommands.h
index 8db991fa..8db991fa 100644
--- a/launcher/widgets/CustomCommands.h
+++ b/launcher/ui/widgets/CustomCommands.h
diff --git a/launcher/widgets/CustomCommands.ui b/launcher/ui/widgets/CustomCommands.ui
index 21964ad2..21964ad2 100644
--- a/launcher/widgets/CustomCommands.ui
+++ b/launcher/ui/widgets/CustomCommands.ui
diff --git a/launcher/widgets/DropLabel.cpp b/launcher/ui/widgets/DropLabel.cpp
index a900e57c..a900e57c 100644
--- a/launcher/widgets/DropLabel.cpp
+++ b/launcher/ui/widgets/DropLabel.cpp
diff --git a/launcher/widgets/DropLabel.h b/launcher/ui/widgets/DropLabel.h
index c5ca0bcc..c5ca0bcc 100644
--- a/launcher/widgets/DropLabel.h
+++ b/launcher/ui/widgets/DropLabel.h
diff --git a/launcher/ui/widgets/ErrorFrame.cpp b/launcher/ui/widgets/ErrorFrame.cpp
new file mode 100644
index 00000000..b3e41036
--- /dev/null
+++ b/launcher/ui/widgets/ErrorFrame.cpp
@@ -0,0 +1,134 @@
+/* Copyright 2013-2021 MultiMC Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <QMessageBox>
+#include <QtGui>
+
+#include "ErrorFrame.h"
+#include "ui_ErrorFrame.h"
+
+#include "ui/dialogs/CustomMessageBox.h"
+
+void ErrorFrame::clear()
+{
+ setTitle(QString());
+ setDescription(QString());
+}
+
+ErrorFrame::ErrorFrame(QWidget *parent) :
+ QFrame(parent),
+ ui(new Ui::ErrorFrame)
+{
+ ui->setupUi(this);
+ ui->label_Description->setHidden(true);
+ ui->label_Title->setHidden(true);
+ updateHiddenState();
+}
+
+ErrorFrame::~ErrorFrame()
+{
+ delete ui;
+}
+
+void ErrorFrame::updateHiddenState()
+{
+ if(ui->label_Description->isHidden() && ui->label_Title->isHidden())
+ {
+ setHidden(true);
+ }
+ else
+ {
+ setHidden(false);
+ }
+}
+
+void ErrorFrame::setTitle(QString text)
+{
+ if(text.isEmpty())
+ {
+ ui->label_Title->setHidden(true);
+ }
+ else
+ {
+ ui->label_Title->setText(text);
+ ui->label_Title->setHidden(false);
+ }
+ updateHiddenState();
+}
+
+void ErrorFrame::setDescription(QString text)
+{
+ if(text.isEmpty())
+ {
+ ui->label_Description->setHidden(true);
+ updateHiddenState();
+ return;
+ }
+ else
+ {
+ ui->label_Description->setHidden(false);
+ updateHiddenState();
+ }
+ ui->label_Description->setToolTip("");
+ QString intermediatetext = text.trimmed();
+ bool prev(false);
+ QChar rem('\n');
+ QString finaltext;
+ finaltext.reserve(intermediatetext.size());
+ foreach(const QChar& c, intermediatetext)
+ {
+ if(c == rem && prev){
+ continue;
+ }
+ prev = c == rem;
+ finaltext += c;
+ }
+ QString labeltext;
+ labeltext.reserve(300);
+ if(finaltext.length() > 290)
+ {
+ ui->label_Description->setOpenExternalLinks(false);
+ ui->label_Description->setTextFormat(Qt::TextFormat::RichText);
+ desc = text;
+ // This allows injecting HTML here.
+ labeltext.append("<html><body>" + finaltext.left(287) + "<a href=\"#mod_desc\">...</a></body></html>");
+ QObject::connect(ui->label_Description, &QLabel::linkActivated, this, &ErrorFrame::ellipsisHandler);
+ }
+ else
+ {
+ ui->label_Description->setTextFormat(Qt::TextFormat::PlainText);
+ labeltext.append(finaltext);
+ }
+ ui->label_Description->setText(labeltext);
+}
+
+void ErrorFrame::ellipsisHandler(const QString &link)
+{
+ if(!currentBox)
+ {
+ currentBox = CustomMessageBox::selectable(this, QString(), desc);
+ connect(currentBox, &QMessageBox::finished, this, &ErrorFrame::boxClosed);
+ currentBox->show();
+ }
+ else
+ {
+ currentBox->setText(desc);
+ }
+}
+
+void ErrorFrame::boxClosed(int result)
+{
+ currentBox = nullptr;
+}
diff --git a/launcher/ui/widgets/ErrorFrame.h b/launcher/ui/widgets/ErrorFrame.h
new file mode 100644
index 00000000..d5069a14
--- /dev/null
+++ b/launcher/ui/widgets/ErrorFrame.h
@@ -0,0 +1,49 @@
+/* Copyright 2013-2021 MultiMC Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <QFrame>
+
+namespace Ui
+{
+class ErrorFrame;
+}
+
+class ErrorFrame : public QFrame
+{
+ Q_OBJECT
+
+public:
+ explicit ErrorFrame(QWidget *parent = 0);
+ ~ErrorFrame();
+
+ void setTitle(QString text);
+ void setDescription(QString text);
+
+ void clear();
+
+public slots:
+ void ellipsisHandler(const QString& link );
+ void boxClosed(int result);
+
+private:
+ void updateHiddenState();
+
+private:
+ Ui::ErrorFrame *ui;
+ QString desc;
+ class QMessageBox * currentBox = nullptr;
+};
diff --git a/launcher/ui/widgets/ErrorFrame.ui b/launcher/ui/widgets/ErrorFrame.ui
new file mode 100644
index 00000000..0bb56743
--- /dev/null
+++ b/launcher/ui/widgets/ErrorFrame.ui
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ErrorFrame</class>
+ <widget class="QFrame" name="ErrorFrame">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>527</width>
+ <height>113</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>120</height>
+ </size>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="label_Title">
+ <property name="text">
+ <string notr="true"/>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::RichText</enum>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ <property name="openExternalLinks">
+ <bool>true</bool>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_Description">
+ <property name="toolTip">
+ <string notr="true"/>
+ </property>
+ <property name="text">
+ <string notr="true"/>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::RichText</enum>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ <property name="openExternalLinks">
+ <bool>true</bool>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/launcher/widgets/FocusLineEdit.cpp b/launcher/ui/widgets/FocusLineEdit.cpp
index b272100c..b272100c 100644
--- a/launcher/widgets/FocusLineEdit.cpp
+++ b/launcher/ui/widgets/FocusLineEdit.cpp
diff --git a/launcher/widgets/FocusLineEdit.h b/launcher/ui/widgets/FocusLineEdit.h
index 71b4f140..71b4f140 100644
--- a/launcher/widgets/FocusLineEdit.h
+++ b/launcher/ui/widgets/FocusLineEdit.h
diff --git a/launcher/widgets/IconLabel.cpp b/launcher/ui/widgets/IconLabel.cpp
index bf1c2358..bf1c2358 100644
--- a/launcher/widgets/IconLabel.cpp
+++ b/launcher/ui/widgets/IconLabel.cpp
diff --git a/launcher/widgets/IconLabel.h b/launcher/ui/widgets/IconLabel.h
index 6d212c4c..6d212c4c 100644
--- a/launcher/widgets/IconLabel.h
+++ b/launcher/ui/widgets/IconLabel.h
diff --git a/launcher/widgets/InstanceCardWidget.ui b/launcher/ui/widgets/InstanceCardWidget.ui
index 6eeeb076..6eeeb076 100644
--- a/launcher/widgets/InstanceCardWidget.ui
+++ b/launcher/ui/widgets/InstanceCardWidget.ui
diff --git a/launcher/widgets/JavaSettingsWidget.cpp b/launcher/ui/widgets/JavaSettingsWidget.cpp
index 11f0653a..b9d7620c 100644
--- a/launcher/widgets/JavaSettingsWidget.cpp
+++ b/launcher/ui/widgets/JavaSettingsWidget.cpp
@@ -1,10 +1,4 @@
#include "JavaSettingsWidget.h"
-#include <Launcher.h>
-
-#include <java/JavaInstall.h>
-#include <dialogs/CustomMessageBox.h>
-#include <java/JavaUtils.h>
-#include <sys.h>
#include <QVBoxLayout>
#include <QGroupBox>
@@ -13,18 +7,27 @@
#include <QLineEdit>
#include <QPushButton>
#include <QToolButton>
-#include <widgets/VersionSelectWidget.h>
-#include <FileSystem.h>
#include <QFileDialog>
-#include <BuildConfig.h>
+
+#include <sys.h>
+
+#include "java/JavaInstall.h"
+#include "java/JavaUtils.h"
+#include "FileSystem.h"
+
+#include "ui/dialogs/CustomMessageBox.h"
+#include "ui/widgets/VersionSelectWidget.h"
+
+#include "Application.h"
+#include "BuildConfig.h"
JavaSettingsWidget::JavaSettingsWidget(QWidget* parent) : QWidget(parent)
{
m_availableMemory = Sys::getSystemRam() / Sys::mebibyte;
- goodIcon = LAUNCHER->getThemedIcon("status-good");
- yellowIcon = LAUNCHER->getThemedIcon("status-yellow");
- badIcon = LAUNCHER->getThemedIcon("status-bad");
+ goodIcon = APPLICATION->getThemedIcon("status-good");
+ yellowIcon = APPLICATION->getThemedIcon("status-yellow");
+ badIcon = APPLICATION->getThemedIcon("status-bad");
setupUi();
connect(m_minMemSpinBox, SIGNAL(valueChanged(int)), this, SLOT(memoryValueChanged(int)));
@@ -116,9 +119,9 @@ void JavaSettingsWidget::setupUi()
void JavaSettingsWidget::initialize()
{
- m_versionWidget->initialize(LAUNCHER->javalist().get());
+ m_versionWidget->initialize(APPLICATION->javalist().get());
m_versionWidget->setResizeOn(2);
- auto s = LAUNCHER->settings();
+ auto s = APPLICATION->settings();
// Memory
observedMinMemory = s->get("MinMemAlloc").toInt();
observedMaxMemory = s->get("MaxMemAlloc").toInt();
diff --git a/launcher/widgets/JavaSettingsWidget.h b/launcher/ui/widgets/JavaSettingsWidget.h
index 0d280daf..0d280daf 100644
--- a/launcher/widgets/JavaSettingsWidget.h
+++ b/launcher/ui/widgets/JavaSettingsWidget.h
diff --git a/launcher/widgets/LabeledToolButton.cpp b/launcher/ui/widgets/LabeledToolButton.cpp
index ab2d3278..ab2d3278 100644
--- a/launcher/widgets/LabeledToolButton.cpp
+++ b/launcher/ui/widgets/LabeledToolButton.cpp
diff --git a/launcher/widgets/LabeledToolButton.h b/launcher/ui/widgets/LabeledToolButton.h
index 51f99e9b..51f99e9b 100644
--- a/launcher/widgets/LabeledToolButton.h
+++ b/launcher/ui/widgets/LabeledToolButton.h
diff --git a/launcher/widgets/LanguageSelectionWidget.cpp b/launcher/ui/widgets/LanguageSelectionWidget.cpp
index 2b972ba7..cf70c7b4 100644
--- a/launcher/widgets/LanguageSelectionWidget.cpp
+++ b/launcher/ui/widgets/LanguageSelectionWidget.cpp
@@ -4,7 +4,7 @@
#include <QTreeView>
#include <QHeaderView>
#include <QLabel>
-#include "Launcher.h"
+#include "Application.h"
#include "translations/TranslationsModel.h"
LanguageSelectionWidget::LanguageSelectionWidget(QWidget *parent) :
@@ -29,7 +29,7 @@ LanguageSelectionWidget::LanguageSelectionWidget(QWidget *parent) :
helpUsLabel->setWordWrap(true);
verticalLayout->addWidget(helpUsLabel);
- auto translations = LAUNCHER->translations();
+ auto translations = APPLICATION->translations();
auto index = translations->selectedIndex();
languageView->setModel(translations.get());
languageView->setCurrentIndex(index);
@@ -41,7 +41,7 @@ LanguageSelectionWidget::LanguageSelectionWidget(QWidget *parent) :
QString LanguageSelectionWidget::getSelectedLanguageKey() const
{
- auto translations = LAUNCHER->translations();
+ auto translations = APPLICATION->translations();
return translations->data(languageView->currentIndex(), Qt::UserRole).toString();
}
@@ -59,7 +59,7 @@ void LanguageSelectionWidget::languageRowChanged(const QModelIndex& current, con
{
return;
}
- auto translations = LAUNCHER->translations();
+ auto translations = APPLICATION->translations();
QString key = translations->data(current, Qt::UserRole).toString();
translations->selectLanguage(key);
translations->updateLanguage(key);
diff --git a/launcher/widgets/LanguageSelectionWidget.h b/launcher/ui/widgets/LanguageSelectionWidget.h
index e65936db..e65936db 100644
--- a/launcher/widgets/LanguageSelectionWidget.h
+++ b/launcher/ui/widgets/LanguageSelectionWidget.h
diff --git a/launcher/widgets/LineSeparator.cpp b/launcher/ui/widgets/LineSeparator.cpp
index d03e6762..d03e6762 100644
--- a/launcher/widgets/LineSeparator.cpp
+++ b/launcher/ui/widgets/LineSeparator.cpp
diff --git a/launcher/widgets/LineSeparator.h b/launcher/ui/widgets/LineSeparator.h
index 22927b68..22927b68 100644
--- a/launcher/widgets/LineSeparator.h
+++ b/launcher/ui/widgets/LineSeparator.h
diff --git a/launcher/widgets/LogView.cpp b/launcher/ui/widgets/LogView.cpp
index 26a2a527..26a2a527 100644
--- a/launcher/widgets/LogView.cpp
+++ b/launcher/ui/widgets/LogView.cpp
diff --git a/launcher/widgets/LogView.h b/launcher/ui/widgets/LogView.h
index 3143360a..3143360a 100644
--- a/launcher/widgets/LogView.h
+++ b/launcher/ui/widgets/LogView.h
diff --git a/launcher/widgets/MCModInfoFrame.cpp b/launcher/ui/widgets/MCModInfoFrame.cpp
index 5b1f6230..8c4bd690 100644
--- a/launcher/widgets/MCModInfoFrame.cpp
+++ b/launcher/ui/widgets/MCModInfoFrame.cpp
@@ -18,7 +18,8 @@
#include "MCModInfoFrame.h"
#include "ui_MCModInfoFrame.h"
-#include "dialogs/CustomMessageBox.h"
+
+#include "ui/dialogs/CustomMessageBox.h"
void MCModInfoFrame::updateWithMod(Mod &m)
{
diff --git a/launcher/widgets/MCModInfoFrame.h b/launcher/ui/widgets/MCModInfoFrame.h
index 0b7ef537..0b7ef537 100644
--- a/launcher/widgets/MCModInfoFrame.h
+++ b/launcher/ui/widgets/MCModInfoFrame.h
diff --git a/launcher/widgets/MCModInfoFrame.ui b/launcher/ui/widgets/MCModInfoFrame.ui
index 5ef33379..5ef33379 100644
--- a/launcher/widgets/MCModInfoFrame.ui
+++ b/launcher/ui/widgets/MCModInfoFrame.ui
diff --git a/launcher/widgets/ModListView.cpp b/launcher/ui/widgets/ModListView.cpp
index c8ccd292..c8ccd292 100644
--- a/launcher/widgets/ModListView.cpp
+++ b/launcher/ui/widgets/ModListView.cpp
diff --git a/launcher/widgets/ModListView.h b/launcher/ui/widgets/ModListView.h
index 881e092f..881e092f 100644
--- a/launcher/widgets/ModListView.h
+++ b/launcher/ui/widgets/ModListView.h
diff --git a/launcher/widgets/PageContainer.cpp b/launcher/ui/widgets/PageContainer.cpp
index 25e3b676..74a6dff3 100644
--- a/launcher/widgets/PageContainer.cpp
+++ b/launcher/ui/widgets/PageContainer.cpp
@@ -14,6 +14,7 @@
*/
#include "PageContainer.h"
+#include "PageContainer_p.h"
#include <QStackedLayout>
#include <QPushButton>
@@ -26,12 +27,12 @@
#include <QDialogButtonBox>
#include <QGridLayout>
-#include "Launcher.h"
#include "settings/SettingsObject.h"
-#include "widgets/IconLabel.h"
-#include "PageContainer_p.h"
-#include <Launcher.h>
-#include <DesktopServices.h>
+
+#include "ui/widgets/IconLabel.h"
+
+#include "DesktopServices.h"
+#include "Application.h"
class PageEntryFilterModel : public QSortFilterProxyModel
{
@@ -139,12 +140,12 @@ void PageContainer::createUI()
m_header->setFont(headerLabelFont);
QHBoxLayout *headerHLayout = new QHBoxLayout;
- const int leftMargin = LAUNCHER->style()->pixelMetric(QStyle::PM_LayoutLeftMargin);
+ const int leftMargin = APPLICATION->style()->pixelMetric(QStyle::PM_LayoutLeftMargin);
headerHLayout->addSpacerItem(new QSpacerItem(leftMargin, 0, QSizePolicy::Fixed, QSizePolicy::Ignored));
headerHLayout->addWidget(m_header);
headerHLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Ignored));
headerHLayout->addWidget(m_iconHeader);
- const int rightMargin = LAUNCHER->style()->pixelMetric(QStyle::PM_LayoutRightMargin);
+ const int rightMargin = APPLICATION->style()->pixelMetric(QStyle::PM_LayoutRightMargin);
headerHLayout->addSpacerItem(new QSpacerItem(rightMargin, 0, QSizePolicy::Fixed, QSizePolicy::Ignored));
headerHLayout->setContentsMargins(0, 6, 0, 0);
@@ -195,7 +196,7 @@ void PageContainer::showPage(int row)
{
m_pageStack->setCurrentIndex(0);
m_header->setText(QString());
- m_iconHeader->setIcon(LAUNCHER->getThemedIcon("bug"));
+ m_iconHeader->setIcon(APPLICATION->getThemedIcon("bug"));
}
}
diff --git a/launcher/widgets/PageContainer.h b/launcher/ui/widgets/PageContainer.h
index 976d34e9..8d2172db 100644
--- a/launcher/widgets/PageContainer.h
+++ b/launcher/ui/widgets/PageContainer.h
@@ -18,8 +18,8 @@
#include <QWidget>
#include <QModelIndex>
-#include "pages/BasePageProvider.h"
-#include "pages/BasePageContainer.h"
+#include "ui/pages/BasePageProvider.h"
+#include "ui/pages/BasePageContainer.h"
class QLayout;
class IconLabel;
diff --git a/launcher/widgets/PageContainer_p.h b/launcher/ui/widgets/PageContainer_p.h
index da1a66f4..da1a66f4 100644
--- a/launcher/widgets/PageContainer_p.h
+++ b/launcher/ui/widgets/PageContainer_p.h
diff --git a/launcher/widgets/ProgressWidget.cpp b/launcher/ui/widgets/ProgressWidget.cpp
index 911e555d..911e555d 100644
--- a/launcher/widgets/ProgressWidget.cpp
+++ b/launcher/ui/widgets/ProgressWidget.cpp
diff --git a/launcher/widgets/ProgressWidget.h b/launcher/ui/widgets/ProgressWidget.h
index fa67748a..fa67748a 100644
--- a/launcher/widgets/ProgressWidget.h
+++ b/launcher/ui/widgets/ProgressWidget.h
diff --git a/launcher/widgets/VersionListView.cpp b/launcher/ui/widgets/VersionListView.cpp
index 8424fedd..aba0b1a1 100644
--- a/launcher/widgets/VersionListView.cpp
+++ b/launcher/ui/widgets/VersionListView.cpp
@@ -19,7 +19,6 @@
#include <QDrag>
#include <QPainter>
#include "VersionListView.h"
-#include "Common.h"
VersionListView::VersionListView(QWidget *parent)
:QTreeView ( parent )
diff --git a/launcher/widgets/VersionListView.h b/launcher/ui/widgets/VersionListView.h
index 4153b314..4153b314 100644
--- a/launcher/widgets/VersionListView.h
+++ b/launcher/ui/widgets/VersionListView.h
diff --git a/launcher/widgets/VersionSelectWidget.cpp b/launcher/ui/widgets/VersionSelectWidget.cpp
index 9925a6b4..1209f118 100644
--- a/launcher/widgets/VersionSelectWidget.cpp
+++ b/launcher/ui/widgets/VersionSelectWidget.cpp
@@ -1,10 +1,13 @@
#include "VersionSelectWidget.h"
+
#include <QProgressBar>
#include <QVBoxLayout>
-#include "VersionListView.h"
#include <QHeaderView>
-#include <VersionProxyModel.h>
-#include <dialogs/CustomMessageBox.h>
+
+#include "VersionListView.h"
+#include "VersionProxyModel.h"
+
+#include "ui/dialogs/CustomMessageBox.h"
VersionSelectWidget::VersionSelectWidget(QWidget* parent)
: QWidget(parent)
diff --git a/launcher/widgets/VersionSelectWidget.h b/launcher/ui/widgets/VersionSelectWidget.h
index 0a649408..0a649408 100644
--- a/launcher/widgets/VersionSelectWidget.h
+++ b/launcher/ui/widgets/VersionSelectWidget.h
diff --git a/launcher/widgets/WideBar.cpp b/launcher/ui/widgets/WideBar.cpp
index cbd6c617..cbd6c617 100644
--- a/launcher/widgets/WideBar.cpp
+++ b/launcher/ui/widgets/WideBar.cpp
diff --git a/launcher/widgets/WideBar.h b/launcher/ui/widgets/WideBar.h
index d1b8cbe7..d1b8cbe7 100644
--- a/launcher/widgets/WideBar.h
+++ b/launcher/ui/widgets/WideBar.h
diff --git a/launcher/updater/DownloadTask.cpp b/launcher/updater/DownloadTask.cpp
index 875d9d84..eba59142 100644
--- a/launcher/updater/DownloadTask.cpp
+++ b/launcher/updater/DownloadTask.cpp
@@ -26,8 +26,12 @@
namespace GoUpdate
{
-DownloadTask::DownloadTask(Status status, QString target, QObject *parent)
- : Task(parent), m_updateFilesDir(target)
+DownloadTask::DownloadTask(
+ shared_qobject_ptr<QNetworkAccessManager> network,
+ Status status,
+ QString target,
+ QObject *parent
+) : Task(parent), m_updateFilesDir(target), m_network(network)
{
m_status = status;
@@ -63,7 +67,7 @@ void DownloadTask::loadVersionInfo()
connect(netJob, &NetJob::succeeded, this, &DownloadTask::processDownloadedVersionInfo);
connect(netJob, &NetJob::failed, this, &DownloadTask::vinfoDownloadFailed);
m_vinfoNetJob.reset(netJob);
- netJob->start();
+ netJob->start(m_network);
}
void DownloadTask::vinfoDownloadFailed()
@@ -117,7 +121,7 @@ void DownloadTask::processDownloadedVersionInfo()
setStatus(tr("Processing file lists - figuring out how to install the update..."));
// make a new netjob for the actual update files
- NetJobPtr netJob (new NetJob("Update Files"));
+ NetJob::Ptr netJob (new NetJob("Update Files"));
// fill netJob and operationList
if (!processFileLists(m_currentVersionFileList, m_newVersionFileList, m_status.rootPath, m_updateFilesDir.path(), netJob, m_operations))
@@ -141,7 +145,7 @@ void DownloadTask::processDownloadedVersionInfo()
}
qDebug() << "Begin downloading update files to" << m_updateFilesDir.path();
m_filesNetJob = netJob;
- m_filesNetJob->start();
+ m_filesNetJob->start(m_network);
}
void DownloadTask::fileDownloadFinished()
diff --git a/launcher/updater/DownloadTask.h b/launcher/updater/DownloadTask.h
index fc5030b4..eac26238 100644
--- a/launcher/updater/DownloadTask.h
+++ b/launcher/updater/DownloadTask.h
@@ -35,7 +35,7 @@ public:
*
* target is a template - XXXXXX at the end will be replaced with a random generated string, ensuring uniqueness
*/
- explicit DownloadTask(Status status, QString target, QObject* parent = 0);
+ explicit DownloadTask(shared_qobject_ptr<QNetworkAccessManager> network, Status status, QString target, QObject* parent = 0);
virtual ~DownloadTask() {};
/// Get the directory that will contain the update files.
@@ -62,13 +62,13 @@ protected:
*/
void loadVersionInfo();
- NetJobPtr m_vinfoNetJob;
+ NetJob::Ptr m_vinfoNetJob;
QByteArray currentVersionFileListData;
QByteArray newVersionFileListData;
Net::Download::Ptr m_currentVersionFileListDownload;
Net::Download::Ptr m_newVersionFileListDownload;
- NetJobPtr m_filesNetJob;
+ NetJob::Ptr m_filesNetJob;
Status m_status;
@@ -91,6 +91,9 @@ protected slots:
void fileDownloadFinished();
void fileDownloadFailed(QString reason);
void fileDownloadProgressChanged(qint64 current, qint64 total);
+
+private:
+ shared_qobject_ptr<QNetworkAccessManager> m_network;
};
}
diff --git a/launcher/updater/GoUpdate.cpp b/launcher/updater/GoUpdate.cpp
index 6167418e..76f68b55 100644
--- a/launcher/updater/GoUpdate.cpp
+++ b/launcher/updater/GoUpdate.cpp
@@ -68,7 +68,7 @@ bool processFileLists
const VersionFileList &newVersion,
const QString &rootPath,
const QString &tempPath,
- NetJobPtr job,
+ NetJob::Ptr job,
OperationList &ops
)
{
diff --git a/launcher/updater/GoUpdate.h b/launcher/updater/GoUpdate.h
index 8058e543..46a679ef 100644
--- a/launcher/updater/GoUpdate.h
+++ b/launcher/updater/GoUpdate.h
@@ -117,7 +117,7 @@ bool processFileLists
const VersionFileList &newVersion,
const QString &rootPath,
const QString &tempPath,
- NetJobPtr job,
+ NetJob::Ptr job,
OperationList &ops
);
diff --git a/launcher/updater/UpdateChecker.cpp b/launcher/updater/UpdateChecker.cpp
index c96a6c9f..c72bbe0b 100644
--- a/launcher/updater/UpdateChecker.cpp
+++ b/launcher/updater/UpdateChecker.cpp
@@ -26,8 +26,9 @@
#include "BuildConfig.h"
#include "sys.h"
-UpdateChecker::UpdateChecker(QString channelUrl, QString currentChannel, int currentBuild)
+UpdateChecker::UpdateChecker(shared_qobject_ptr<QNetworkAccessManager> nam, QString channelUrl, QString currentChannel, int currentBuild)
{
+ m_network = nam;
m_channelUrl = channelUrl;
m_currentChannel = currentChannel;
m_currentBuild = currentBuild;
@@ -103,12 +104,11 @@ void UpdateChecker::checkForUpdate(QString updateChannel, bool notifyNoUpdate)
QUrl indexUrl = QUrl(m_newRepoUrl).resolved(QUrl("index.json"));
- auto job = new NetJob("GoUpdate Repository Index");
- job->addNetAction(Net::Download::makeByteArray(indexUrl, &indexData));
- connect(job, &NetJob::succeeded, [this, notifyNoUpdate](){ updateCheckFinished(notifyNoUpdate); });
- connect(job, &NetJob::failed, this, &UpdateChecker::updateCheckFailed);
- indexJob.reset(job);
- job->start();
+ indexJob = new NetJob("GoUpdate Repository Index");
+ indexJob->addNetAction(Net::Download::makeByteArray(indexUrl, &indexData));
+ connect(indexJob.get(), &NetJob::succeeded, [this, notifyNoUpdate](){ updateCheckFinished(notifyNoUpdate); });
+ connect(indexJob.get(), &NetJob::failed, this, &UpdateChecker::updateCheckFailed);
+ indexJob->start(m_network);
}
void UpdateChecker::updateCheckFinished(bool notifyNoUpdate)
@@ -191,12 +191,11 @@ void UpdateChecker::updateChanList(bool notifyNoUpdate)
}
m_chanListLoading = true;
- NetJob *job = new NetJob("Update System Channel List");
- job->addNetAction(Net::Download::makeByteArray(QUrl(m_channelUrl), &chanlistData));
- connect(job, &NetJob::succeeded, [this, notifyNoUpdate]() { chanListDownloadFinished(notifyNoUpdate); });
- QObject::connect(job, &NetJob::failed, this, &UpdateChecker::chanListDownloadFailed);
- chanListJob.reset(job);
- job->start();
+ chanListJob = new NetJob("Update System Channel List");
+ chanListJob->addNetAction(Net::Download::makeByteArray(QUrl(m_channelUrl), &chanlistData));
+ connect(chanListJob.get(), &NetJob::succeeded, [this, notifyNoUpdate]() { chanListDownloadFinished(notifyNoUpdate); });
+ connect(chanListJob.get(), &NetJob::failed, this, &UpdateChecker::chanListDownloadFailed);
+ chanListJob->start(m_network);
}
void UpdateChecker::chanListDownloadFinished(bool notifyNoUpdate)
@@ -233,10 +232,12 @@ void UpdateChecker::chanListDownloadFinished(bool notifyNoUpdate)
for (QJsonValue chanVal : channelArray)
{
QJsonObject channelObj = chanVal.toObject();
- ChannelListEntry entry{channelObj.value("id").toVariant().toString(),
- channelObj.value("name").toVariant().toString(),
- channelObj.value("description").toVariant().toString(),
- channelObj.value("url").toVariant().toString()};
+ ChannelListEntry entry {
+ channelObj.value("id").toVariant().toString(),
+ channelObj.value("name").toVariant().toString(),
+ channelObj.value("description").toVariant().toString(),
+ channelObj.value("url").toVariant().toString()
+ };
if (entry.id.isEmpty() || entry.name.isEmpty() || entry.url.isEmpty())
{
qCritical() << "Channel list entry with empty ID, name, or URL. Skipping.";
@@ -253,8 +254,9 @@ void UpdateChecker::chanListDownloadFinished(bool notifyNoUpdate)
qDebug() << "Successfully loaded UpdateChecker channel list.";
// If we're waiting to check for updates, do that now.
- if (m_checkUpdateWaiting)
+ if (m_checkUpdateWaiting) {
checkForUpdate(m_deferredUpdateChannel, notifyNoUpdate);
+ }
emit channelListLoaded();
}
diff --git a/launcher/updater/UpdateChecker.h b/launcher/updater/UpdateChecker.h
index 219c3c62..13ee4efd 100644
--- a/launcher/updater/UpdateChecker.h
+++ b/launcher/updater/UpdateChecker.h
@@ -23,7 +23,7 @@ class UpdateChecker : public QObject
Q_OBJECT
public:
- UpdateChecker(QString channelUrl, QString currentChannel, int currentBuild);
+ UpdateChecker(shared_qobject_ptr<QNetworkAccessManager> nam, QString channelUrl, QString currentChannel, int currentBuild);
void checkForUpdate(QString updateChannel, bool notifyNoUpdate);
/*!
@@ -73,9 +73,11 @@ private slots:
private:
friend class UpdateCheckerTest;
- NetJobPtr indexJob;
+ shared_qobject_ptr<QNetworkAccessManager> m_network;
+
+ NetJob::Ptr indexJob;
QByteArray indexData;
- NetJobPtr chanListJob;
+ NetJob::Ptr chanListJob;
QByteArray chanlistData;
QString m_channelUrl;
diff --git a/launcher/updater/UpdateChecker_test.cpp b/launcher/updater/UpdateChecker_test.cpp
index 5702d9c6..ec55a40e 100644
--- a/launcher/updater/UpdateChecker_test.cpp
+++ b/launcher/updater/UpdateChecker_test.cpp
@@ -91,7 +91,8 @@ slots:
QFETCH(bool, valid);
QFETCH(QList<UpdateChecker::ChannelListEntry>, result);
- UpdateChecker checker(channelUrl, channel, 0);
+ shared_qobject_ptr<QNetworkAccessManager> nam = new QNetworkAccessManager();
+ UpdateChecker checker(nam, channelUrl, channel, 0);
QSignalSpy channelListLoadedSpy(&checker, SIGNAL(channelListLoaded()));
QVERIFY(channelListLoadedSpy.isValid());
@@ -119,7 +120,8 @@ slots:
QString channelUrl = findTestDataUrl("data/channels.json");
int currentBuild = 2;
- UpdateChecker checker(channelUrl, channel, currentBuild);
+ shared_qobject_ptr<QNetworkAccessManager> nam = new QNetworkAccessManager();
+ UpdateChecker checker(nam, channelUrl, channel, currentBuild);
QSignalSpy updateAvailableSpy(&checker, SIGNAL(updateAvailable(GoUpdate::Status)));
QVERIFY(updateAvailableSpy.isValid());
diff --git a/libraries/LocalPeer/CMakeLists.txt b/libraries/LocalPeer/CMakeLists.txt
index f476da38..1e7557ec 100644
--- a/libraries/LocalPeer/CMakeLists.txt
+++ b/libraries/LocalPeer/CMakeLists.txt
@@ -1,8 +1,7 @@
cmake_minimum_required(VERSION 3.1)
project(LocalPeer)
-find_package(Qt5Core REQUIRED QUIET)
-find_package(Qt5Network REQUIRED QUIET)
+find_package(Qt5 COMPONENTS Core Network REQUIRED)
set(SINGLE_SOURCES
src/LocalPeer.cpp
diff --git a/libraries/katabasis/CMakeLists.txt b/libraries/katabasis/CMakeLists.txt
index 2f9cb66d..c6115881 100644
--- a/libraries/katabasis/CMakeLists.txt
+++ b/libraries/katabasis/CMakeLists.txt
@@ -27,20 +27,18 @@ set(CMAKE_C_STANDARD 11)
find_package(Qt5 COMPONENTS Core Network REQUIRED)
set( katabasis_PRIVATE
- src/OAuth2.cpp
+ src/DeviceFlow.cpp
src/JsonResponse.cpp
src/JsonResponse.h
src/PollServer.cpp
src/Reply.cpp
- src/ReplyServer.cpp
)
set( katabasis_PUBLIC
- include/katabasis/OAuth2.h
+ include/katabasis/DeviceFlow.h
include/katabasis/Globals.h
include/katabasis/PollServer.h
include/katabasis/Reply.h
- include/katabasis/ReplyServer.h
include/katabasis/RequestParameter.h
)
diff --git a/libraries/katabasis/include/katabasis/Bits.h b/libraries/katabasis/include/katabasis/Bits.h
index 3fd2f530..f11f25d2 100644
--- a/libraries/katabasis/include/katabasis/Bits.h
+++ b/libraries/katabasis/include/katabasis/Bits.h
@@ -10,7 +10,11 @@ enum class Activity {
Idle,
LoggingIn,
LoggingOut,
- Refreshing
+ Refreshing,
+ FailedSoft, //!< soft failure. this generally means the user auth details haven't been invalidated
+ FailedHard, //!< hard failure. auth is invalid
+ FailedGone, //!< hard failure. auth is invalid, and the account no longer exists
+ Succeeded
};
enum class Validity {
diff --git a/libraries/katabasis/include/katabasis/DeviceFlow.h b/libraries/katabasis/include/katabasis/DeviceFlow.h
new file mode 100644
index 00000000..b68c92e0
--- /dev/null
+++ b/libraries/katabasis/include/katabasis/DeviceFlow.h
@@ -0,0 +1,150 @@
+#pragma once
+
+#include <QNetworkAccessManager>
+#include <QNetworkRequest>
+#include <QNetworkReply>
+#include <QPair>
+
+#include "Reply.h"
+#include "RequestParameter.h"
+#include "Bits.h"
+
+namespace Katabasis {
+
+class ReplyServer;
+class PollServer;
+
+/// Simple OAuth2 Device Flow authenticator.
+class DeviceFlow: public QObject
+{
+ Q_OBJECT
+public:
+ Q_ENUMS(GrantFlow)
+
+public:
+
+ struct Options {
+ QString userAgent = QStringLiteral("Katabasis/1.0");
+ QString responseType = QStringLiteral("code");
+ QString scope;
+ QString clientIdentifier;
+ QString clientSecret;
+ QUrl authorizationUrl;
+ QUrl accessTokenUrl;
+ };
+
+public:
+ /// Are we authenticated?
+ bool linked();
+
+ /// Authentication token.
+ QString token();
+
+ /// Provider-specific extra tokens, available after a successful authentication
+ QVariantMap extraTokens();
+
+public:
+ // TODO: put in `Options`
+ /// User-defined extra parameters to append to request URL
+ QVariantMap extraRequestParams();
+ void setExtraRequestParams(const QVariantMap &value);
+
+ // TODO: split up the class into multiple, each implementing one OAuth2 flow
+ /// Grant type (if non-standard)
+ QString grantType();
+ void setGrantType(const QString &value);
+
+public:
+ /// Constructor.
+ /// @param parent Parent object.
+ explicit DeviceFlow(Options & opts, Token & token, QObject *parent = 0, QNetworkAccessManager *manager = 0);
+
+ /// Get refresh token.
+ QString refreshToken();
+
+ /// Get token expiration time
+ QDateTime expires();
+
+public slots:
+ /// Authenticate.
+ void login();
+
+ /// De-authenticate.
+ void logout();
+
+ /// Refresh token.
+ bool refresh();
+
+ /// Handle situation where reply server has opted to close its connection
+ void serverHasClosed(bool paramsfound = false);
+
+signals:
+ /// Emitted when client needs to open a web browser window, with the given URL.
+ void openBrowser(const QUrl &url);
+
+ /// Emitted when client can close the browser window.
+ void closeBrowser();
+
+ /// Emitted when client needs to show a verification uri and user code
+ void showVerificationUriAndCode(const QUrl &uri, const QString &code, int expiresIn);
+
+ /// Emitted when the internal state changes
+ void activityChanged(Activity activity);
+
+public slots:
+ /// Handle verification response.
+ void onVerificationReceived(QMap<QString, QString>);
+
+protected slots:
+ /// Handle completion of a Device Authorization Request
+ void onDeviceAuthReplyFinished();
+
+ /// Handle completion of a refresh request.
+ void onRefreshFinished();
+
+ /// Handle failure of a refresh request.
+ void onRefreshError(QNetworkReply::NetworkError error, QNetworkReply *reply);
+
+protected:
+ /// Set refresh token.
+ void setRefreshToken(const QString &v);
+
+ /// Set token expiration time.
+ void setExpires(QDateTime v);
+
+ /// Start polling authorization server
+ void startPollServer(const QVariantMap &params, int expiresIn);
+
+ /// Set authentication token.
+ void setToken(const QString &v);
+
+ /// Set the linked state
+ void setLinked(bool v);
+
+ /// Set extra tokens found in OAuth response
+ void setExtraTokens(QVariantMap extraTokens);
+
+ /// Set local poll server
+ void setPollServer(PollServer *server);
+
+ PollServer * pollServer() const;
+
+ void updateActivity(Activity activity);
+
+protected:
+ Options options_;
+
+ QVariantMap extraReqParams_;
+ QNetworkAccessManager *manager_ = nullptr;
+ ReplyList timedReplies_;
+ QString grantType_;
+
+protected:
+ Token &token_;
+
+private:
+ PollServer *pollServer_ = nullptr;
+ Activity activity_ = Activity::Idle;
+};
+
+}
diff --git a/libraries/katabasis/include/katabasis/OAuth2.h b/libraries/katabasis/include/katabasis/OAuth2.h
deleted file mode 100644
index 9dbe5c71..00000000
--- a/libraries/katabasis/include/katabasis/OAuth2.h
+++ /dev/null
@@ -1,233 +0,0 @@
-#pragma once
-
-#include <QNetworkAccessManager>
-#include <QNetworkRequest>
-#include <QNetworkReply>
-#include <QPair>
-
-#include "Reply.h"
-#include "RequestParameter.h"
-#include "Bits.h"
-
-namespace Katabasis {
-
-class ReplyServer;
-class PollServer;
-
-
-/*
- * FIXME: this is not as simple as it should be. it squishes 4 different grant flows into one big ball of mud
- * This serves no practical purpose and simply makes the code less readable / maintainable.
- *
- * Therefore: Split this into the 4 different OAuth2 flows that people can use as authentication steps. Write tests/examples for all of them.
- */
-
-/// Simple OAuth2 authenticator.
-class OAuth2: public QObject
-{
- Q_OBJECT
-public:
- Q_ENUMS(GrantFlow)
-
-public:
-
- struct Options {
- QString userAgent = QStringLiteral("Katabasis/1.0");
- QString redirectionUrl = QStringLiteral("http://localhost:%1");
- QString responseType = QStringLiteral("code");
- QString scope;
- QString clientIdentifier;
- QString clientSecret;
- QUrl authorizationUrl;
- QUrl accessTokenUrl;
- QVector<quint16> listenerPorts = { 0 };
- };
-
- /// Authorization flow types.
- enum GrantFlow {
- GrantFlowAuthorizationCode, ///< @see http://tools.ietf.org/html/draft-ietf-oauth-v2-15#section-4.1
- GrantFlowImplicit, ///< @see http://tools.ietf.org/html/draft-ietf-oauth-v2-15#section-4.2
- GrantFlowResourceOwnerPasswordCredentials,
- GrantFlowDevice ///< @see https://tools.ietf.org/html/rfc8628#section-1
- };
-
- /// Authorization flow.
- GrantFlow grantFlow();
- void setGrantFlow(GrantFlow value);
-
-public:
- /// Are we authenticated?
- bool linked();
-
- /// Authentication token.
- QString token();
-
- /// Provider-specific extra tokens, available after a successful authentication
- QVariantMap extraTokens();
-
- /// Page content on local host after successful oauth.
- /// Provide it in case you do not want to close the browser, but display something
- QByteArray replyContent() const;
- void setReplyContent(const QByteArray &value);
-
-public:
-
- // TODO: remove
- /// Resource owner username.
- /// instances with the same (username, password) share the same "linked" and "token" properties.
- QString username();
- void setUsername(const QString &value);
-
- // TODO: remove
- /// Resource owner password.
- /// instances with the same (username, password) share the same "linked" and "token" properties.
- QString password();
- void setPassword(const QString &value);
-
- // TODO: remove
- /// API key.
- QString apiKey();
- void setApiKey(const QString &value);
-
- // TODO: remove
- /// Allow ignoring SSL errors?
- /// E.g. SurveyMonkey fails on Mac due to SSL error. Ignoring the error circumvents the problem
- bool ignoreSslErrors();
- void setIgnoreSslErrors(bool ignoreSslErrors);
-
- // TODO: put in `Options`
- /// User-defined extra parameters to append to request URL
- QVariantMap extraRequestParams();
- void setExtraRequestParams(const QVariantMap &value);
-
- // TODO: split up the class into multiple, each implementing one OAuth2 flow
- /// Grant type (if non-standard)
- QString grantType();
- void setGrantType(const QString &value);
-
-public:
- /// Constructor.
- /// @param parent Parent object.
- explicit OAuth2(Options & opts, Token & token, QObject *parent = 0, QNetworkAccessManager *manager = 0);
-
- /// Get refresh token.
- QString refreshToken();
-
- /// Get token expiration time
- QDateTime expires();
-
-public slots:
- /// Authenticate.
- virtual void link();
-
- /// De-authenticate.
- virtual void unlink();
-
- /// Refresh token.
- bool refresh();
-
- /// Handle situation where reply server has opted to close its connection
- void serverHasClosed(bool paramsfound = false);
-
-signals:
- /// Emitted when a token refresh has been completed or failed.
- void refreshFinished(QNetworkReply::NetworkError error);
-
- /// Emitted when client needs to open a web browser window, with the given URL.
- void openBrowser(const QUrl &url);
-
- /// Emitted when client can close the browser window.
- void closeBrowser();
-
- /// Emitted when client needs to show a verification uri and user code
- void showVerificationUriAndCode(const QUrl &uri, const QString &code, int expiresIn);
-
- /// Emitted when authentication/deauthentication succeeded.
- void linkingSucceeded();
-
- /// Emitted when authentication/deauthentication failed.
- void linkingFailed();
-
- void activityChanged(Activity activity);
-
-public slots:
- /// Handle verification response.
- virtual void onVerificationReceived(QMap<QString, QString>);
-
-protected slots:
- /// Handle completion of a token request.
- virtual void onTokenReplyFinished();
-
- /// Handle failure of a token request.
- virtual void onTokenReplyError(QNetworkReply::NetworkError error);
-
- /// Handle completion of a refresh request.
- virtual void onRefreshFinished();
-
- /// Handle failure of a refresh request.
- virtual void onRefreshError(QNetworkReply::NetworkError error);
-
- /// Handle completion of a Device Authorization Request
- virtual void onDeviceAuthReplyFinished();
-
-protected:
- /// Build HTTP request body.
- QByteArray buildRequestBody(const QMap<QString, QString> &parameters);
-
- /// Set refresh token.
- void setRefreshToken(const QString &v);
-
- /// Set token expiration time.
- void setExpires(QDateTime v);
-
- /// Start polling authorization server
- void startPollServer(const QVariantMap &params, int expiresIn);
-
- /// Set authentication token.
- void setToken(const QString &v);
-
- /// Set the linked state
- void setLinked(bool v);
-
- /// Set extra tokens found in OAuth response
- void setExtraTokens(QVariantMap extraTokens);
-
- /// Set local reply server
- void setReplyServer(ReplyServer *server);
-
- ReplyServer * replyServer() const;
-
- /// Set local poll server
- void setPollServer(PollServer *server);
-
- PollServer * pollServer() const;
-
- void updateActivity(Activity activity);
-
-protected:
- QString username_;
- QString password_;
-
- Options options_;
-
- QVariantMap extraReqParams_;
- QString apiKey_;
- QNetworkAccessManager *manager_ = nullptr;
- ReplyList timedReplies_;
- GrantFlow grantFlow_;
- QString grantType_;
-
-protected:
- QString redirectUri_;
- Token &token_;
-
- // this should be part of the reply server impl
- QByteArray replyContent_;
-
-private:
- ReplyServer *replyServer_ = nullptr;
- PollServer *pollServer_ = nullptr;
- Activity activity_ = Activity::Idle;
-};
-
-}
diff --git a/libraries/katabasis/include/katabasis/Reply.h b/libraries/katabasis/include/katabasis/Reply.h
index 3af1d49f..415cf4ec 100644
--- a/libraries/katabasis/include/katabasis/Reply.h
+++ b/libraries/katabasis/include/katabasis/Reply.h
@@ -9,12 +9,14 @@
namespace Katabasis {
+constexpr int defaultTimeout = 30 * 1000;
+
/// A network request/reply pair that can time out.
class Reply: public QTimer {
Q_OBJECT
public:
- Reply(QNetworkReply *reply, int timeOut = 60 * 1000, QObject *parent = 0);
+ Reply(QNetworkReply *reply, int timeOut = defaultTimeout, QObject *parent = 0);
signals:
void error(QNetworkReply::NetworkError);
@@ -25,6 +27,7 @@ public slots:
public:
QNetworkReply *reply;
+ bool timedOut = false;
};
/// List of O2Replies.
@@ -37,7 +40,7 @@ public:
virtual ~ReplyList();
/// Create a new O2Reply from a QNetworkReply, and add it to this list.
- void add(QNetworkReply *reply);
+ void add(QNetworkReply *reply, int timeOut = defaultTimeout);
/// Add an O2Reply to the list, while taking ownership of it.
void add(Reply *reply);
diff --git a/libraries/katabasis/include/katabasis/ReplyServer.h b/libraries/katabasis/include/katabasis/ReplyServer.h
deleted file mode 100644
index bf47df69..00000000
--- a/libraries/katabasis/include/katabasis/ReplyServer.h
+++ /dev/null
@@ -1,53 +0,0 @@
-#pragma once
-
-#include <QTcpServer>
-#include <QMap>
-#include <QByteArray>
-#include <QString>
-
-namespace Katabasis {
-
-/// HTTP server to process authentication response.
-class ReplyServer: public QTcpServer {
- Q_OBJECT
-
-public:
- explicit ReplyServer(QObject *parent = 0);
-
- /// Page content on local host after successful oauth - in case you do not want to close the browser, but display something
- Q_PROPERTY(QByteArray replyContent READ replyContent WRITE setReplyContent)
- QByteArray replyContent();
- void setReplyContent(const QByteArray &value);
-
- /// Seconds to keep listening *after* first response for a callback with token content
- Q_PROPERTY(int timeout READ timeout WRITE setTimeout)
- int timeout();
- void setTimeout(int timeout);
-
- /// Maximum number of callback tries to accept, in case some don't have token content (favicons, etc.)
- Q_PROPERTY(int callbackTries READ callbackTries WRITE setCallbackTries)
- int callbackTries();
- void setCallbackTries(int maxtries);
-
- QString uniqueState();
- void setUniqueState(const QString &state);
-
-signals:
- void verificationReceived(QMap<QString, QString>);
- void serverClosed(bool); // whether it has found parameters
-
-public slots:
- void onIncomingConnection();
- void onBytesReady();
- QMap<QString, QString> parseQueryParams(QByteArray *data);
- void closeServer(QTcpSocket *socket = 0, bool hasparameters = false);
-
-protected:
- QByteArray replyContent_;
- int timeout_;
- int maxtries_;
- int tries_;
- QString uniqueState_;
-};
-
-}
diff --git a/libraries/katabasis/src/DeviceFlow.cpp b/libraries/katabasis/src/DeviceFlow.cpp
new file mode 100644
index 00000000..ba1d121d
--- /dev/null
+++ b/libraries/katabasis/src/DeviceFlow.cpp
@@ -0,0 +1,451 @@
+#include <QList>
+#include <QPair>
+#include <QDebug>
+#include <QTcpServer>
+#include <QMap>
+#include <QNetworkRequest>
+#include <QNetworkReply>
+#include <QNetworkAccessManager>
+#include <QDateTime>
+#include <QCryptographicHash>
+#include <QTimer>
+#include <QVariantMap>
+#include <QUuid>
+#include <QDataStream>
+
+#include <QUrlQuery>
+
+#include "katabasis/DeviceFlow.h"
+#include "katabasis/PollServer.h"
+#include "katabasis/Globals.h"
+
+#include "JsonResponse.h"
+
+namespace {
+// ref: https://tools.ietf.org/html/rfc8628#section-3.2
+// Exception: Google sign-in uses "verification_url" instead of "*_uri" - we'll accept both.
+bool hasMandatoryDeviceAuthParams(const QVariantMap& params)
+{
+ if (!params.contains(Katabasis::OAUTH2_DEVICE_CODE))
+ return false;
+
+ if (!params.contains(Katabasis::OAUTH2_USER_CODE))
+ return false;
+
+ if (!(params.contains(Katabasis::OAUTH2_VERIFICATION_URI) || params.contains(Katabasis::OAUTH2_VERIFICATION_URL)))
+ return false;
+
+ if (!params.contains(Katabasis::OAUTH2_EXPIRES_IN))
+ return false;
+
+ return true;
+}
+
+QByteArray createQueryParameters(const QList<Katabasis::RequestParameter> &parameters) {
+ QByteArray ret;
+ bool first = true;
+ for( auto & h: parameters) {
+ if (first) {
+ first = false;
+ } else {
+ ret.append("&");
+ }
+ ret.append(QUrl::toPercentEncoding(h.name) + "=" + QUrl::toPercentEncoding(h.value));
+ }
+ return ret;
+}
+}
+
+namespace Katabasis {
+
+DeviceFlow::DeviceFlow(Options & opts, Token & token, QObject *parent, QNetworkAccessManager *manager) : QObject(parent), token_(token) {
+ manager_ = manager ? manager : new QNetworkAccessManager(this);
+ qRegisterMetaType<QNetworkReply::NetworkError>("QNetworkReply::NetworkError");
+ options_ = opts;
+}
+
+bool DeviceFlow::linked() {
+ return token_.validity != Validity::None;
+}
+void DeviceFlow::setLinked(bool v) {
+ qDebug() << "DeviceFlow::setLinked:" << (v? "true": "false");
+ token_.validity = v ? Validity::Certain : Validity::None;
+}
+
+void DeviceFlow::updateActivity(Activity activity)
+{
+ if(activity_ == activity) {
+ return;
+ }
+
+ activity_ = activity;
+ switch(activity) {
+ case Katabasis::Activity::Idle:
+ case Katabasis::Activity::LoggingIn:
+ case Katabasis::Activity::LoggingOut:
+ case Katabasis::Activity::Refreshing:
+ // non-terminal states...
+ break;
+ case Katabasis::Activity::FailedSoft:
+ // terminal state, tokens did not change
+ break;
+ case Katabasis::Activity::FailedHard:
+ case Katabasis::Activity::FailedGone:
+ // terminal state, tokens are invalid
+ token_ = Token();
+ break;
+ case Katabasis::Activity::Succeeded:
+ setLinked(true);
+ break;
+ }
+ emit activityChanged(activity_);
+}
+
+QString DeviceFlow::token() {
+ return token_.token;
+}
+void DeviceFlow::setToken(const QString &v) {
+ token_.token = v;
+}
+
+QVariantMap DeviceFlow::extraTokens() {
+ return token_.extra;
+}
+
+void DeviceFlow::setExtraTokens(QVariantMap extraTokens) {
+ token_.extra = extraTokens;
+}
+
+void DeviceFlow::setPollServer(PollServer *server)
+{
+ if (pollServer_)
+ pollServer_->deleteLater();
+
+ pollServer_ = server;
+}
+
+PollServer *DeviceFlow::pollServer() const
+{
+ return pollServer_;
+}
+
+QVariantMap DeviceFlow::extraRequestParams()
+{
+ return extraReqParams_;
+}
+
+void DeviceFlow::setExtraRequestParams(const QVariantMap &value)
+{
+ extraReqParams_ = value;
+}
+
+QString DeviceFlow::grantType()
+{
+ if (!grantType_.isEmpty())
+ return grantType_;
+
+ return OAUTH2_GRANT_TYPE_DEVICE;
+}
+
+void DeviceFlow::setGrantType(const QString &value)
+{
+ grantType_ = value;
+}
+
+// First get the URL and token to display to the user
+void DeviceFlow::login() {
+ qDebug() << "DeviceFlow::link";
+
+ updateActivity(Activity::LoggingIn);
+ setLinked(false);
+ setToken("");
+ setExtraTokens(QVariantMap());
+ setRefreshToken(QString());
+ setExpires(QDateTime());
+
+ QList<RequestParameter> parameters;
+ parameters.append(RequestParameter(OAUTH2_CLIENT_ID, options_.clientIdentifier.toUtf8()));
+ parameters.append(RequestParameter(OAUTH2_SCOPE, options_.scope.toUtf8()));
+ QByteArray payload = createQueryParameters(parameters);
+
+ QUrl url(options_.authorizationUrl);
+ QNetworkRequest deviceRequest(url);
+ deviceRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
+ QNetworkReply *tokenReply = manager_->post(deviceRequest, payload);
+
+ connect(tokenReply, &QNetworkReply::finished, this, &DeviceFlow::onDeviceAuthReplyFinished, Qt::QueuedConnection);
+}
+
+// Then, once we get them, present them to the user
+void DeviceFlow::onDeviceAuthReplyFinished()
+{
+ qDebug() << "DeviceFlow::onDeviceAuthReplyFinished";
+ QNetworkReply *tokenReply = qobject_cast<QNetworkReply *>(sender());
+ if (!tokenReply)
+ {
+ qDebug() << "DeviceFlow::onDeviceAuthReplyFinished: reply is null";
+ return;
+ }
+ if (tokenReply->error() == QNetworkReply::NoError) {
+ QByteArray replyData = tokenReply->readAll();
+
+ // Dump replyData
+ // SENSITIVE DATA in RelWithDebInfo or Debug builds
+ //qDebug() << "DeviceFlow::onDeviceAuthReplyFinished: replyData\n";
+ //qDebug() << QString( replyData );
+
+ QVariantMap params = parseJsonResponse(replyData);
+
+ // Dump tokens
+ qDebug() << "DeviceFlow::onDeviceAuthReplyFinished: Tokens returned:\n";
+ foreach (QString key, params.keys()) {
+ // SENSITIVE DATA in RelWithDebInfo or Debug builds, so it is truncated first
+ qDebug() << key << ": "<< params.value( key ).toString();
+ }
+
+ // Check for mandatory parameters
+ if (hasMandatoryDeviceAuthParams(params)) {
+ qDebug() << "DeviceFlow::onDeviceAuthReplyFinished: Device auth request response";
+
+ const QString userCode = params.take(OAUTH2_USER_CODE).toString();
+ QUrl uri = params.take(OAUTH2_VERIFICATION_URI).toUrl();
+ if (uri.isEmpty())
+ uri = params.take(OAUTH2_VERIFICATION_URL).toUrl();
+
+ if (params.contains(OAUTH2_VERIFICATION_URI_COMPLETE))
+ emit openBrowser(params.take(OAUTH2_VERIFICATION_URI_COMPLETE).toUrl());
+
+ bool ok = false;
+ int expiresIn = params[OAUTH2_EXPIRES_IN].toInt(&ok);
+ if (!ok) {
+ qWarning() << "DeviceFlow::startPollServer: No expired_in parameter";
+ updateActivity(Activity::FailedHard);
+ return;
+ }
+
+ emit showVerificationUriAndCode(uri, userCode, expiresIn);
+
+ startPollServer(params, expiresIn);
+ } else {
+ qWarning() << "DeviceFlow::onDeviceAuthReplyFinished: Mandatory parameters missing from response";
+ updateActivity(Activity::FailedHard);
+ }
+ }
+ tokenReply->deleteLater();
+}
+
+// Spin up polling for the user completing the login flow out of band
+void DeviceFlow::startPollServer(const QVariantMap &params, int expiresIn)
+{
+ qDebug() << "DeviceFlow::startPollServer: device_ and user_code expires in" << expiresIn << "seconds";
+
+ QUrl url(options_.accessTokenUrl);
+ QNetworkRequest authRequest(url);
+ authRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
+
+ const QString deviceCode = params[OAUTH2_DEVICE_CODE].toString();
+ const QString grantType = grantType_.isEmpty() ? OAUTH2_GRANT_TYPE_DEVICE : grantType_;
+
+ QList<RequestParameter> parameters;
+ parameters.append(RequestParameter(OAUTH2_CLIENT_ID, options_.clientIdentifier.toUtf8()));
+ if ( !options_.clientSecret.isEmpty() ) {
+ parameters.append(RequestParameter(OAUTH2_CLIENT_SECRET, options_.clientSecret.toUtf8()));
+ }
+ parameters.append(RequestParameter(OAUTH2_CODE, deviceCode.toUtf8()));
+ parameters.append(RequestParameter(OAUTH2_GRANT_TYPE, grantType.toUtf8()));
+ QByteArray payload = createQueryParameters(parameters);
+
+ PollServer * pollServer = new PollServer(manager_, authRequest, payload, expiresIn, this);
+ if (params.contains(OAUTH2_INTERVAL)) {
+ bool ok = false;
+ int interval = params[OAUTH2_INTERVAL].toInt(&ok);
+ if (ok) {
+ pollServer->setInterval(interval);
+ }
+ }
+ connect(pollServer, &PollServer::verificationReceived, this, &DeviceFlow::onVerificationReceived);
+ connect(pollServer, &PollServer::serverClosed, this, &DeviceFlow::serverHasClosed);
+ setPollServer(pollServer);
+ pollServer->startPolling();
+}
+
+// Once the user completes the flow, update the internal state and report it to observers
+void DeviceFlow::onVerificationReceived(const QMap<QString, QString> response) {
+ qDebug() << "DeviceFlow::onVerificationReceived: Emitting closeBrowser()";
+ emit closeBrowser();
+
+ if (response.contains("error")) {
+ qWarning() << "DeviceFlow::onVerificationReceived: Verification failed:" << response;
+ updateActivity(Activity::FailedHard);
+ return;
+ }
+
+ // Check for mandatory tokens
+ if (response.contains(OAUTH2_ACCESS_TOKEN)) {
+ qDebug() << "DeviceFlow::onVerificationReceived: Access token returned for implicit or device flow";
+ setToken(response.value(OAUTH2_ACCESS_TOKEN));
+ if (response.contains(OAUTH2_EXPIRES_IN)) {
+ bool ok = false;
+ int expiresIn = response.value(OAUTH2_EXPIRES_IN).toInt(&ok);
+ if (ok) {
+ qDebug() << "DeviceFlow::onVerificationReceived: Token expires in" << expiresIn << "seconds";
+ setExpires(QDateTime::currentDateTimeUtc().addSecs(expiresIn));
+ }
+ }
+ if (response.contains(OAUTH2_REFRESH_TOKEN)) {
+ setRefreshToken(response.value(OAUTH2_REFRESH_TOKEN));
+ }
+ updateActivity(Activity::Succeeded);
+ } else {
+ qWarning() << "DeviceFlow::onVerificationReceived: Access token missing from response for implicit or device flow";
+ updateActivity(Activity::FailedHard);
+ }
+}
+
+// Or if the flow fails or the polling times out, update the internal state with error and report it to observers
+void DeviceFlow::serverHasClosed(bool paramsfound)
+{
+ if ( !paramsfound ) {
+ // server has probably timed out after receiving first response
+ updateActivity(Activity::FailedHard);
+ }
+ // poll server is not re-used for later auth requests
+ setPollServer(NULL);
+}
+
+void DeviceFlow::logout() {
+ qDebug() << "DeviceFlow::unlink";
+ updateActivity(Activity::LoggingOut);
+ // FIXME: implement logout flows... if they exist
+ token_ = Token();
+ updateActivity(Activity::FailedHard);
+}
+
+QDateTime DeviceFlow::expires() {
+ return token_.notAfter;
+}
+void DeviceFlow::setExpires(QDateTime v) {
+ token_.notAfter = v;
+}
+
+QString DeviceFlow::refreshToken() {
+ return token_.refresh_token;
+}
+
+void DeviceFlow::setRefreshToken(const QString &v) {
+#ifndef NDEBUG
+ qDebug() << "DeviceFlow::setRefreshToken" << v << "...";
+#endif
+ token_.refresh_token = v;
+}
+
+namespace {
+QByteArray buildRequestBody(const QMap<QString, QString> &parameters) {
+ QByteArray body;
+ bool first = true;
+ foreach (QString key, parameters.keys()) {
+ if (first) {
+ first = false;
+ } else {
+ body.append("&");
+ }
+ QString value = parameters.value(key);
+ body.append(QUrl::toPercentEncoding(key) + QString("=").toUtf8() + QUrl::toPercentEncoding(value));
+ }
+ return body;
+}
+}
+
+bool DeviceFlow::refresh() {
+ qDebug() << "DeviceFlow::refresh: Token: ..." << refreshToken().right(7);
+
+ updateActivity(Activity::Refreshing);
+
+ if (refreshToken().isEmpty()) {
+ qWarning() << "DeviceFlow::refresh: No refresh token";
+ onRefreshError(QNetworkReply::AuthenticationRequiredError, nullptr);
+ return false;
+ }
+ if (options_.accessTokenUrl.isEmpty()) {
+ qWarning() << "DeviceFlow::refresh: Refresh token URL not set";
+ onRefreshError(QNetworkReply::AuthenticationRequiredError, nullptr);
+ return false;
+ }
+
+ QNetworkRequest refreshRequest(options_.accessTokenUrl);
+ refreshRequest.setHeader(QNetworkRequest::ContentTypeHeader, MIME_TYPE_XFORM);
+ QMap<QString, QString> parameters;
+ parameters.insert(OAUTH2_CLIENT_ID, options_.clientIdentifier);
+ if ( !options_.clientSecret.isEmpty() ) {
+ parameters.insert(OAUTH2_CLIENT_SECRET, options_.clientSecret);
+ }
+ parameters.insert(OAUTH2_REFRESH_TOKEN, refreshToken());
+ parameters.insert(OAUTH2_GRANT_TYPE, OAUTH2_REFRESH_TOKEN);
+
+ QByteArray data = buildRequestBody(parameters);
+ QNetworkReply *refreshReply = manager_->post(refreshRequest, data);
+ timedReplies_.add(refreshReply);
+ connect(refreshReply, &QNetworkReply::finished, this, &DeviceFlow::onRefreshFinished, Qt::QueuedConnection);
+ return true;
+}
+
+void DeviceFlow::onRefreshFinished() {
+ QNetworkReply *refreshReply = qobject_cast<QNetworkReply *>(sender());
+
+ auto networkError = refreshReply->error();
+ if (networkError == QNetworkReply::NoError) {
+ QByteArray reply = refreshReply->readAll();
+ QVariantMap tokens = parseJsonResponse(reply);
+ setToken(tokens.value(OAUTH2_ACCESS_TOKEN).toString());
+ setExpires(QDateTime::currentDateTimeUtc().addSecs(tokens.value(OAUTH2_EXPIRES_IN).toInt()));
+ QString refreshToken = tokens.value(OAUTH2_REFRESH_TOKEN).toString();
+ if(!refreshToken.isEmpty()) {
+ setRefreshToken(refreshToken);
+ }
+ else {
+ qDebug() << "No new refresh token. Keep the old one.";
+ }
+ timedReplies_.remove(refreshReply);
+ refreshReply->deleteLater();
+ updateActivity(Activity::Succeeded);
+ qDebug() << "New token expires in" << expires() << "seconds";
+ } else {
+ // FIXME: differentiate the error more here
+ onRefreshError(networkError, refreshReply);
+ }
+}
+
+void DeviceFlow::onRefreshError(QNetworkReply::NetworkError error, QNetworkReply *refreshReply) {
+ QString errorString = "No Reply";
+ if(refreshReply) {
+ timedReplies_.remove(refreshReply);
+ errorString = refreshReply->errorString();
+ }
+
+ switch (error)
+ {
+ // used for invalid credentials and similar errors. Fall through.
+ case QNetworkReply::AuthenticationRequiredError:
+ case QNetworkReply::ContentAccessDenied:
+ case QNetworkReply::ContentOperationNotPermittedError:
+ case QNetworkReply::ProtocolInvalidOperationError:
+ updateActivity(Activity::FailedHard);
+ break;
+ case QNetworkReply::ContentGoneError: {
+ updateActivity(Activity::FailedGone);
+ break;
+ }
+ case QNetworkReply::TimeoutError:
+ case QNetworkReply::OperationCanceledError:
+ case QNetworkReply::SslHandshakeFailedError:
+ default:
+ updateActivity(Activity::FailedSoft);
+ return;
+ }
+ if(refreshReply) {
+ refreshReply->deleteLater();
+ }
+ qDebug() << "DeviceFlow::onRefreshFinished: Error" << (int)error << " - " << errorString;
+}
+
+}
diff --git a/libraries/katabasis/src/OAuth2.cpp b/libraries/katabasis/src/OAuth2.cpp
deleted file mode 100644
index 260aa9c1..00000000
--- a/libraries/katabasis/src/OAuth2.cpp
+++ /dev/null
@@ -1,672 +0,0 @@
-#include <QList>
-#include <QPair>
-#include <QDebug>
-#include <QTcpServer>
-#include <QMap>
-#include <QNetworkRequest>
-#include <QNetworkReply>
-#include <QNetworkAccessManager>
-#include <QDateTime>
-#include <QCryptographicHash>
-#include <QTimer>
-#include <QVariantMap>
-#include <QUuid>
-#include <QDataStream>
-
-#include <QUrlQuery>
-
-#include "katabasis/OAuth2.h"
-#include "katabasis/PollServer.h"
-#include "katabasis/ReplyServer.h"
-#include "katabasis/Globals.h"
-
-#include "JsonResponse.h"
-
-namespace {
-// ref: https://tools.ietf.org/html/rfc8628#section-3.2
-// Exception: Google sign-in uses "verification_url" instead of "*_uri" - we'll accept both.
-bool hasMandatoryDeviceAuthParams(const QVariantMap& params)
-{
- if (!params.contains(Katabasis::OAUTH2_DEVICE_CODE))
- return false;
-
- if (!params.contains(Katabasis::OAUTH2_USER_CODE))
- return false;
-
- if (!(params.contains(Katabasis::OAUTH2_VERIFICATION_URI) || params.contains(Katabasis::OAUTH2_VERIFICATION_URL)))
- return false;
-
- if (!params.contains(Katabasis::OAUTH2_EXPIRES_IN))
- return false;
-
- return true;
-}
-
-QByteArray createQueryParameters(const QList<Katabasis::RequestParameter> &parameters) {
- QByteArray ret;
- bool first = true;
- for( auto & h: parameters) {
- if (first) {
- first = false;
- } else {
- ret.append("&");
- }
- ret.append(QUrl::toPercentEncoding(h.name) + "=" + QUrl::toPercentEncoding(h.value));
- }
- return ret;
-}
-}
-
-namespace Katabasis {
-
-OAuth2::OAuth2(Options & opts, Token & token, QObject *parent, QNetworkAccessManager *manager) : QObject(parent), token_(token) {
- manager_ = manager ? manager : new QNetworkAccessManager(this);
- grantFlow_ = GrantFlowAuthorizationCode;
- qRegisterMetaType<QNetworkReply::NetworkError>("QNetworkReply::NetworkError");
- options_ = opts;
-}
-
-bool OAuth2::linked() {
- return token_.validity != Validity::None;
-}
-void OAuth2::setLinked(bool v) {
- qDebug() << "OAuth2::setLinked:" << (v? "true": "false");
- token_.validity = v ? Validity::Certain : Validity::None;
-}
-
-QString OAuth2::token() {
- return token_.token;
-}
-void OAuth2::setToken(const QString &v) {
- token_.token = v;
-}
-
-QByteArray OAuth2::replyContent() const {
- return replyContent_;
-}
-
-void OAuth2::setReplyContent(const QByteArray &value) {
- replyContent_ = value;
- if (replyServer_) {
- replyServer_->setReplyContent(replyContent_);
- }
-}
-
-QVariantMap OAuth2::extraTokens() {
- return token_.extra;
-}
-
-void OAuth2::setExtraTokens(QVariantMap extraTokens) {
- token_.extra = extraTokens;
-}
-
-void OAuth2::setReplyServer(ReplyServer * server)
-{
- delete replyServer_;
-
- replyServer_ = server;
- replyServer_->setReplyContent(replyContent_);
-}
-
-ReplyServer * OAuth2::replyServer() const
-{
- return replyServer_;
-}
-
-void OAuth2::setPollServer(PollServer *server)
-{
- if (pollServer_)
- pollServer_->deleteLater();
-
- pollServer_ = server;
-}
-
-PollServer *OAuth2::pollServer() const
-{
- return pollServer_;
-}
-
-OAuth2::GrantFlow OAuth2::grantFlow() {
- return grantFlow_;
-}
-
-void OAuth2::setGrantFlow(OAuth2::GrantFlow value) {
- grantFlow_ = value;
-}
-
-QString OAuth2::username() {
- return username_;
-}
-
-void OAuth2::setUsername(const QString &value) {
- username_ = value;
-}
-
-QString OAuth2::password() {
- return password_;
-}
-
-void OAuth2::setPassword(const QString &value) {
- password_ = value;
-}
-
-QVariantMap OAuth2::extraRequestParams()
-{
- return extraReqParams_;
-}
-
-void OAuth2::setExtraRequestParams(const QVariantMap &value)
-{
- extraReqParams_ = value;
-}
-
-QString OAuth2::grantType()
-{
- if (!grantType_.isEmpty())
- return grantType_;
-
- switch (grantFlow_) {
- case GrantFlowAuthorizationCode:
- return OAUTH2_GRANT_TYPE_CODE;
- case GrantFlowImplicit:
- return OAUTH2_GRANT_TYPE_TOKEN;
- case GrantFlowResourceOwnerPasswordCredentials:
- return OAUTH2_GRANT_TYPE_PASSWORD;
- case GrantFlowDevice:
- return OAUTH2_GRANT_TYPE_DEVICE;
- }
-
- return QString();
-}
-
-void OAuth2::setGrantType(const QString &value)
-{
- grantType_ = value;
-}
-
-void OAuth2::updateActivity(Activity activity)
-{
- if(activity_ != activity) {
- activity_ = activity;
- emit activityChanged(activity_);
- }
-}
-
-void OAuth2::link() {
- qDebug() << "OAuth2::link";
-
- // Create the reply server if it doesn't exist
- if(replyServer() == NULL) {
- ReplyServer * replyServer = new ReplyServer(this);
- connect(replyServer, &ReplyServer::verificationReceived, this, &OAuth2::onVerificationReceived);
- connect(replyServer, &ReplyServer::serverClosed, this, &OAuth2::serverHasClosed);
- setReplyServer(replyServer);
- }
-
- if (linked()) {
- qDebug() << "OAuth2::link: Linked already";
- emit linkingSucceeded();
- return;
- }
-
- setLinked(false);
- setToken("");
- setExtraTokens(QVariantMap());
- setRefreshToken(QString());
- setExpires(QDateTime());
-
- if (grantFlow_ == GrantFlowAuthorizationCode || grantFlow_ == GrantFlowImplicit) {
-
- QString uniqueState = QUuid::createUuid().toString().remove(QRegExp("([^a-zA-Z0-9]|[-])"));
-
- // FIXME: this should be part of a 'redirection handler' that would get injected into O2
- {
- quint16 foundPort = 0;
- // Start listening to authentication replies
- if (!replyServer()->isListening()) {
- auto ports = options_.listenerPorts;
- for(auto & port: ports) {
- if (replyServer()->listen(QHostAddress::Any, port)) {
- foundPort = replyServer()->serverPort();
- qDebug() << "OAuth2::link: Reply server listening on port " << foundPort;
- break;
- }
- }
- if(foundPort == 0) {
- qWarning() << "OAuth2::link: Reply server failed to start listening on any port out of " << ports;
- emit linkingFailed();
- return;
- }
- }
-
- // Save redirect URI, as we have to reuse it when requesting the access token
- redirectUri_ = options_.redirectionUrl.arg(foundPort);
- replyServer()->setUniqueState(uniqueState);
- }
-
- // Assemble intial authentication URL
- QUrl url(options_.authorizationUrl);
- QUrlQuery query(url);
- QList<QPair<QString, QString> > parameters;
- query.addQueryItem(OAUTH2_RESPONSE_TYPE, (grantFlow_ == GrantFlowAuthorizationCode)? OAUTH2_GRANT_TYPE_CODE: OAUTH2_GRANT_TYPE_TOKEN);
- query.addQueryItem(OAUTH2_CLIENT_ID, options_.clientIdentifier);
- query.addQueryItem(OAUTH2_REDIRECT_URI, redirectUri_);
- query.addQueryItem(OAUTH2_SCOPE, options_.scope.replace( " ", "+" ));
- query.addQueryItem(OAUTH2_STATE, uniqueState);
- if (!apiKey_.isEmpty()) {
- query.addQueryItem(OAUTH2_API_KEY, apiKey_);
- }
- for(auto iter = extraReqParams_.begin(); iter != extraReqParams_.end(); iter++) {
- query.addQueryItem(iter.key(), iter.value().toString());
- }
- url.setQuery(query);
-
- // Show authentication URL with a web browser
- qDebug() << "OAuth2::link: Emit openBrowser" << url.toString();
- emit openBrowser(url);
- updateActivity(Activity::LoggingIn);
- } else if (grantFlow_ == GrantFlowResourceOwnerPasswordCredentials) {
- QList<RequestParameter> parameters;
- parameters.append(RequestParameter(OAUTH2_CLIENT_ID, options_.clientIdentifier.toUtf8()));
- if ( !options_.clientSecret.isEmpty() ) {
- parameters.append(RequestParameter(OAUTH2_CLIENT_SECRET, options_.clientSecret.toUtf8()));
- }
- parameters.append(RequestParameter(OAUTH2_USERNAME, username_.toUtf8()));
- parameters.append(RequestParameter(OAUTH2_PASSWORD, password_.toUtf8()));
- parameters.append(RequestParameter(OAUTH2_GRANT_TYPE, OAUTH2_GRANT_TYPE_PASSWORD));
- parameters.append(RequestParameter(OAUTH2_SCOPE, options_.scope.toUtf8()));
- if ( !apiKey_.isEmpty() )
- parameters.append(RequestParameter(OAUTH2_API_KEY, apiKey_.toUtf8()));
- foreach (QString key, extraRequestParams().keys()) {
- parameters.append(RequestParameter(key.toUtf8(), extraRequestParams().value(key).toByteArray()));
- }
- QByteArray payload = createQueryParameters(parameters);
-
- qDebug() << "OAuth2::link: Sending token request for resource owner flow";
- QUrl url(options_.accessTokenUrl);
- QNetworkRequest tokenRequest(url);
- tokenRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
- QNetworkReply *tokenReply = manager_->post(tokenRequest, payload);
-
- connect(tokenReply, SIGNAL(finished()), this, SLOT(onTokenReplyFinished()), Qt::QueuedConnection);
- connect(tokenReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onTokenReplyError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
- updateActivity(Activity::LoggingIn);
- }
- else if (grantFlow_ == GrantFlowDevice) {
- QList<RequestParameter> parameters;
- parameters.append(RequestParameter(OAUTH2_CLIENT_ID, options_.clientIdentifier.toUtf8()));
- parameters.append(RequestParameter(OAUTH2_SCOPE, options_.scope.toUtf8()));
- QByteArray payload = createQueryParameters(parameters);
-
- QUrl url(options_.authorizationUrl);
- QNetworkRequest deviceRequest(url);
- deviceRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
- QNetworkReply *tokenReply = manager_->post(deviceRequest, payload);
-
- connect(tokenReply, SIGNAL(finished()), this, SLOT(onDeviceAuthReplyFinished()), Qt::QueuedConnection);
- connect(tokenReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onTokenReplyError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
- updateActivity(Activity::LoggingIn);
- }
-}
-
-void OAuth2::unlink() {
- qDebug() << "OAuth2::unlink";
- updateActivity(Activity::LoggingOut);
- // FIXME: implement logout flows... if they exist
- token_ = Token();
- updateActivity(Activity::Idle);
-}
-
-void OAuth2::onVerificationReceived(const QMap<QString, QString> response) {
- qDebug() << "OAuth2::onVerificationReceived: Emitting closeBrowser()";
- emit closeBrowser();
-
- if (response.contains("error")) {
- qWarning() << "OAuth2::onVerificationReceived: Verification failed:" << response;
- emit linkingFailed();
- updateActivity(Activity::Idle);
- return;
- }
-
- if (grantFlow_ == GrantFlowAuthorizationCode) {
- // NOTE: access code is temporary and should never be saved anywhere!
- auto access_code = response.value(QString(OAUTH2_GRANT_TYPE_CODE));
-
- // Exchange access code for access/refresh tokens
- QString query;
- if(!apiKey_.isEmpty())
- query = QString("?" + QString(OAUTH2_API_KEY) + "=" + apiKey_);
- QNetworkRequest tokenRequest(QUrl(options_.accessTokenUrl.toString() + query));
- tokenRequest.setHeader(QNetworkRequest::ContentTypeHeader, MIME_TYPE_XFORM);
- tokenRequest.setRawHeader("Accept", MIME_TYPE_JSON);
- QMap<QString, QString> parameters;
- parameters.insert(OAUTH2_GRANT_TYPE_CODE, access_code);
- parameters.insert(OAUTH2_CLIENT_ID, options_.clientIdentifier);
- if ( !options_.clientSecret.isEmpty() ) {
- parameters.insert(OAUTH2_CLIENT_SECRET, options_.clientSecret);
- }
- parameters.insert(OAUTH2_REDIRECT_URI, redirectUri_);
- parameters.insert(OAUTH2_GRANT_TYPE, AUTHORIZATION_CODE);
- QByteArray data = buildRequestBody(parameters);
-
- qDebug() << QString("OAuth2::onVerificationReceived: Exchange access code data:\n%1").arg(QString(data));
-
- QNetworkReply *tokenReply = manager_->post(tokenRequest, data);
- timedReplies_.add(tokenReply);
- connect(tokenReply, SIGNAL(finished()), this, SLOT(onTokenReplyFinished()), Qt::QueuedConnection);
- connect(tokenReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onTokenReplyError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
- } else if (grantFlow_ == GrantFlowImplicit || grantFlow_ == GrantFlowDevice) {
- // Check for mandatory tokens
- if (response.contains(OAUTH2_ACCESS_TOKEN)) {
- qDebug() << "OAuth2::onVerificationReceived: Access token returned for implicit or device flow";
- setToken(response.value(OAUTH2_ACCESS_TOKEN));
- if (response.contains(OAUTH2_EXPIRES_IN)) {
- bool ok = false;
- int expiresIn = response.value(OAUTH2_EXPIRES_IN).toInt(&ok);
- if (ok) {
- qDebug() << "OAuth2::onVerificationReceived: Token expires in" << expiresIn << "seconds";
- setExpires(QDateTime::currentDateTimeUtc().addSecs(expiresIn));
- }
- }
- if (response.contains(OAUTH2_REFRESH_TOKEN)) {
- setRefreshToken(response.value(OAUTH2_REFRESH_TOKEN));
- }
- setLinked(true);
- emit linkingSucceeded();
- } else {
- qWarning() << "OAuth2::onVerificationReceived: Access token missing from response for implicit or device flow";
- emit linkingFailed();
- }
- updateActivity(Activity::Idle);
- } else {
- setToken(response.value(OAUTH2_ACCESS_TOKEN));
- setRefreshToken(response.value(OAUTH2_REFRESH_TOKEN));
- updateActivity(Activity::Idle);
- }
-}
-
-void OAuth2::onTokenReplyFinished() {
- qDebug() << "OAuth2::onTokenReplyFinished";
- QNetworkReply *tokenReply = qobject_cast<QNetworkReply *>(sender());
- if (!tokenReply)
- {
- qDebug() << "OAuth2::onTokenReplyFinished: reply is null";
- return;
- }
- if (tokenReply->error() == QNetworkReply::NoError) {
- QByteArray replyData = tokenReply->readAll();
-
- // Dump replyData
- // SENSITIVE DATA in RelWithDebInfo or Debug builds
- //qDebug() << "OAuth2::onTokenReplyFinished: replyData\n";
- //qDebug() << QString( replyData );
-
- QVariantMap tokens = parseJsonResponse(replyData);
-
- // Dump tokens
- qDebug() << "OAuth2::onTokenReplyFinished: Tokens returned:\n";
- foreach (QString key, tokens.keys()) {
- // SENSITIVE DATA in RelWithDebInfo or Debug builds, so it is truncated first
- qDebug() << key << ": "<< tokens.value( key ).toString();
- }
-
- // Check for mandatory tokens
- if (tokens.contains(OAUTH2_ACCESS_TOKEN)) {
- qDebug() << "OAuth2::onTokenReplyFinished: Access token returned";
- setToken(tokens.take(OAUTH2_ACCESS_TOKEN).toString());
- bool ok = false;
- int expiresIn = tokens.take(OAUTH2_EXPIRES_IN).toInt(&ok);
- if (ok) {
- qDebug() << "OAuth2::onTokenReplyFinished: Token expires in" << expiresIn << "seconds";
- setExpires(QDateTime::currentDateTimeUtc().addSecs(expiresIn));
- }
- setRefreshToken(tokens.take(OAUTH2_REFRESH_TOKEN).toString());
- setExtraTokens(tokens);
- timedReplies_.remove(tokenReply);
- setLinked(true);
- emit linkingSucceeded();
- } else {
- qWarning() << "OAuth2::onTokenReplyFinished: Access token missing from response";
- emit linkingFailed();
- }
- }
- tokenReply->deleteLater();
- updateActivity(Activity::Idle);
-}
-
-void OAuth2::onTokenReplyError(QNetworkReply::NetworkError error) {
- QNetworkReply *tokenReply = qobject_cast<QNetworkReply *>(sender());
- if (!tokenReply)
- {
- qDebug() << "OAuth2::onTokenReplyError: reply is null";
- } else {
- qWarning() << "OAuth2::onTokenReplyError: " << error << ": " << tokenReply->errorString();
- qDebug() << "OAuth2::onTokenReplyError: " << tokenReply->readAll();
- timedReplies_.remove(tokenReply);
- }
-
- setToken(QString());
- setRefreshToken(QString());
- emit linkingFailed();
-}
-
-QByteArray OAuth2::buildRequestBody(const QMap<QString, QString> &parameters) {
- QByteArray body;
- bool first = true;
- foreach (QString key, parameters.keys()) {
- if (first) {
- first = false;
- } else {
- body.append("&");
- }
- QString value = parameters.value(key);
- body.append(QUrl::toPercentEncoding(key) + QString("=").toUtf8() + QUrl::toPercentEncoding(value));
- }
- return body;
-}
-
-QDateTime OAuth2::expires() {
- return token_.notAfter;
-}
-void OAuth2::setExpires(QDateTime v) {
- token_.notAfter = v;
-}
-
-void OAuth2::startPollServer(const QVariantMap &params, int expiresIn)
-{
- qDebug() << "OAuth2::startPollServer: device_ and user_code expires in" << expiresIn << "seconds";
-
- QUrl url(options_.accessTokenUrl);
- QNetworkRequest authRequest(url);
- authRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
-
- const QString deviceCode = params[OAUTH2_DEVICE_CODE].toString();
- const QString grantType = grantType_.isEmpty() ? OAUTH2_GRANT_TYPE_DEVICE : grantType_;
-
- QList<RequestParameter> parameters;
- parameters.append(RequestParameter(OAUTH2_CLIENT_ID, options_.clientIdentifier.toUtf8()));
- if ( !options_.clientSecret.isEmpty() ) {
- parameters.append(RequestParameter(OAUTH2_CLIENT_SECRET, options_.clientSecret.toUtf8()));
- }
- parameters.append(RequestParameter(OAUTH2_CODE, deviceCode.toUtf8()));
- parameters.append(RequestParameter(OAUTH2_GRANT_TYPE, grantType.toUtf8()));
- QByteArray payload = createQueryParameters(parameters);
-
- PollServer * pollServer = new PollServer(manager_, authRequest, payload, expiresIn, this);
- if (params.contains(OAUTH2_INTERVAL)) {
- bool ok = false;
- int interval = params[OAUTH2_INTERVAL].toInt(&ok);
- if (ok)
- pollServer->setInterval(interval);
- }
- connect(pollServer, SIGNAL(verificationReceived(QMap<QString,QString>)), this, SLOT(onVerificationReceived(QMap<QString,QString>)));
- connect(pollServer, SIGNAL(serverClosed(bool)), this, SLOT(serverHasClosed(bool)));
- setPollServer(pollServer);
- pollServer->startPolling();
-}
-
-QString OAuth2::refreshToken() {
- return token_.refresh_token;
-}
-void OAuth2::setRefreshToken(const QString &v) {
-#ifndef NDEBUG
- qDebug() << "OAuth2::setRefreshToken" << v << "...";
-#endif
- token_.refresh_token = v;
-}
-
-bool OAuth2::refresh() {
- qDebug() << "OAuth2::refresh: Token: ..." << refreshToken().right(7);
-
- if (refreshToken().isEmpty()) {
- qWarning() << "OAuth2::refresh: No refresh token";
- onRefreshError(QNetworkReply::AuthenticationRequiredError);
- return false;
- }
- if (options_.accessTokenUrl.isEmpty()) {
- qWarning() << "OAuth2::refresh: Refresh token URL not set";
- onRefreshError(QNetworkReply::AuthenticationRequiredError);
- return false;
- }
-
- updateActivity(Activity::Refreshing);
-
- QNetworkRequest refreshRequest(options_.accessTokenUrl);
- refreshRequest.setHeader(QNetworkRequest::ContentTypeHeader, MIME_TYPE_XFORM);
- QMap<QString, QString> parameters;
- parameters.insert(OAUTH2_CLIENT_ID, options_.clientIdentifier);
- if ( !options_.clientSecret.isEmpty() ) {
- parameters.insert(OAUTH2_CLIENT_SECRET, options_.clientSecret);
- }
- parameters.insert(OAUTH2_REFRESH_TOKEN, refreshToken());
- parameters.insert(OAUTH2_GRANT_TYPE, OAUTH2_REFRESH_TOKEN);
-
- QByteArray data = buildRequestBody(parameters);
- QNetworkReply *refreshReply = manager_->post(refreshRequest, data);
- timedReplies_.add(refreshReply);
- connect(refreshReply, SIGNAL(finished()), this, SLOT(onRefreshFinished()), Qt::QueuedConnection);
- connect(refreshReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onRefreshError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
- return true;
-}
-
-void OAuth2::onRefreshFinished() {
- QNetworkReply *refreshReply = qobject_cast<QNetworkReply *>(sender());
-
- if (refreshReply->error() == QNetworkReply::NoError) {
- QByteArray reply = refreshReply->readAll();
- QVariantMap tokens = parseJsonResponse(reply);
- setToken(tokens.value(OAUTH2_ACCESS_TOKEN).toString());
- setExpires(QDateTime::currentDateTimeUtc().addSecs(tokens.value(OAUTH2_EXPIRES_IN).toInt()));
- QString refreshToken = tokens.value(OAUTH2_REFRESH_TOKEN).toString();
- if(!refreshToken.isEmpty()) {
- setRefreshToken(refreshToken);
- }
- else {
- qDebug() << "No new refresh token. Keep the old one.";
- }
- timedReplies_.remove(refreshReply);
- setLinked(true);
- emit linkingSucceeded();
- emit refreshFinished(QNetworkReply::NoError);
- qDebug() << "New token expires in" << expires() << "seconds";
- } else {
- emit linkingFailed();
- qDebug() << "OAuth2::onRefreshFinished: Error" << (int)refreshReply->error() << refreshReply->errorString();
- }
- refreshReply->deleteLater();
- updateActivity(Activity::Idle);
-}
-
-void OAuth2::onRefreshError(QNetworkReply::NetworkError error) {
- QNetworkReply *refreshReply = qobject_cast<QNetworkReply *>(sender());
- qWarning() << "OAuth2::onRefreshError: " << error;
- unlink();
- timedReplies_.remove(refreshReply);
- emit refreshFinished(error);
-}
-
-void OAuth2::onDeviceAuthReplyFinished()
-{
- qDebug() << "OAuth2::onDeviceAuthReplyFinished";
- QNetworkReply *tokenReply = qobject_cast<QNetworkReply *>(sender());
- if (!tokenReply)
- {
- qDebug() << "OAuth2::onDeviceAuthReplyFinished: reply is null";
- return;
- }
- if (tokenReply->error() == QNetworkReply::NoError) {
- QByteArray replyData = tokenReply->readAll();
-
- // Dump replyData
- // SENSITIVE DATA in RelWithDebInfo or Debug builds
- //qDebug() << "OAuth2::onDeviceAuthReplyFinished: replyData\n";
- //qDebug() << QString( replyData );
-
- QVariantMap params = parseJsonResponse(replyData);
-
- // Dump tokens
- qDebug() << "OAuth2::onDeviceAuthReplyFinished: Tokens returned:\n";
- foreach (QString key, params.keys()) {
- // SENSITIVE DATA in RelWithDebInfo or Debug builds, so it is truncated first
- qDebug() << key << ": "<< params.value( key ).toString();
- }
-
- // Check for mandatory parameters
- if (hasMandatoryDeviceAuthParams(params)) {
- qDebug() << "OAuth2::onDeviceAuthReplyFinished: Device auth request response";
-
- const QString userCode = params.take(OAUTH2_USER_CODE).toString();
- QUrl uri = params.take(OAUTH2_VERIFICATION_URI).toUrl();
- if (uri.isEmpty())
- uri = params.take(OAUTH2_VERIFICATION_URL).toUrl();
-
- if (params.contains(OAUTH2_VERIFICATION_URI_COMPLETE))
- emit openBrowser(params.take(OAUTH2_VERIFICATION_URI_COMPLETE).toUrl());
-
- bool ok = false;
- int expiresIn = params[OAUTH2_EXPIRES_IN].toInt(&ok);
- if (!ok) {
- qWarning() << "OAuth2::startPollServer: No expired_in parameter";
- emit linkingFailed();
- return;
- }
-
- emit showVerificationUriAndCode(uri, userCode, expiresIn);
-
- startPollServer(params, expiresIn);
- } else {
- qWarning() << "OAuth2::onDeviceAuthReplyFinished: Mandatory parameters missing from response";
- emit linkingFailed();
- updateActivity(Activity::Idle);
- }
- }
- tokenReply->deleteLater();
-}
-
-void OAuth2::serverHasClosed(bool paramsfound)
-{
- if ( !paramsfound ) {
- // server has probably timed out after receiving first response
- emit linkingFailed();
- }
- // poll server is not re-used for later auth requests
- setPollServer(NULL);
-}
-
-QString OAuth2::apiKey() {
- return apiKey_;
-}
-
-void OAuth2::setApiKey(const QString &value) {
- apiKey_ = value;
-}
-
-bool OAuth2::ignoreSslErrors() {
- return timedReplies_.ignoreSslErrors();
-}
-
-void OAuth2::setIgnoreSslErrors(bool ignoreSslErrors) {
- timedReplies_.setIgnoreSslErrors(ignoreSslErrors);
-}
-
-}
diff --git a/libraries/katabasis/src/Reply.cpp b/libraries/katabasis/src/Reply.cpp
index 775b9202..3e27a7e6 100644
--- a/libraries/katabasis/src/Reply.cpp
+++ b/libraries/katabasis/src/Reply.cpp
@@ -7,25 +7,28 @@ namespace Katabasis {
Reply::Reply(QNetworkReply *r, int timeOut, QObject *parent): QTimer(parent), reply(r) {
setSingleShot(true);
- connect(this, SIGNAL(error(QNetworkReply::NetworkError)), reply, SIGNAL(error(QNetworkReply::NetworkError)), Qt::QueuedConnection);
- connect(this, SIGNAL(timeout()), this, SLOT(onTimeOut()), Qt::QueuedConnection);
+ connect(this, &Reply::timeout, this, &Reply::onTimeOut, Qt::QueuedConnection);
start(timeOut);
}
void Reply::onTimeOut() {
- emit error(QNetworkReply::TimeoutError);
+ timedOut = true;
+ reply->abort();
}
+// ----------------------------
+
ReplyList::~ReplyList() {
foreach (Reply *timedReply, replies_) {
delete timedReply;
}
}
-void ReplyList::add(QNetworkReply *reply) {
- if (reply && ignoreSslErrors())
- reply->ignoreSslErrors();
- add(new Reply(reply));
+void ReplyList::add(QNetworkReply *reply, int timeOut) {
+ if (reply && ignoreSslErrors()) {
+ reply->ignoreSslErrors();
+ }
+ add(new Reply(reply, timeOut));
}
void ReplyList::add(Reply *reply) {
diff --git a/libraries/katabasis/src/ReplyServer.cpp b/libraries/katabasis/src/ReplyServer.cpp
deleted file mode 100755
index 4598b18a..00000000
--- a/libraries/katabasis/src/ReplyServer.cpp
+++ /dev/null
@@ -1,182 +0,0 @@
-#include <QTcpServer>
-#include <QTcpSocket>
-#include <QByteArray>
-#include <QString>
-#include <QMap>
-#include <QPair>
-#include <QTimer>
-#include <QStringList>
-#include <QUrl>
-#include <QDebug>
-#include <QUrlQuery>
-
-#include "katabasis/Globals.h"
-#include "katabasis/ReplyServer.h"
-
-namespace Katabasis {
-
-ReplyServer::ReplyServer(QObject *parent): QTcpServer(parent),
- timeout_(15), maxtries_(3), tries_(0) {
- qDebug() << "O2ReplyServer: Starting";
- connect(this, SIGNAL(newConnection()), this, SLOT(onIncomingConnection()));
- replyContent_ = "<HTML></HTML>";
-}
-
-void ReplyServer::onIncomingConnection() {
- qDebug() << "O2ReplyServer::onIncomingConnection: Receiving...";
- QTcpSocket *socket = nextPendingConnection();
- connect(socket, SIGNAL(readyRead()), this, SLOT(onBytesReady()), Qt::UniqueConnection);
- connect(socket, SIGNAL(disconnected()), socket, SLOT(deleteLater()));
-
- // Wait for a bit *after* first response, then close server if no useable data has arrived
- // Helps with implicit flow, where a URL fragment may need processed by local user-agent and
- // sent as secondary query string callback, or additional requests make it through first,
- // like for favicons, etc., before such secondary callbacks are fired
- QTimer *timer = new QTimer(socket);
- timer->setObjectName("timeoutTimer");
- connect(timer, SIGNAL(timeout()), this, SLOT(closeServer()));
- timer->setSingleShot(true);
- timer->setInterval(timeout() * 1000);
- connect(socket, SIGNAL(readyRead()), timer, SLOT(start()));
-}
-
-void ReplyServer::onBytesReady() {
- if (!isListening()) {
- // server has been closed, stop processing queued connections
- return;
- }
- qDebug() << "O2ReplyServer::onBytesReady: Processing request";
- // NOTE: on first call, the timeout timer is started
- QTcpSocket *socket = qobject_cast<QTcpSocket *>(sender());
- if (!socket) {
- qWarning() << "O2ReplyServer::onBytesReady: No socket available";
- return;
- }
- QByteArray reply;
- reply.append("HTTP/1.0 200 OK \r\n");
- reply.append("Content-Type: text/html; charset=\"utf-8\"\r\n");
- reply.append(QString("Content-Length: %1\r\n\r\n").arg(replyContent_.size()).toLatin1());
- reply.append(replyContent_);
- socket->write(reply);
- qDebug() << "O2ReplyServer::onBytesReady: Sent reply";
-
- QByteArray data = socket->readAll();
- QMap<QString, QString> queryParams = parseQueryParams(&data);
- if (queryParams.isEmpty()) {
- if (tries_ < maxtries_ ) {
- qDebug() << "O2ReplyServer::onBytesReady: No query params found, waiting for more callbacks";
- ++tries_;
- return;
- } else {
- tries_ = 0;
- qWarning() << "O2ReplyServer::onBytesReady: No query params found, maximum callbacks received";
- closeServer(socket, false);
- return;
- }
- }
- if (!uniqueState_.isEmpty() && !queryParams.contains(QString(OAUTH2_STATE))) {
- qDebug() << "O2ReplyServer::onBytesReady: Malicious or service request";
- closeServer(socket, true);
- return; // Malicious or service (e.g. favicon.ico) request
- }
- qDebug() << "O2ReplyServer::onBytesReady: Query params found, closing server";
- closeServer(socket, true);
- emit verificationReceived(queryParams);
-}
-
-QMap<QString, QString> ReplyServer::parseQueryParams(QByteArray *data) {
- qDebug() << "O2ReplyServer::parseQueryParams";
-
- //qDebug() << QString("O2ReplyServer::parseQueryParams data:\n%1").arg(QString(*data));
-
- QString splitGetLine = QString(*data).split("\r\n").first();
- splitGetLine.remove("GET ");
- splitGetLine.remove("HTTP/1.1");
- splitGetLine.remove("\r\n");
- splitGetLine.prepend("http://localhost");
- QUrl getTokenUrl(splitGetLine);
-
- QList< QPair<QString, QString> > tokens;
- QUrlQuery query(getTokenUrl);
- tokens = query.queryItems();
- QMap<QString, QString> queryParams;
- QPair<QString, QString> tokenPair;
- foreach (tokenPair, tokens) {
- // FIXME: We are decoding key and value again. This helps with Google OAuth, but is it mandated by the standard?
- QString key = QUrl::fromPercentEncoding(QByteArray().append(tokenPair.first.trimmed().toLatin1()));
- QString value = QUrl::fromPercentEncoding(QByteArray().append(tokenPair.second.trimmed().toLatin1()));
- queryParams.insert(key, value);
- }
- return queryParams;
-}
-
-void ReplyServer::closeServer(QTcpSocket *socket, bool hasparameters)
-{
- if (!isListening()) {
- return;
- }
-
- qDebug() << "O2ReplyServer::closeServer: Initiating";
- int port = serverPort();
-
- if (!socket && sender()) {
- QTimer *timer = qobject_cast<QTimer*>(sender());
- if (timer) {
- qWarning() << "O2ReplyServer::closeServer: Closing due to timeout";
- timer->stop();
- socket = qobject_cast<QTcpSocket *>(timer->parent());
- timer->deleteLater();
- }
- }
- if (socket) {
- QTimer *timer = socket->findChild<QTimer*>("timeoutTimer");
- if (timer) {
- qDebug() << "O2ReplyServer::closeServer: Stopping socket's timeout timer";
- timer->stop();
- }
- socket->disconnectFromHost();
- }
- close();
- qDebug() << "O2ReplyServer::closeServer: Closed, no longer listening on port" << port;
- emit serverClosed(hasparameters);
-}
-
-QByteArray ReplyServer::replyContent() {
- return replyContent_;
-}
-
-void ReplyServer::setReplyContent(const QByteArray &value) {
- replyContent_ = value;
-}
-
-int ReplyServer::timeout()
-{
- return timeout_;
-}
-
-void ReplyServer::setTimeout(int timeout)
-{
- timeout_ = timeout;
-}
-
-int ReplyServer::callbackTries()
-{
- return maxtries_;
-}
-
-void ReplyServer::setCallbackTries(int maxtries)
-{
- maxtries_ = maxtries;
-}
-
-QString ReplyServer::uniqueState()
-{
- return uniqueState_;
-}
-
-void ReplyServer::setUniqueState(const QString &state)
-{
- uniqueState_ = state;
-}
-
-}