diff --git a/apps/app-frontend/src/App.vue b/apps/app-frontend/src/App.vue index 5faea7c84a0..5232be18f3e 100644 --- a/apps/app-frontend/src/App.vue +++ b/apps/app-frontend/src/App.vue @@ -780,6 +780,20 @@ async function setupApp() { show_worlds_tab_in_instances, show_screenshots_tab_in_instances, show_skin_selector_in_sidebar, + refocus_on_game_close, + compact_instance_cards, + show_play_time, + warn_on_unknown_modpacks, + skip_non_essential_warnings, + show_jump_in, + always_show_copy_details, + hide_installed_modpacks, + advanced_filters_collapsed, + dismissed_photosensitivity_filter_warning, + friends_active_collapsed, + friends_online_collapsed, + friends_offline_collapsed, + friends_pending_collapsed, developer_mode, feature_flags, pending_update_toast_for_version, @@ -819,6 +833,20 @@ async function setupApp() { appSettings.showWorldsTabInInstances = show_worlds_tab_in_instances appSettings.showScreenshotsTabInInstances = show_screenshots_tab_in_instances appSettings.showSkinSelectorInSidebar = show_skin_selector_in_sidebar + appSettings.refocusOnGameClose = refocus_on_game_close + appSettings.compactInstanceCards = compact_instance_cards + appSettings.showPlayTime = show_play_time + appSettings.warnOnUnknownModpacks = warn_on_unknown_modpacks + appSettings.skipNonEssentialWarnings = skip_non_essential_warnings + appSettings.showJumpIn = show_jump_in + appSettings.alwaysShowCopyDetails = always_show_copy_details + appSettings.hideInstalledModpacks = hide_installed_modpacks + appSettings.advancedFiltersCollapsed = advanced_filters_collapsed + appSettings.dismissedPhotosensitivityFilterWarning = dismissed_photosensitivity_filter_warning + appSettings.friendsActiveCollapsed = friends_active_collapsed + appSettings.friendsOnlineCollapsed = friends_online_collapsed + appSettings.friendsOfflineCollapsed = friends_offline_collapsed + appSettings.friendsPendingCollapsed = friends_pending_collapsed appSettings.devMode = developer_mode stateInitialized.value = true debugStartup('App state initialized') @@ -1241,16 +1269,24 @@ watch( } if (behavior && appSettings.syncBehaviorAcrossDevices) { - const behaviorFeatureFlags = { - compact_instance_cards: behavior.compact_instance_cards, - show_instance_play_time: behavior.show_play_time, - skip_unknown_pack_warning: !behavior.warn_on_unknown_modpacks, - skip_non_essential_warnings: behavior.skip_non_essential_warnings, + const behaviorSettings = { + refocus_on_game_close: 'refocusOnGameClose', + compact_instance_cards: 'compactInstanceCards', + show_play_time: 'showPlayTime', + warn_on_unknown_modpacks: 'warnOnUnknownModpacks', + skip_non_essential_warnings: 'skipNonEssentialWarnings', + } + for (const [key, stateKey] of Object.entries(behaviorSettings)) { + const value = behavior[key] ?? settings[key] + appSettings[stateKey] = value + if (settings[key] !== value) { + settings[key] = value + settingsChanged = true + } } appSettings.toggleSidebar = behavior.hide_right_sidebar appSettings.hideNametagSkinsPage = behavior.hide_nametag - Object.assign(appSettings.featureFlags, behaviorFeatureFlags) if (settings.hide_on_process_start !== behavior.minimize_app) { settings.hide_on_process_start = behavior.minimize_app @@ -1264,20 +1300,11 @@ watch( settings.hide_nametag_skins_page = behavior.hide_nametag settingsChanged = true } - - for (const [flag, value] of Object.entries(behaviorFeatureFlags)) { - if (settings.feature_flags[flag] !== value) { - settings.feature_flags[flag] = value - settingsChanged = true - } - } } if (behavior && appSettings.syncFeaturesAcrossDevices) { - const featureFlags = { - worlds_in_home: behavior.show_jump_in, - } const featureSettings = { + show_jump_in: 'showJumpIn', show_files_tab_in_instances: 'showFilesTabInInstances', show_worlds_tab_in_instances: 'showWorldsTabInInstances', show_screenshots_tab_in_instances: 'showScreenshotsTabInInstances', @@ -1291,7 +1318,6 @@ watch( settingsChanged = true } } - Object.assign(appSettings.featureFlags, featureFlags) if (typeof behavior.quick_instance_count === 'number') { quickInstances.setLimit(behavior.quick_instance_count) } @@ -1310,13 +1336,6 @@ watch( await queryClient.invalidateQueries({ queryKey: screenshotKeys.all }) } } - - for (const [flag, value] of Object.entries(featureFlags)) { - if (settings.feature_flags[flag] !== value) { - settings.feature_flags[flag] = value - settingsChanged = true - } - } } if (settingsChanged) { diff --git a/apps/app-frontend/src/components/ui/download-manager/use-download-manager.ts b/apps/app-frontend/src/components/ui/download-manager/use-download-manager.ts index 05641764818..23f033cdc48 100644 --- a/apps/app-frontend/src/components/ui/download-manager/use-download-manager.ts +++ b/apps/app-frontend/src/components/ui/download-manager/use-download-manager.ts @@ -125,7 +125,7 @@ export function useDownloadManager() { canCopyDetails: job.status === 'failed' || job.status === 'interrupted' || - appSettings.getFeatureFlag('always_show_copy_details'), + appSettings.alwaysShowCopyDetails, copied: copiedJobs.value.has(job.job_id), busy: busyJobs.value.has(job.job_id), } diff --git a/apps/app-frontend/src/components/ui/friends/FriendsList.vue b/apps/app-frontend/src/components/ui/friends/FriendsList.vue index 8db35f4cf8c..08f0d43dd56 100644 --- a/apps/app-frontend/src/components/ui/friends/FriendsList.vue +++ b/apps/app-frontend/src/components/ui/friends/FriendsList.vue @@ -32,21 +32,28 @@ const props = defineProps<{ signIn: () => void }>() -type FriendsSectionCollapsedFlag = +type FriendsSectionCollapsedSetting = | 'friends_active_collapsed' | 'friends_online_collapsed' | 'friends_offline_collapsed' | 'friends_pending_collapsed' -function isFriendsSectionCollapsed(flag: FriendsSectionCollapsedFlag) { - return appSettings.getFeatureFlag(flag) +const friendsSectionSettings = { + friends_active_collapsed: 'friendsActiveCollapsed', + friends_online_collapsed: 'friendsOnlineCollapsed', + friends_offline_collapsed: 'friendsOfflineCollapsed', + friends_pending_collapsed: 'friendsPendingCollapsed', +} as const + +function isFriendsSectionCollapsed(setting: FriendsSectionCollapsedSetting) { + return appSettings[friendsSectionSettings[setting]] } -function setFriendsSectionCollapsed(flag: FriendsSectionCollapsedFlag, collapsed: boolean) { - appSettings.featureFlags[flag] = collapsed +function setFriendsSectionCollapsed(setting: FriendsSectionCollapsedSetting, collapsed: boolean) { + appSettings[friendsSectionSettings[setting]] = collapsed getSettings() .then((settings) => { - settings.feature_flags[flag] = collapsed + settings[setting] = collapsed return setSettings(settings) }) .catch(handleError) diff --git a/apps/app-frontend/src/components/ui/install_flow/UnknownPackWarningModal.vue b/apps/app-frontend/src/components/ui/install_flow/UnknownPackWarningModal.vue index b1063c805de..e0e38a5018e 100644 --- a/apps/app-frontend/src/components/ui/install_flow/UnknownPackWarningModal.vue +++ b/apps/app-frontend/src/components/ui/install_flow/UnknownPackWarningModal.vue @@ -13,11 +13,10 @@ import { UnknownFileWarningModal } from '@modrinth/ui' import { ref, useTemplateRef } from 'vue' -import { type FeatureFlag, useAppSettings } from '@/composables/use-app-settings.ts' +import { useAppSettings } from '@/composables/use-app-settings.ts' import { get as getSettings, set as setSettings } from '@/helpers/settings' const appSettings = useAppSettings() -const skipUnknownPackWarningFeatureFlag = 'skip_unknown_pack_warning' as FeatureFlag const modal = useTemplateRef('modal') const onProceed = ref<() => Promise>() @@ -33,7 +32,7 @@ function show( fileName.value = selectedFileName externalFilesInModpack.value = selectedExternalFiles - if (appSettings.getFeatureFlag(skipUnknownPackWarningFeatureFlag)) { + if (!appSettings.warnOnUnknownModpacks) { void createInstance() return } @@ -49,9 +48,9 @@ function reset() { async function proceed(dontShowAgain: boolean) { if (dontShowAgain) { - appSettings.featureFlags[skipUnknownPackWarningFeatureFlag] = true + appSettings.warnOnUnknownModpacks = false const settings = await getSettings() - settings.feature_flags[skipUnknownPackWarningFeatureFlag] = true + settings.warn_on_unknown_modpacks = false await setSettings(settings) } diff --git a/apps/app-frontend/src/components/ui/library/instance-group/index.vue b/apps/app-frontend/src/components/ui/library/instance-group/index.vue index 644246aee40..fbfd098d27b 100644 --- a/apps/app-frontend/src/components/ui/library/instance-group/index.vue +++ b/apps/app-frontend/src/components/ui/library/instance-group/index.vue @@ -54,7 +54,7 @@ const props = withDefaults( const { formatMessage } = useVIntl() const appSettings = useAppSettings() -const compactMode = computed(() => appSettings.getFeatureFlag('compact_instance_cards')) +const compactMode = computed(() => appSettings.compactInstanceCards) const { addNotification } = injectNotificationManager() const { isSectionCollapsed, diff --git a/apps/app-frontend/src/components/ui/library/instance-group/instance-card-view.vue b/apps/app-frontend/src/components/ui/library/instance-group/instance-card-view.vue index 71028c79058..891aa3e43f3 100644 --- a/apps/app-frontend/src/components/ui/library/instance-group/instance-card-view.vue +++ b/apps/app-frontend/src/components/ui/library/instance-group/instance-card-view.vue @@ -22,7 +22,7 @@ const localIcon = computed(() => { return path && !/^https?:/.test(path) && !path.toLowerCase().endsWith('.svg') ? path : undefined }) const appSettings = useAppSettings() -const compactMode = computed(() => appSettings.getFeatureFlag('compact_instance_cards')) +const compactMode = computed(() => appSettings.compactInstanceCards) const thumbnail = useImageThumbnail( localIcon, () => (compactMode.value ? 96 : 384), diff --git a/apps/app-frontend/src/components/ui/settings/display/BehaviorSettings.vue b/apps/app-frontend/src/components/ui/settings/display/BehaviorSettings.vue index 55622d7ee24..db502adecfb 100644 --- a/apps/app-frontend/src/components/ui/settings/display/BehaviorSettings.vue +++ b/apps/app-frontend/src/components/ui/settings/display/BehaviorSettings.vue @@ -11,11 +11,7 @@ import { import { useMutation, useQuery, useQueryClient } from '@tanstack/vue-query' import { inject, onBeforeUnmount, onMounted } from 'vue' -import { - DEFAULT_FEATURE_FLAGS, - type FeatureFlag, - useAppSettings, -} from '@/composables/use-app-settings.ts' +import { useAppSettings } from '@/composables/use-app-settings.ts' import { type AppSettings, appSettingsKeys, @@ -33,11 +29,6 @@ const { updatePreferences } = injectUserPreferences() const settingsModal = inject(appSettingsModalContextKey, null) const queryClient = useQueryClient() -const compactInstanceCardsFlag: FeatureFlag = 'compact_instance_cards' -const skipNonEssentialWarningsFlag: FeatureFlag = 'skip_non_essential_warnings' -const skipUnknownPackWarningFlag: FeatureFlag = 'skip_unknown_pack_warning' -const showPlayTimeFlag: FeatureFlag = 'show_instance_play_time' - const messages = defineMessages({ syncAcrossDevicesTitle: { id: 'app.behavior-settings.sync-across-devices.title', @@ -72,6 +63,14 @@ const messages = defineMessages({ id: 'app.appearance-settings.minimize-launcher.description', defaultMessage: 'Minimize Modrinth App when Minecraft starts.', }, + refocusOnGameCloseTitle: { + id: 'app.behavior-settings.refocus-on-game-close.title', + defaultMessage: 'Refocus app when Minecraft closes', + }, + refocusOnGameCloseDescription: { + id: 'app.behavior-settings.refocus-on-game-close.description', + defaultMessage: 'Bring Modrinth App to the foreground when Minecraft exits.', + }, defaultLandingPageHome: { id: 'app.appearance-settings.default-landing-page.home', defaultMessage: 'Home', @@ -135,6 +134,7 @@ const messages = defineMessages({ type BehaviorSettingsState = { syncBehaviorAcrossDevices: boolean minimizeApp: boolean + refocusOnGameClose: boolean hideRightSidebar: boolean compactInstanceCards: boolean showPlayTime: boolean @@ -150,20 +150,13 @@ function getBehaviorSettingsState(settings: AppSettings): BehaviorSettingsState return { syncBehaviorAcrossDevices: settings.sync_behavior_across_devices, minimizeApp: settings.hide_on_process_start, + refocusOnGameClose: settings.refocus_on_game_close, + compactInstanceCards: settings.compact_instance_cards, + showPlayTime: settings.show_play_time, + warnOnUnknownModpacks: settings.warn_on_unknown_modpacks, + skipNonEssentialWarnings: settings.skip_non_essential_warnings, hideRightSidebar: settings.toggle_sidebar, - compactInstanceCards: - settings.feature_flags[compactInstanceCardsFlag] ?? - DEFAULT_FEATURE_FLAGS[compactInstanceCardsFlag], - showPlayTime: - settings.feature_flags[showPlayTimeFlag] ?? DEFAULT_FEATURE_FLAGS[showPlayTimeFlag], hideNametag: settings.hide_nametag_skins_page, - warnOnUnknownModpacks: !( - settings.feature_flags[skipUnknownPackWarningFlag] ?? - DEFAULT_FEATURE_FLAGS[skipUnknownPackWarningFlag] - ), - skipNonEssentialWarnings: - settings.feature_flags[skipNonEssentialWarningsFlag] ?? - DEFAULT_FEATURE_FLAGS[skipNonEssentialWarningsFlag], } } @@ -175,6 +168,7 @@ const settingsMutation = useMutation({ await updatePreferences({ behavior: { minimize_app: value.minimizeApp, + refocus_on_game_close: value.refocusOnGameClose, hide_right_sidebar: value.hideRightSidebar, compact_instance_cards: value.compactInstanceCards, show_play_time: value.showPlayTime, @@ -192,24 +186,23 @@ const settingsMutation = useMutation({ hide_on_process_start: value.minimizeApp, toggle_sidebar: value.hideRightSidebar, hide_nametag_skins_page: value.hideNametag, - feature_flags: { - ...latestSettings.feature_flags, - [compactInstanceCardsFlag]: value.compactInstanceCards, - [showPlayTimeFlag]: value.showPlayTime, - [skipUnknownPackWarningFlag]: !value.warnOnUnknownModpacks, - [skipNonEssentialWarningsFlag]: value.skipNonEssentialWarnings, - }, + refocus_on_game_close: value.refocusOnGameClose, + compact_instance_cards: value.compactInstanceCards, + show_play_time: value.showPlayTime, + warn_on_unknown_modpacks: value.warnOnUnknownModpacks, + skip_non_essential_warnings: value.skipNonEssentialWarnings, } await set(nextSettings) queryClient.setQueryData(appSettingsKeys.all, nextSettings) appSettings.setBehaviorSyncAcrossDevices(value.syncBehaviorAcrossDevices) + appSettings.refocusOnGameClose = value.refocusOnGameClose + appSettings.compactInstanceCards = value.compactInstanceCards + appSettings.showPlayTime = value.showPlayTime + appSettings.warnOnUnknownModpacks = value.warnOnUnknownModpacks + appSettings.skipNonEssentialWarnings = value.skipNonEssentialWarnings appSettings.toggleSidebar = value.hideRightSidebar appSettings.hideNametagSkinsPage = value.hideNametag - appSettings.featureFlags[compactInstanceCardsFlag] = value.compactInstanceCards - appSettings.featureFlags[showPlayTimeFlag] = value.showPlayTime - appSettings.featureFlags[skipUnknownPackWarningFlag] = !value.warnOnUnknownModpacks - appSettings.featureFlags[skipNonEssentialWarningsFlag] = value.skipNonEssentialWarnings }, onMutate: () => queryClient.cancelQueries({ queryKey: appSettingsKeys.all }), onError: handleError, @@ -289,6 +282,23 @@ onBeforeUnmount(() => { +
+
+

+ {{ formatMessage(messages.refocusOnGameCloseTitle) }} +

+

+ {{ formatMessage(messages.refocusOnGameCloseDescription) }} +

+
+ +
+

diff --git a/apps/app-frontend/src/components/ui/settings/display/FeaturesSettings.vue b/apps/app-frontend/src/components/ui/settings/display/FeaturesSettings.vue index 1d3e3794165..6ba67a98531 100644 --- a/apps/app-frontend/src/components/ui/settings/display/FeaturesSettings.vue +++ b/apps/app-frontend/src/components/ui/settings/display/FeaturesSettings.vue @@ -12,11 +12,7 @@ import { import { useMutation, useQuery, useQueryClient } from '@tanstack/vue-query' import { inject, onBeforeUnmount, onMounted } from 'vue' -import { - DEFAULT_FEATURE_FLAGS, - type FeatureFlag, - useAppSettings, -} from '@/composables/use-app-settings.ts' +import { useAppSettings } from '@/composables/use-app-settings.ts' import { QUICK_INSTANCE_LIMIT_MAX, useQuickInstanceLimit, @@ -42,8 +38,6 @@ const settingsModal = inject(appSettingsModalContextKey, null) const quickInstances = useQuickInstanceLimit() const queryClient = useQueryClient() -const showJumpInFlag: FeatureFlag = 'worlds_in_home' - const messages = defineMessages({ syncAcrossDevicesTitle: { id: 'app.features-settings.sync-across-devices.title', @@ -145,7 +139,7 @@ function getFeaturesSettingsState( showAllScreenshots: globalSyncedOptions.screenshots, showSkinSelector: settings.show_skin_selector_in_sidebar, quickInstanceCount: quickInstances.limit.value ?? QUICK_INSTANCE_LIMIT_MAX, - showJumpIn: settings.feature_flags[showJumpInFlag] ?? DEFAULT_FEATURE_FLAGS[showJumpInFlag], + showJumpIn: settings.show_jump_in, } } @@ -181,10 +175,7 @@ const settingsMutation = useMutation({ show_worlds_tab_in_instances: value.showWorldsTab, show_screenshots_tab_in_instances: value.showScreenshotsTab, show_skin_selector_in_sidebar: value.showSkinSelector, - feature_flags: { - ...latestSettings.feature_flags, - [showJumpInFlag]: value.showJumpIn, - }, + show_jump_in: value.showJumpIn, } const screenshotsChanged = @@ -205,7 +196,7 @@ const settingsMutation = useMutation({ appSettings.showWorldsTabInInstances = value.showWorldsTab appSettings.showScreenshotsTabInInstances = value.showScreenshotsTab appSettings.showSkinSelectorInSidebar = value.showSkinSelector - appSettings.featureFlags[showJumpInFlag] = value.showJumpIn + appSettings.showJumpIn = value.showJumpIn if (updateQuickInstanceCount) { quickInstances.setLimit(value.quickInstanceCount) diff --git a/apps/app-frontend/src/components/ui/settings/instances/ResourceManagementSettings.vue b/apps/app-frontend/src/components/ui/settings/instances/ResourceManagementSettings.vue index 9ce5445b578..5e2e47444b4 100644 --- a/apps/app-frontend/src/components/ui/settings/instances/ResourceManagementSettings.vue +++ b/apps/app-frontend/src/components/ui/settings/instances/ResourceManagementSettings.vue @@ -25,7 +25,6 @@ const { formatMessage } = useVIntl() const appSettings = useAppSettings() const settings = ref(await get()) const purgeCacheConfirmModal = ref(null) -const alwaysShowCopyDetailsFlag = 'always_show_copy_details' const messages = defineMessages({ appDirectoryTitle: { @@ -146,7 +145,7 @@ async function purgeCache() { } function handlePurgeCacheClick() { - if (appSettings.getFeatureFlag('skip_non_essential_warnings')) { + if (appSettings.skipNonEssentialWarnings) { void purgeCache() return } @@ -212,12 +211,12 @@ async function findLauncherDir() {

diff --git a/apps/app-frontend/src/components/ui/shared-instances/shared-instance-invite-handler/use-shared-instance-invite-handler.ts b/apps/app-frontend/src/components/ui/shared-instances/shared-instance-invite-handler/use-shared-instance-invite-handler.ts index 00bd70b9c04..41d7ef805a1 100644 --- a/apps/app-frontend/src/components/ui/shared-instances/shared-instance-invite-handler/use-shared-instance-invite-handler.ts +++ b/apps/app-frontend/src/components/ui/shared-instances/shared-instance-invite-handler/use-shared-instance-invite-handler.ts @@ -121,7 +121,7 @@ export function useSharedInstanceInviteHandler( (instance) => instance.shared_instance?.id === sharedInstanceId, ) - if (!existingInstance || appSettings.getFeatureFlag('skip_non_essential_warnings')) { + if (!existingInstance || appSettings.skipNonEssentialWarnings) { showInstall(preview, install, creator) return } diff --git a/apps/app-frontend/src/components/ui/world/RecentWorldsList.vue b/apps/app-frontend/src/components/ui/world/RecentWorldsList.vue index e42cdcb0630..d54f2703f80 100644 --- a/apps/app-frontend/src/components/ui/world/RecentWorldsList.vue +++ b/apps/app-frontend/src/components/ui/world/RecentWorldsList.vue @@ -178,7 +178,7 @@ type WorldJumpBackInItem = BaseJumpBackInItem & { type JumpBackInItem = InstanceJumpBackInItem | WorldJumpBackInItem -const showWorlds = computed(() => appSettings.getFeatureFlag('worlds_in_home')) +const showWorlds = computed(() => appSettings.showJumpIn) const recentWorldsQuery = useQuery({ ...recentWorldsQueryOptions(MAX_JUMP_BACK_IN), diff --git a/apps/app-frontend/src/composables/use-app-settings.ts b/apps/app-frontend/src/composables/use-app-settings.ts index 0d58903fa12..dceec83997a 100644 --- a/apps/app-frontend/src/composables/use-app-settings.ts +++ b/apps/app-frontend/src/composables/use-app-settings.ts @@ -3,26 +3,13 @@ import { reactive, ref } from 'vue' export const DEFAULT_FEATURE_FLAGS = { project_background: false, page_path: false, - worlds_in_home: true, server_project_qa: false, show_version_environment_column: false, server_ram_as_bytes_always_on: false, always_show_app_controls: false, show_sync_instances_update_modal: false, - skip_non_essential_warnings: false, - skip_unknown_pack_warning: false, pride_fundraiser: true, i18n_debug: false, - show_instance_play_time: true, - compact_instance_cards: false, - advanced_filters_collapsed: true, - always_show_copy_details: false, - hide_installed_modpacks: false, - friends_active_collapsed: false, - friends_online_collapsed: false, - friends_offline_collapsed: true, - friends_pending_collapsed: true, - dismissed_photosensitivity_filter_warning: false, localhost_sign_in: false, } @@ -46,6 +33,20 @@ function getFeatureFlag(key: FeatureFlag): boolean { } const appSettings = reactive({ + showJumpIn: true, + alwaysShowCopyDetails: false, + hideInstalledModpacks: false, + advancedFiltersCollapsed: true, + dismissedPhotosensitivityFilterWarning: false, + friendsActiveCollapsed: false, + friendsOnlineCollapsed: false, + friendsOfflineCollapsed: true, + friendsPendingCollapsed: true, + refocusOnGameClose: false, + compactInstanceCards: false, + showPlayTime: true, + warnOnUnknownModpacks: true, + skipNonEssentialWarnings: false, syncBehaviorAcrossDevices, syncFeaturesAcrossDevices, hideNametagSkinsPage: false, diff --git a/apps/app-frontend/src/helpers/settings.ts b/apps/app-frontend/src/helpers/settings.ts index 9d1d67b7744..85688c10cf6 100644 --- a/apps/app-frontend/src/helpers/settings.ts +++ b/apps/app-frontend/src/helpers/settings.ts @@ -63,6 +63,20 @@ export type AppSettings = { force_fullscreen: boolean game_resolution: WindowSize hide_on_process_start: boolean + show_jump_in: boolean + always_show_copy_details: boolean + hide_installed_modpacks: boolean + advanced_filters_collapsed: boolean + dismissed_photosensitivity_filter_warning: boolean + friends_active_collapsed: boolean + friends_online_collapsed: boolean + friends_offline_collapsed: boolean + friends_pending_collapsed: boolean + refocus_on_game_close: boolean + compact_instance_cards: boolean + show_play_time: boolean + warn_on_unknown_modpacks: boolean + skip_non_essential_warnings: boolean hooks: Hooks custom_dir?: string | null diff --git a/apps/app-frontend/src/helpers/types.d.ts b/apps/app-frontend/src/helpers/types.d.ts index b2bbc664ce4..a17a0acadc2 100644 --- a/apps/app-frontend/src/helpers/types.d.ts +++ b/apps/app-frontend/src/helpers/types.d.ts @@ -243,6 +243,20 @@ type AppSettings = { force_fullscreen: boolean game_resolution: [number, number] hide_on_process_start: boolean + show_jump_in: boolean + always_show_copy_details: boolean + hide_installed_modpacks: boolean + advanced_filters_collapsed: boolean + dismissed_photosensitivity_filter_warning: boolean + friends_active_collapsed: boolean + friends_online_collapsed: boolean + friends_offline_collapsed: boolean + friends_pending_collapsed: boolean + refocus_on_game_close: boolean + compact_instance_cards: boolean + show_play_time: boolean + warn_on_unknown_modpacks: boolean + skip_non_essential_warnings: boolean hooks: Hooks custom_dir?: string diff --git a/apps/app-frontend/src/locales/en-US/index.json b/apps/app-frontend/src/locales/en-US/index.json index 09f98ec77fe..99d88e154e1 100644 --- a/apps/app-frontend/src/locales/en-US/index.json +++ b/apps/app-frontend/src/locales/en-US/index.json @@ -206,6 +206,12 @@ "app.behavior-settings.content.title": { "message": "Home and content" }, + "app.behavior-settings.refocus-on-game-close.description": { + "message": "Bring Modrinth App to the foreground when Minecraft exits." + }, + "app.behavior-settings.refocus-on-game-close.title": { + "message": "Refocus app when Minecraft closes" + }, "app.behavior-settings.startup-and-navigation.title": { "message": "Startup and navigation" }, diff --git a/apps/app-frontend/src/pages/Browse.vue b/apps/app-frontend/src/pages/Browse.vue index c088dfb550d..2fb77e28e9f 100644 --- a/apps/app-frontend/src/pages/Browse.vue +++ b/apps/app-frontend/src/pages/Browse.vue @@ -382,19 +382,19 @@ async function initInstanceContext() { } } -function setBrowseHideInstalledFlag(flag: 'hide_installed_modpacks', value: boolean) { - appSettings.featureFlags[flag] = value +function setHideInstalledModpacks(value: boolean) { + appSettings.hideInstalledModpacks = value getSettings() .then((settings) => { - settings.feature_flags[flag] = value + settings.hide_installed_modpacks = value return setSettings(settings) }) .catch(handleError) } const hideInstalledModpacks = computed({ - get: () => appSettings.getFeatureFlag('hide_installed_modpacks'), - set: (value: boolean) => setBrowseHideInstalledFlag('hide_installed_modpacks', value), + get: () => appSettings.hideInstalledModpacks, + set: (value: boolean) => setHideInstalledModpacks(value), }) const instanceFilters = computed(() => { @@ -751,7 +751,7 @@ const installContext = computed(() => { queuedCount: queuedServerInstallCount.value, selectedProjects: selectedServerInstallProjects.value, isInstallingSelected: isInstallingQueuedServerInstalls.value, - skipNonEssentialWarnings: appSettings.getFeatureFlag('skip_non_essential_warnings'), + skipNonEssentialWarnings: appSettings.skipNonEssentialWarnings, installProgress: queuedInstallProgress.value, clearQueued: clearQueuedServerInstalls, clearSelected: clearQueuedServerInstalls, @@ -1231,12 +1231,12 @@ function getProjectBrowseQuery() { } const advancedFiltersCollapsed = computed({ - get: () => appSettings.getFeatureFlag('advanced_filters_collapsed'), + get: () => appSettings.advancedFiltersCollapsed, set: (value) => { - appSettings.featureFlags['advanced_filters_collapsed'] = value + appSettings.advancedFiltersCollapsed = value getSettings() .then((settings) => { - settings.feature_flags['advanced_filters_collapsed'] = value + settings.advanced_filters_collapsed = value return setSettings(settings) }) .catch(handleError) @@ -1244,12 +1244,12 @@ const advancedFiltersCollapsed = computed({ }) const dismissedPhotosensitivityFilterWarning = computed({ - get: () => appSettings.getFeatureFlag('dismissed_photosensitivity_filter_warning'), + get: () => appSettings.dismissedPhotosensitivityFilterWarning, set: (value) => { - appSettings.featureFlags['dismissed_photosensitivity_filter_warning'] = value + appSettings.dismissedPhotosensitivityFilterWarning = value getSettings() .then((settings) => { - settings.feature_flags['dismissed_photosensitivity_filter_warning'] = value + settings.dismissed_photosensitivity_filter_warning = value return setSettings(settings) }) .catch(handleError) diff --git a/apps/app-frontend/src/pages/Index.vue b/apps/app-frontend/src/pages/Index.vue index 1c5fb5d223f..cdad0e8818a 100644 --- a/apps/app-frontend/src/pages/Index.vue +++ b/apps/app-frontend/src/pages/Index.vue @@ -97,7 +97,7 @@ function openPageContextMenu(event: MouseEvent) { @contextmenu="openPageContextMenu" > diff --git a/apps/app-frontend/src/pages/instance/components/settings-modal/installation-settings.vue b/apps/app-frontend/src/pages/instance/components/settings-modal/installation-settings.vue index acb7e1f4110..6c6d6d0b17e 100644 --- a/apps/app-frontend/src/pages/instance/components/settings-modal/installation-settings.vue +++ b/apps/app-frontend/src/pages/instance/components/settings-modal/installation-settings.vue @@ -51,9 +51,7 @@ const appSettings = useAppSettings() const { instance, offline, isMinecraftServer, onUnlinked, closeModal } = injectInstanceSettings() const managedContentPolicy = useManagedContentPolicy(instance) -const skipNonEssentialWarnings = computed(() => - appSettings.getFeatureFlag('skip_non_essential_warnings'), -) +const skipNonEssentialWarnings = computed(() => appSettings.skipNonEssentialWarnings) debug('metadata load: start', { instanceId: instance.value.id, diff --git a/apps/app-frontend/src/pages/instance/content/index.vue b/apps/app-frontend/src/pages/instance/content/index.vue index 491e336b85e..4dc2165b410 100644 --- a/apps/app-frontend/src/pages/instance/content/index.vue +++ b/apps/app-frontend/src/pages/instance/content/index.vue @@ -130,7 +130,7 @@ import ShareModalWrapper from '@/components/ui/modal/ShareModalWrapper.vue' import { useManagedContentPolicy } from '@/composables/instances/use-managed-content-policy' import { useSyncedPackActions } from '@/composables/instances/use-synced-pack-actions' import { useAppEvent } from '@/composables/use-app-event' -import { type FeatureFlag, useAppSettings } from '@/composables/use-app-settings.ts' +import { useAppSettings } from '@/composables/use-app-settings.ts' import { trackEvent } from '@/helpers/analytics' import { get_project_versions, get_version, get_version_many } from '@/helpers/cache.js' import { @@ -239,10 +239,7 @@ const route = useRoute() const queryClient = useQueryClient() const debug = useDebugLogger('Mods:ContentUpdate') const appSettings = useAppSettings() -const skipUnknownFileWarningFeatureFlag = 'skip_unknown_pack_warning' as FeatureFlag -const skipNonEssentialWarnings = computed(() => - appSettings.getFeatureFlag('skip_non_essential_warnings'), -) +const skipNonEssentialWarnings = computed(() => appSettings.skipNonEssentialWarnings) const instancePage = injectInstancePage() const sharedInstanceState = injectSharedInstance() @@ -796,7 +793,7 @@ async function handleUploadFiles() { } function confirmUnknownFileInstallation(fileName: string) { - if (appSettings.getFeatureFlag(skipUnknownFileWarningFeatureFlag)) { + if (!appSettings.warnOnUnknownModpacks) { return Promise.resolve(true) } @@ -816,10 +813,10 @@ function resolveUnknownFileWarning(confirmed: boolean) { async function handleUnknownFileContinue(dontShowAgain: boolean) { if (dontShowAgain) { - appSettings.featureFlags[skipUnknownFileWarningFeatureFlag] = true + appSettings.warnOnUnknownModpacks = false try { const settings = await getSettings() - settings.feature_flags[skipUnknownFileWarningFeatureFlag] = true + settings.warn_on_unknown_modpacks = false await setSettings(settings) } catch (error) { handleError(error as Error) diff --git a/apps/app-frontend/src/pages/instance/layout.vue b/apps/app-frontend/src/pages/instance/layout.vue index 7ec73ca240e..30d902ef1b6 100644 --- a/apps/app-frontend/src/pages/instance/layout.vue +++ b/apps/app-frontend/src/pages/instance/layout.vue @@ -214,7 +214,7 @@ watch( { immediate: true }, ) const appSettings = useAppSettings() -const showInstancePlayTime = computed(() => appSettings.getFeatureFlag('show_instance_play_time')) +const showInstancePlayTime = computed(() => appSettings.showPlayTime) const online = useOnline() const offline = computed(() => !online.value) diff --git a/apps/app-frontend/src/providers/content-install.ts b/apps/app-frontend/src/providers/content-install.ts index 2a2f05f08a3..e574d1f4ea4 100644 --- a/apps/app-frontend/src/providers/content-install.ts +++ b/apps/app-frontend/src/providers/content-install.ts @@ -860,7 +860,7 @@ export function createContentInstall(opts: { const packs = await list() const existingPack = packs.find((pack) => pack.link?.project_id === project.id) - if (existingPack && !appSettings.getFeatureFlag('skip_non_essential_warnings')) { + if (existingPack && !appSettings.skipNonEssentialWarnings) { pendingModpackInstall = { project, version, source, callback, createInstanceCallback } modpackAlreadyInstalledModalRef?.show(existingPack.name, existingPack.id) return diff --git a/apps/app-frontend/src/providers/setup/creation-modal.ts b/apps/app-frontend/src/providers/setup/creation-modal.ts index 964b17cdacb..31ad5aa5aa4 100644 --- a/apps/app-frontend/src/providers/setup/creation-modal.ts +++ b/apps/app-frontend/src/providers/setup/creation-modal.ts @@ -93,7 +93,7 @@ export function setupCreationModal( const instances = await list().catch(handleError) const existingInstance = instances?.find((i) => i.link?.project_id === projectId) - if (existingInstance && !appSettings.getFeatureFlag('skip_non_essential_warnings')) { + if (existingInstance && !appSettings.skipNonEssentialWarnings) { pendingModpackCreation.value = { projectId, versionId, name } installationModal.value?.hide() modpackAlreadyInstalledModal.value?.show(existingInstance.name, existingInstance.id) diff --git a/apps/labrinth/src/models/v3/preferences.rs b/apps/labrinth/src/models/v3/preferences.rs index 8eb54b34d2a..61044956295 100644 --- a/apps/labrinth/src/models/v3/preferences.rs +++ b/apps/labrinth/src/models/v3/preferences.rs @@ -39,6 +39,7 @@ pub struct AppearancePreferences { #[derive(Debug, Serialize, Deserialize, ToSchema, PartialEq, Component)] pub struct BehaviorPreferences { pub minimize_app: bool, + pub refocus_on_game_close: bool, pub hide_right_sidebar: bool, pub show_jump_in: bool, pub compact_instance_cards: bool, @@ -58,6 +59,7 @@ impl Default for BehaviorPreferences { fn default() -> Self { Self { minimize_app: false, + refocus_on_game_close: false, hide_right_sidebar: false, show_jump_in: true, compact_instance_cards: false, diff --git a/packages/api-client/src/modules/labrinth/types.ts b/packages/api-client/src/modules/labrinth/types.ts index e105386f05d..3b5be3ad4e6 100644 --- a/packages/api-client/src/modules/labrinth/types.ts +++ b/packages/api-client/src/modules/labrinth/types.ts @@ -1811,6 +1811,7 @@ export namespace Labrinth { export type BehaviorPreferences = { minimize_app: boolean + refocus_on_game_close: boolean hide_right_sidebar: boolean show_jump_in: boolean compact_instance_cards: boolean diff --git a/packages/app-lib/.sqlx/query-157e08b825d3f3a9325aefd1daf4695cb9c82d67b3b47be219e358ab0bf950d8.json b/packages/app-lib/.sqlx/query-157e08b825d3f3a9325aefd1daf4695cb9c82d67b3b47be219e358ab0bf950d8.json deleted file mode 100644 index e810ccb4443..00000000000 --- a/packages/app-lib/.sqlx/query-157e08b825d3f3a9325aefd1daf4695cb9c82d67b3b47be219e358ab0bf950d8.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "db_name": "SQLite", - "query": "SELECT binding.file_id, binding.blob_sha512, binding.materialization_kind FROM store_instance_files binding INNER JOIN instance_files file ON file.id = binding.file_id WHERE file.instance_id = ?", - "describe": { - "columns": [ - { - "name": "file_id", - "ordinal": 0, - "type_info": "Text" - }, - { - "name": "blob_sha512", - "ordinal": 1, - "type_info": "Text" - }, - { - "name": "materialization_kind", - "ordinal": 2, - "type_info": "Text" - } - ], - "parameters": { - "Right": 1 - }, - "nullable": [ - false, - false, - false - ] - }, - "hash": "157e08b825d3f3a9325aefd1daf4695cb9c82d67b3b47be219e358ab0bf950d8" -} diff --git a/packages/app-lib/.sqlx/query-4a61be9c9656ac5e0017a64752670625caa1412a520c41351c7d38f94dae7bda.json b/packages/app-lib/.sqlx/query-4a61be9c9656ac5e0017a64752670625caa1412a520c41351c7d38f94dae7bda.json deleted file mode 100644 index d6b3449ac88..00000000000 --- a/packages/app-lib/.sqlx/query-4a61be9c9656ac5e0017a64752670625caa1412a520c41351c7d38f94dae7bda.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "db_name": "SQLite", - "query": "SELECT binding.blob_sha512, binding.materialization_kind, file.size FROM store_instance_files binding INNER JOIN instance_files file ON file.id = binding.file_id WHERE file.missing = 0", - "describe": { - "columns": [ - { - "name": "blob_sha512", - "ordinal": 0, - "type_info": "Text" - }, - { - "name": "materialization_kind", - "ordinal": 1, - "type_info": "Text" - }, - { - "name": "size", - "ordinal": 2, - "type_info": "Integer" - } - ], - "parameters": { - "Right": 0 - }, - "nullable": [ - false, - false, - false - ] - }, - "hash": "4a61be9c9656ac5e0017a64752670625caa1412a520c41351c7d38f94dae7bda" -} diff --git a/packages/app-lib/.sqlx/query-a37f3c9cc8c1d8aa620f83569633db30d98573c1ac04705da186d0cf88b20ca7.json b/packages/app-lib/.sqlx/query-73280fdb7c56d365237cbda6eafe9b137ebf2cb7af6dcaa7f62ab53f9e359ba1.json similarity index 71% rename from packages/app-lib/.sqlx/query-a37f3c9cc8c1d8aa620f83569633db30d98573c1ac04705da186d0cf88b20ca7.json rename to packages/app-lib/.sqlx/query-73280fdb7c56d365237cbda6eafe9b137ebf2cb7af6dcaa7f62ab53f9e359ba1.json index 7c0feed8ed2..aa43bbd7ad5 100644 --- a/packages/app-lib/.sqlx/query-a37f3c9cc8c1d8aa620f83569633db30d98573c1ac04705da186d0cf88b20ca7.json +++ b/packages/app-lib/.sqlx/query-73280fdb7c56d365237cbda6eafe9b137ebf2cb7af6dcaa7f62ab53f9e359ba1.json @@ -1,6 +1,6 @@ { "db_name": "SQLite", - "query": "\n SELECT\n max_concurrent_writes, max_concurrent_downloads,\n theme, locale, default_page, collapsed_navigation, hide_nametag_skins_page, advanced_rendering, native_decorations,\n discord_rpc, developer_mode, telemetry, personalized_ads,\n json(extra_launch_args) extra_launch_args, json(custom_env_vars) custom_env_vars,\n mc_memory_max, mc_force_fullscreen, mc_game_resolution_x, mc_game_resolution_y, hide_on_process_start,\n hook_pre_launch, hook_wrapper, hook_post_exit,\n custom_dir, prev_custom_dir, migrated, json(feature_flags) feature_flags, toggle_sidebar,\n skipped_update, pending_update_toast_for_version, auto_download_updates,\n\t\t\t\tsync_theme_across_devices, sync_behavior_across_devices, sync_features_across_devices,\n\t\t\t\tshow_files_tab_in_instances, show_worlds_tab_in_instances,\n\t\t\t\tshow_screenshots_tab_in_instances, show_skin_selector_in_sidebar,\n version\n FROM settings\n ", + "query": "\n SELECT\n max_concurrent_writes, max_concurrent_downloads,\n theme, locale, default_page, collapsed_navigation, hide_nametag_skins_page, advanced_rendering, native_decorations,\n discord_rpc, developer_mode, telemetry, personalized_ads,\n json(extra_launch_args) extra_launch_args, json(custom_env_vars) custom_env_vars,\n mc_memory_max, mc_force_fullscreen, mc_game_resolution_x, mc_game_resolution_y, hide_on_process_start,\n hook_pre_launch, hook_wrapper, hook_post_exit,\n custom_dir, prev_custom_dir, migrated, json(feature_flags) feature_flags, toggle_sidebar,\n skipped_update, pending_update_toast_for_version, auto_download_updates,\n\t\t\t\tsync_theme_across_devices, sync_behavior_across_devices, sync_features_across_devices,\n\t\t\t\tshow_files_tab_in_instances, show_worlds_tab_in_instances,\n\t\t\t\tshow_screenshots_tab_in_instances, show_skin_selector_in_sidebar,\n\t\t\t\trefocus_on_game_close, compact_instance_cards, show_play_time, warn_on_unknown_modpacks, skip_non_essential_warnings,\n\t\t\t\tshow_jump_in,\n\t\t\t\talways_show_copy_details,\n\t\t\t\thide_installed_modpacks,\n\t\t\t\tadvanced_filters_collapsed,\n\t\t\t\tdismissed_photosensitivity_filter_warning,\n\t\t\t\tfriends_active_collapsed,\n\t\t\t\tfriends_online_collapsed,\n\t\t\t\tfriends_offline_collapsed,\n\t\t\t\tfriends_pending_collapsed,\n version\n FROM settings\n ", "describe": { "columns": [ { @@ -194,9 +194,79 @@ "type_info": "Integer" }, { - "name": "version", + "name": "refocus_on_game_close", "ordinal": 38, "type_info": "Integer" + }, + { + "name": "compact_instance_cards", + "ordinal": 39, + "type_info": "Integer" + }, + { + "name": "show_play_time", + "ordinal": 40, + "type_info": "Integer" + }, + { + "name": "warn_on_unknown_modpacks", + "ordinal": 41, + "type_info": "Integer" + }, + { + "name": "skip_non_essential_warnings", + "ordinal": 42, + "type_info": "Integer" + }, + { + "name": "show_jump_in", + "ordinal": 43, + "type_info": "Integer" + }, + { + "name": "always_show_copy_details", + "ordinal": 44, + "type_info": "Integer" + }, + { + "name": "hide_installed_modpacks", + "ordinal": 45, + "type_info": "Integer" + }, + { + "name": "advanced_filters_collapsed", + "ordinal": 46, + "type_info": "Integer" + }, + { + "name": "dismissed_photosensitivity_filter_warning", + "ordinal": 47, + "type_info": "Integer" + }, + { + "name": "friends_active_collapsed", + "ordinal": 48, + "type_info": "Integer" + }, + { + "name": "friends_online_collapsed", + "ordinal": 49, + "type_info": "Integer" + }, + { + "name": "friends_offline_collapsed", + "ordinal": 50, + "type_info": "Integer" + }, + { + "name": "friends_pending_collapsed", + "ordinal": 51, + "type_info": "Integer" + }, + { + "name": "version", + "ordinal": 52, + "type_info": "Integer" } ], "parameters": { @@ -241,8 +311,22 @@ false, false, false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, false ] }, - "hash": "a37f3c9cc8c1d8aa620f83569633db30d98573c1ac04705da186d0cf88b20ca7" + "hash": "73280fdb7c56d365237cbda6eafe9b137ebf2cb7af6dcaa7f62ab53f9e359ba1" } diff --git a/packages/app-lib/.sqlx/query-05b2976127c9c71488506c93b27801b9b6b187e7c75ca59fdffda2f0fb10e964.json b/packages/app-lib/.sqlx/query-781feeaa43114c4ebefa5d3200db329a3bdaa66917e8c798e4e6d1830d3e5320.json similarity index 71% rename from packages/app-lib/.sqlx/query-05b2976127c9c71488506c93b27801b9b6b187e7c75ca59fdffda2f0fb10e964.json rename to packages/app-lib/.sqlx/query-781feeaa43114c4ebefa5d3200db329a3bdaa66917e8c798e4e6d1830d3e5320.json index 955d9f2bb4d..21c02a7dfec 100644 --- a/packages/app-lib/.sqlx/query-05b2976127c9c71488506c93b27801b9b6b187e7c75ca59fdffda2f0fb10e964.json +++ b/packages/app-lib/.sqlx/query-781feeaa43114c4ebefa5d3200db329a3bdaa66917e8c798e4e6d1830d3e5320.json @@ -1,12 +1,12 @@ { "db_name": "SQLite", - "query": "\n UPDATE settings\n SET\n max_concurrent_writes = $1,\n max_concurrent_downloads = $2,\n\n theme = $3,\n locale = $4,\n default_page = $5,\n collapsed_navigation = $6,\n advanced_rendering = $7,\n native_decorations = $8,\n\n discord_rpc = $9,\n developer_mode = $10,\n telemetry = $11,\n personalized_ads = $12,\n\n extra_launch_args = jsonb($13),\n custom_env_vars = jsonb($14),\n mc_memory_max = $15,\n mc_force_fullscreen = $16,\n mc_game_resolution_x = $17,\n mc_game_resolution_y = $18,\n hide_on_process_start = $19,\n\n hook_pre_launch = $20,\n hook_wrapper = $21,\n hook_post_exit = $22,\n\n custom_dir = $23,\n prev_custom_dir = $24,\n migrated = $25,\n\n toggle_sidebar = $26,\n feature_flags = $27,\n hide_nametag_skins_page = $28,\n\n skipped_update = $29,\n pending_update_toast_for_version = $30,\n auto_download_updates = $31,\n\n sync_theme_across_devices = $32,\n sync_behavior_across_devices = $33,\n\t\t\t\tsync_features_across_devices = $34,\n\t\t\t\tshow_files_tab_in_instances = $35,\n\t\t\t\tshow_worlds_tab_in_instances = $36,\n\t\t\t\tshow_screenshots_tab_in_instances = $37,\n\t\t\t\tshow_skin_selector_in_sidebar = $38,\n\n\t\t\t\tversion = $39\n ", + "query": "\n UPDATE settings\n SET\n max_concurrent_writes = $1,\n max_concurrent_downloads = $2,\n\n theme = $3,\n locale = $4,\n default_page = $5,\n collapsed_navigation = $6,\n advanced_rendering = $7,\n native_decorations = $8,\n\n discord_rpc = $9,\n developer_mode = $10,\n telemetry = $11,\n personalized_ads = $12,\n\n extra_launch_args = jsonb($13),\n custom_env_vars = jsonb($14),\n mc_memory_max = $15,\n mc_force_fullscreen = $16,\n mc_game_resolution_x = $17,\n mc_game_resolution_y = $18,\n hide_on_process_start = $19,\n\n hook_pre_launch = $20,\n hook_wrapper = $21,\n hook_post_exit = $22,\n\n custom_dir = $23,\n prev_custom_dir = $24,\n migrated = $25,\n\n toggle_sidebar = $26,\n feature_flags = $27,\n hide_nametag_skins_page = $28,\n\n skipped_update = $29,\n pending_update_toast_for_version = $30,\n auto_download_updates = $31,\n\n sync_theme_across_devices = $32,\n sync_behavior_across_devices = $33,\n\t\t\t\tsync_features_across_devices = $34,\n\t\t\t\tshow_files_tab_in_instances = $35,\n\t\t\t\tshow_worlds_tab_in_instances = $36,\n\t\t\t\tshow_screenshots_tab_in_instances = $37,\n\t\t\t\tshow_skin_selector_in_sidebar = $38,\n\n\t\t\t\tversion = $39,\n\t\t\t\trefocus_on_game_close = $40,\n\t\t\t\tcompact_instance_cards = $41,\n\t\t\t\tshow_play_time = $42,\n\t\t\t\twarn_on_unknown_modpacks = $43,\n\t\t\t\tskip_non_essential_warnings = $44,\n\t\t\t\tshow_jump_in = $45,\n\t\t\t\talways_show_copy_details = $46,\n\t\t\t\thide_installed_modpacks = $47,\n\t\t\t\tadvanced_filters_collapsed = $48,\n\t\t\t\tdismissed_photosensitivity_filter_warning = $49,\n\t\t\t\tfriends_active_collapsed = $50,\n\t\t\t\tfriends_online_collapsed = $51,\n\t\t\t\tfriends_offline_collapsed = $52,\n\t\t\t\tfriends_pending_collapsed = $53\n ", "describe": { "columns": [], "parameters": { - "Right": 39 + "Right": 53 }, "nullable": [] }, - "hash": "05b2976127c9c71488506c93b27801b9b6b187e7c75ca59fdffda2f0fb10e964" + "hash": "781feeaa43114c4ebefa5d3200db329a3bdaa66917e8c798e4e6d1830d3e5320" } diff --git a/packages/app-lib/.sqlx/query-e5b82dcec8a1ecb462ce076c094604d15a37a029ab2eeb358145e0d7e7a28d98.json b/packages/app-lib/.sqlx/query-e5b82dcec8a1ecb462ce076c094604d15a37a029ab2eeb358145e0d7e7a28d98.json deleted file mode 100644 index 1f9568c8afe..00000000000 --- a/packages/app-lib/.sqlx/query-e5b82dcec8a1ecb462ce076c094604d15a37a029ab2eeb358145e0d7e7a28d98.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "db_name": "SQLite", - "query": "SELECT file_id, blob_sha512, materialization_kind FROM store_instance_files WHERE file_id = ?", - "describe": { - "columns": [ - { - "name": "file_id", - "ordinal": 0, - "type_info": "Text" - }, - { - "name": "blob_sha512", - "ordinal": 1, - "type_info": "Text" - }, - { - "name": "materialization_kind", - "ordinal": 2, - "type_info": "Text" - } - ], - "parameters": { - "Right": 1 - }, - "nullable": [ - false, - false, - false - ] - }, - "hash": "e5b82dcec8a1ecb462ce076c094604d15a37a029ab2eeb358145e0d7e7a28d98" -} diff --git a/packages/app-lib/.sqlx/query-e78c758eb8e6d1ddebed37fd65b1a823a6eee33e0c3cbac48cb4dc55e6e4d509.json b/packages/app-lib/.sqlx/query-e78c758eb8e6d1ddebed37fd65b1a823a6eee33e0c3cbac48cb4dc55e6e4d509.json deleted file mode 100644 index 6d0f30d597e..00000000000 --- a/packages/app-lib/.sqlx/query-e78c758eb8e6d1ddebed37fd65b1a823a6eee33e0c3cbac48cb4dc55e6e4d509.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "db_name": "SQLite", - "query": "SELECT sha512, size, status, modified_as, last_used_at, sources FROM store_blobs", - "describe": { - "columns": [ - { - "name": "sha512", - "ordinal": 0, - "type_info": "Text" - }, - { - "name": "size", - "ordinal": 1, - "type_info": "Integer" - }, - { - "name": "status", - "ordinal": 2, - "type_info": "Text" - }, - { - "name": "modified_as", - "ordinal": 3, - "type_info": "Integer" - }, - { - "name": "last_used_at", - "ordinal": 4, - "type_info": "Integer" - }, - { - "name": "sources", - "ordinal": 5, - "type_info": "Text" - } - ], - "parameters": { - "Right": 0 - }, - "nullable": [ - false, - false, - false, - false, - false, - false - ] - }, - "hash": "e78c758eb8e6d1ddebed37fd65b1a823a6eee33e0c3cbac48cb4dc55e6e4d509" -} diff --git a/packages/app-lib/migrations/20260918120000_promote-behavior-settings.sql b/packages/app-lib/migrations/20260918120000_promote-behavior-settings.sql new file mode 100644 index 00000000000..252f23261e1 --- /dev/null +++ b/packages/app-lib/migrations/20260918120000_promote-behavior-settings.sql @@ -0,0 +1,75 @@ +ALTER TABLE settings +ADD COLUMN refocus_on_game_close INTEGER NOT NULL DEFAULT FALSE CHECK (refocus_on_game_close IN (0, 1)); + +ALTER TABLE settings +ADD COLUMN compact_instance_cards INTEGER NOT NULL DEFAULT FALSE CHECK (compact_instance_cards IN (0, 1)); + +ALTER TABLE settings +ADD COLUMN show_play_time INTEGER NOT NULL DEFAULT TRUE CHECK (show_play_time IN (0, 1)); + +ALTER TABLE settings +ADD COLUMN warn_on_unknown_modpacks INTEGER NOT NULL DEFAULT TRUE CHECK (warn_on_unknown_modpacks IN (0, 1)); + +ALTER TABLE settings +ADD COLUMN skip_non_essential_warnings INTEGER NOT NULL DEFAULT FALSE CHECK (skip_non_essential_warnings IN (0, 1)); + +ALTER TABLE settings +ADD COLUMN show_jump_in INTEGER NOT NULL DEFAULT TRUE CHECK (show_jump_in IN (0, 1)); + +ALTER TABLE settings +ADD COLUMN always_show_copy_details INTEGER NOT NULL DEFAULT FALSE CHECK (always_show_copy_details IN (0, 1)); + +ALTER TABLE settings +ADD COLUMN hide_installed_modpacks INTEGER NOT NULL DEFAULT FALSE CHECK (hide_installed_modpacks IN (0, 1)); + +ALTER TABLE settings +ADD COLUMN advanced_filters_collapsed INTEGER NOT NULL DEFAULT TRUE CHECK (advanced_filters_collapsed IN (0, 1)); + +ALTER TABLE settings +ADD COLUMN dismissed_photosensitivity_filter_warning INTEGER NOT NULL DEFAULT FALSE CHECK (dismissed_photosensitivity_filter_warning IN (0, 1)); + +ALTER TABLE settings +ADD COLUMN friends_active_collapsed INTEGER NOT NULL DEFAULT FALSE CHECK (friends_active_collapsed IN (0, 1)); + +ALTER TABLE settings +ADD COLUMN friends_online_collapsed INTEGER NOT NULL DEFAULT FALSE CHECK (friends_online_collapsed IN (0, 1)); + +ALTER TABLE settings +ADD COLUMN friends_offline_collapsed INTEGER NOT NULL DEFAULT TRUE CHECK (friends_offline_collapsed IN (0, 1)); + +ALTER TABLE settings +ADD COLUMN friends_pending_collapsed INTEGER NOT NULL DEFAULT TRUE CHECK (friends_pending_collapsed IN (0, 1)); + +UPDATE settings +SET + refocus_on_game_close = COALESCE(json_extract(feature_flags, '$.refocus_on_game_close'), FALSE), + compact_instance_cards = COALESCE(json_extract(feature_flags, '$.compact_instance_cards'), FALSE), + show_play_time = COALESCE(json_extract(feature_flags, '$.show_instance_play_time'), TRUE), + warn_on_unknown_modpacks = NOT COALESCE(json_extract(feature_flags, '$.skip_unknown_pack_warning'), FALSE), + skip_non_essential_warnings = COALESCE(json_extract(feature_flags, '$.skip_non_essential_warnings'), FALSE), + show_jump_in = COALESCE(json_extract(feature_flags, '$.worlds_in_home'), TRUE), + always_show_copy_details = COALESCE(json_extract(feature_flags, '$.always_show_copy_details'), FALSE), + hide_installed_modpacks = COALESCE(json_extract(feature_flags, '$.hide_installed_modpacks'), FALSE), + advanced_filters_collapsed = COALESCE(json_extract(feature_flags, '$.advanced_filters_collapsed'), TRUE), + dismissed_photosensitivity_filter_warning = COALESCE(json_extract(feature_flags, '$.dismissed_photosensitivity_filter_warning'), FALSE), + friends_active_collapsed = COALESCE(json_extract(feature_flags, '$.friends_active_collapsed'), FALSE), + friends_online_collapsed = COALESCE(json_extract(feature_flags, '$.friends_online_collapsed'), FALSE), + friends_offline_collapsed = COALESCE(json_extract(feature_flags, '$.friends_offline_collapsed'), TRUE), + friends_pending_collapsed = COALESCE(json_extract(feature_flags, '$.friends_pending_collapsed'), TRUE), + feature_flags = json_remove( + feature_flags, + '$.refocus_on_game_close', + '$.compact_instance_cards', + '$.show_instance_play_time', + '$.skip_unknown_pack_warning', + '$.skip_non_essential_warnings', + '$.worlds_in_home', + '$.always_show_copy_details', + '$.hide_installed_modpacks', + '$.advanced_filters_collapsed', + '$.dismissed_photosensitivity_filter_warning', + '$.friends_active_collapsed', + '$.friends_online_collapsed', + '$.friends_offline_collapsed', + '$.friends_pending_collapsed' + ); diff --git a/packages/app-lib/src/state/process.rs b/packages/app-lib/src/state/process.rs index fb098423ea6..45471b9f861 100644 --- a/packages/app-lib/src/state/process.rs +++ b/packages/app-lib/src/state/process.rs @@ -988,11 +988,13 @@ impl Process { let _ = state.friends_socket.update_status(None).await; - // If in tauri, window should show itself again after process exists if it was hidden #[cfg(feature = "tauri")] { - let window = crate::EventState::get_main_window().await?; - if let Some(window) = window { + let settings = crate::state::Settings::get(&state.pool).await?; + if settings.refocus_on_game_close + && let Some(window) = + crate::EventState::get_main_window().await? + { window.unminimize()?; window.set_focus()?; } diff --git a/packages/app-lib/src/state/settings.rs b/packages/app-lib/src/state/settings.rs index 20601b8d02f..47490ad1996 100644 --- a/packages/app-lib/src/state/settings.rs +++ b/packages/app-lib/src/state/settings.rs @@ -32,6 +32,25 @@ pub struct Settings { #[serde(default = "default_true")] pub show_skin_selector_in_sidebar: bool, + #[serde(default = "default_true")] + pub show_jump_in: bool, + #[serde(default)] + pub always_show_copy_details: bool, + #[serde(default)] + pub hide_installed_modpacks: bool, + #[serde(default = "default_true")] + pub advanced_filters_collapsed: bool, + #[serde(default)] + pub dismissed_photosensitivity_filter_warning: bool, + #[serde(default)] + pub friends_active_collapsed: bool, + #[serde(default)] + pub friends_online_collapsed: bool, + #[serde(default = "default_true")] + pub friends_offline_collapsed: bool, + #[serde(default = "default_true")] + pub friends_pending_collapsed: bool, + pub telemetry: bool, pub discord_rpc: bool, pub personalized_ads: bool, @@ -42,6 +61,16 @@ pub struct Settings { pub force_fullscreen: bool, pub game_resolution: WindowSize, pub hide_on_process_start: bool, + #[serde(default)] + pub refocus_on_game_close: bool, + #[serde(default)] + pub compact_instance_cards: bool, + #[serde(default = "default_true")] + pub show_play_time: bool, + #[serde(default = "default_true")] + pub warn_on_unknown_modpacks: bool, + #[serde(default)] + pub skip_non_essential_warnings: bool, pub hooks: Hooks, pub custom_dir: Option, @@ -67,26 +96,13 @@ fn default_true() -> bool { pub enum FeatureFlag { PagePath, ProjectBackground, - WorldsInHome, ServerRamAsBytesAlwaysOn, AlwaysShowAppControls, ShowSyncInstancesUpdateModal, - SkipUnknownPackWarning, PrideFundraiser, ServersInApp, ServerProjectQa, I18nDebug, - ShowInstancePlayTime, - CompactInstanceCards, - SkipNonEssentialWarnings, - AdvancedFiltersCollapsed, - AlwaysShowCopyDetails, - HideInstalledModpacks, - FriendsActiveCollapsed, - FriendsOnlineCollapsed, - FriendsOfflineCollapsed, - FriendsPendingCollapsed, - DismissedPhotosensitivityFilterWarning, LocalhostSignIn, } @@ -110,6 +126,16 @@ impl Settings { sync_theme_across_devices, sync_behavior_across_devices, sync_features_across_devices, show_files_tab_in_instances, show_worlds_tab_in_instances, show_screenshots_tab_in_instances, show_skin_selector_in_sidebar, + refocus_on_game_close, compact_instance_cards, show_play_time, warn_on_unknown_modpacks, skip_non_essential_warnings, + show_jump_in, + always_show_copy_details, + hide_installed_modpacks, + advanced_filters_collapsed, + dismissed_photosensitivity_filter_warning, + friends_active_collapsed, + friends_online_collapsed, + friends_offline_collapsed, + friends_pending_collapsed, version FROM settings " @@ -128,6 +154,17 @@ impl Settings { advanced_rendering: res.advanced_rendering == 1, native_decorations: res.native_decorations == 1, toggle_sidebar: res.toggle_sidebar == 1, + show_jump_in: res.show_jump_in == 1, + always_show_copy_details: res.always_show_copy_details == 1, + hide_installed_modpacks: res.hide_installed_modpacks == 1, + advanced_filters_collapsed: res.advanced_filters_collapsed == 1, + dismissed_photosensitivity_filter_warning: res + .dismissed_photosensitivity_filter_warning + == 1, + friends_active_collapsed: res.friends_active_collapsed == 1, + friends_online_collapsed: res.friends_online_collapsed == 1, + friends_offline_collapsed: res.friends_offline_collapsed == 1, + friends_pending_collapsed: res.friends_pending_collapsed == 1, telemetry: res.telemetry == 1, discord_rpc: res.discord_rpc == 1, developer_mode: res.developer_mode == 1, @@ -151,6 +188,11 @@ impl Settings { res.mc_game_resolution_y as u16, ), hide_on_process_start: res.hide_on_process_start == 1, + refocus_on_game_close: res.refocus_on_game_close == 1, + compact_instance_cards: res.compact_instance_cards == 1, + show_play_time: res.show_play_time == 1, + warn_on_unknown_modpacks: res.warn_on_unknown_modpacks == 1, + skip_non_essential_warnings: res.skip_non_essential_warnings == 1, hooks: Hooks { pre_launch: res.hook_pre_launch, wrapper: res.hook_wrapper, @@ -246,7 +288,21 @@ impl Settings { show_screenshots_tab_in_instances = $37, show_skin_selector_in_sidebar = $38, - version = $39 + version = $39, + refocus_on_game_close = $40, + compact_instance_cards = $41, + show_play_time = $42, + warn_on_unknown_modpacks = $43, + skip_non_essential_warnings = $44, + show_jump_in = $45, + always_show_copy_details = $46, + hide_installed_modpacks = $47, + advanced_filters_collapsed = $48, + dismissed_photosensitivity_filter_warning = $49, + friends_active_collapsed = $50, + friends_online_collapsed = $51, + friends_offline_collapsed = $52, + friends_pending_collapsed = $53 ", max_concurrent_writes, max_concurrent_downloads, @@ -287,6 +343,20 @@ impl Settings { self.show_screenshots_tab_in_instances, self.show_skin_selector_in_sidebar, version, + self.refocus_on_game_close, + self.compact_instance_cards, + self.show_play_time, + self.warn_on_unknown_modpacks, + self.skip_non_essential_warnings, + self.show_jump_in, + self.always_show_copy_details, + self.hide_installed_modpacks, + self.advanced_filters_collapsed, + self.dismissed_photosensitivity_filter_warning, + self.friends_active_collapsed, + self.friends_online_collapsed, + self.friends_offline_collapsed, + self.friends_pending_collapsed, ) .execute(exec) .await?;