2019-01-24 16:43:03 +08:00
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
2018-04-13 17:19:50 +08:00
2022-06-17 15:37:17 +08:00
#nullable disable
2021-11-10 21:03:29 +08:00
using System ;
2022-02-25 04:11:49 +08:00
using System.Diagnostics ;
2024-01-04 13:30:46 +08:00
using System.Linq ;
2023-07-31 01:05:08 +08:00
using JetBrains.Annotations ;
2016-11-14 16:23:33 +08:00
using osu.Framework.Allocation ;
2023-11-08 21:13:35 +08:00
using osu.Framework.Audio ;
using osu.Framework.Audio.Sample ;
2019-02-21 18:04:31 +08:00
using osu.Framework.Bindables ;
2016-09-18 04:33:46 +08:00
using osu.Framework.Graphics ;
2023-07-14 18:19:14 +08:00
using osu.Framework.Graphics.Containers ;
2025-01-03 13:20:23 +08:00
using osu.Framework.Graphics.Sprites ;
2022-02-23 21:06:22 +08:00
using osu.Framework.Input.Bindings ;
using osu.Framework.Input.Events ;
2022-06-27 17:41:27 +08:00
using osu.Framework.Logging ;
2019-03-02 12:11:34 +08:00
using osu.Framework.Platform ;
2017-03-28 20:26:20 +08:00
using osu.Framework.Screens ;
2021-03-03 13:06:39 +08:00
using osu.Game.Beatmaps ;
2019-09-19 15:26:22 +08:00
using osu.Game.Configuration ;
2018-09-21 02:13:15 +08:00
using osu.Game.Graphics ;
2016-09-30 12:30:55 +08:00
using osu.Game.Graphics.Containers ;
2022-02-23 21:06:22 +08:00
using osu.Game.Input.Bindings ;
2020-07-06 21:03:09 +08:00
using osu.Game.IO ;
2019-09-08 13:36:58 +08:00
using osu.Game.Online.API ;
2019-05-15 11:08:23 +08:00
using osu.Game.Overlays ;
2024-01-04 13:30:46 +08:00
using osu.Game.Overlays.Dialog ;
2023-11-24 09:56:59 +08:00
using osu.Game.Overlays.SkinEditor ;
2024-12-16 14:18:39 +08:00
using osu.Game.Overlays.Volume ;
2021-03-03 13:06:39 +08:00
using osu.Game.Rulesets ;
2016-11-14 16:23:33 +08:00
using osu.Game.Screens.Backgrounds ;
2017-03-14 22:18:40 +08:00
using osu.Game.Screens.Edit ;
2024-05-30 20:15:44 +08:00
using osu.Game.Screens.OnlinePlay.DailyChallenge ;
2020-12-25 23:50:00 +08:00
using osu.Game.Screens.OnlinePlay.Multiplayer ;
using osu.Game.Screens.OnlinePlay.Playlists ;
2016-11-21 03:34:16 +08:00
using osu.Game.Screens.Select ;
2024-12-20 13:46:34 +08:00
using osu.Game.Seasonal ;
2021-05-19 15:27:38 +08:00
using osuTK ;
using osuTK.Graphics ;
2018-04-13 17:19:50 +08:00
2016-11-14 16:23:33 +08:00
namespace osu.Game.Screens.Menu
2016-08-26 11:28:23 +08:00
{
2022-02-23 21:06:22 +08:00
public partial class MainMenu : OsuScreen , IHandlePresentBeatmap , IKeyBindingHandler < GlobalAction >
2016-08-26 11:28:23 +08:00
{
2019-07-05 12:08:45 +08:00
public const float FADE_IN_DURATION = 300 ;
public const float FADE_OUT_DURATION = 400 ;
2018-04-13 17:19:50 +08:00
2022-04-19 14:46:03 +08:00
public override bool HideOverlaysOnEnter = > Buttons = = null | | Buttons . State = = ButtonSystemState . Initial ;
2018-04-13 17:19:50 +08:00
2024-11-27 05:50:23 +08:00
public override bool AllowUserExit = > false ;
2018-05-15 03:09:09 +08:00
2018-11-29 16:18:59 +08:00
public override bool AllowExternalScreenChange = > true ;
2024-01-08 19:54:16 +08:00
public override bool? AllowGlobalTrackControl = > true ;
2019-02-26 08:54:42 +08:00
private MenuSideFlashes sideFlashes ;
2018-04-13 17:19:50 +08:00
2022-04-19 14:46:03 +08:00
protected ButtonSystem Buttons ;
2019-07-05 12:08:45 +08:00
2019-02-25 09:42:36 +08:00
[Resolved]
private GameHost host { get ; set ; }
2018-04-13 17:19:50 +08:00
2023-06-21 18:06:47 +08:00
[Resolved]
private INotificationOverlay notifications { get ; set ; }
2020-08-11 11:40:58 +08:00
[Resolved]
2020-08-16 22:04:49 +08:00
private MusicController musicController { get ; set ; }
2019-07-09 17:32:49 +08:00
2019-09-08 13:36:58 +08:00
[Resolved]
private IAPIProvider api { get ; set ; }
2023-06-23 14:19:47 +08:00
[Resolved]
private Storage storage { get ; set ; }
[Resolved(canBeNull: true)]
private LoginOverlay login { get ; set ; }
2019-09-19 16:40:46 +08:00
[Resolved(canBeNull: true)]
2022-04-18 17:09:14 +08:00
private IDialogOverlay dialogOverlay { get ; set ; }
2019-09-19 15:26:22 +08:00
2022-07-08 01:00:02 +08:00
protected override BackgroundScreen CreateBackground ( ) = > new BackgroundScreenDefault ( ) ;
2018-04-13 17:19:50 +08:00
2022-06-15 12:04:08 +08:00
protected override bool PlayExitSound = > false ;
2022-03-04 11:21:05 +08:00
private Bindable < double > holdDelay ;
2019-09-25 20:56:47 +08:00
private Bindable < bool > loginDisplayed ;
2025-01-03 13:20:23 +08:00
private Bindable < bool > showMobileDisclaimer ;
2019-09-19 15:26:22 +08:00
2023-06-23 13:46:38 +08:00
private HoldToExitGameOverlay holdToExitGameOverlay ;
2019-09-19 19:17:58 +08:00
2023-06-21 18:06:47 +08:00
private bool exitConfirmedViaDialog ;
private bool exitConfirmedViaHoldOrClick ;
2020-01-11 12:08:00 +08:00
private ParallaxContainer buttonsContainer ;
2020-01-11 12:17:13 +08:00
private SongTicker songTicker ;
2023-07-14 18:19:14 +08:00
private Container logoTarget ;
2024-03-23 16:41:40 +08:00
private OnlineMenuBanner onlineMenuBanner ;
2023-12-28 15:05:20 +08:00
private MenuTip menuTip ;
private FillFlowContainer bottomElementsFlow ;
2023-12-28 16:14:16 +08:00
private SupporterDisplay supporterDisplay ;
2020-01-11 12:08:00 +08:00
2023-11-08 21:13:35 +08:00
private Sample reappearSampleSwoosh ;
2023-11-24 09:56:59 +08:00
[Resolved(canBeNull: true)]
private SkinEditorOverlay skinEditor { get ; set ; }
2019-02-26 08:54:42 +08:00
[BackgroundDependencyLoader(true)]
2023-11-08 21:13:35 +08:00
private void load ( BeatmapListingOverlay beatmapListing , SettingsOverlay settings , OsuConfigManager config , SessionStatics statics , AudioManager audio )
2016-11-01 22:24:14 +08:00
{
2022-03-04 11:21:05 +08:00
holdDelay = config . GetBindable < double > ( OsuSetting . UIHoldActivationDelay ) ;
2019-09-28 20:21:51 +08:00
loginDisplayed = statics . GetBindable < bool > ( Static . LoginOverlayDisplayed ) ;
2025-01-03 13:20:23 +08:00
showMobileDisclaimer = config . GetBindable < bool > ( OsuSetting . ShowMobileDisclaimer ) ;
2019-09-19 15:26:22 +08:00
2020-01-24 15:34:13 +08:00
if ( host . CanExit )
{
2023-06-23 13:46:38 +08:00
AddInternal ( holdToExitGameOverlay = new HoldToExitGameOverlay
2020-01-24 15:34:13 +08:00
{
Action = ( ) = >
{
2023-06-21 18:06:47 +08:00
exitConfirmedViaHoldOrClick = holdDelay . Value > 0 ;
this . Exit ( ) ;
2020-01-24 15:34:13 +08:00
}
} ) ;
}
AddRangeInternal ( new [ ]
2016-09-30 12:31:05 +08:00
{
2024-12-20 13:46:34 +08:00
SeasonalUIConfig . ENABLED ? new MainMenuSeasonalLighting ( ) : Empty ( ) ,
2024-12-16 14:18:39 +08:00
new GlobalScrollAdjustsVolume ( ) ,
2020-01-11 12:08:00 +08:00
buttonsContainer = new ParallaxContainer
2016-09-29 19:13:58 +08:00
{
2016-10-01 16:02:20 +08:00
ParallaxAmount = 0.01f ,
Children = new Drawable [ ]
{
2022-04-19 14:46:03 +08:00
Buttons = new ButtonSystem
2016-10-01 16:02:20 +08:00
{
2023-11-24 09:56:59 +08:00
OnEditBeatmap = ( ) = >
2020-08-24 18:38:05 +08:00
{
Beatmap . SetDefault ( ) ;
2021-09-05 22:59:28 +08:00
this . Push ( new EditorLoader ( ) ) ;
2020-08-24 18:38:05 +08:00
} ,
2023-11-24 09:56:59 +08:00
OnEditSkin = ( ) = >
{
skinEditor ? . Show ( ) ;
} ,
2021-03-03 13:06:39 +08:00
OnSolo = loadSoloSongSelect ,
2020-12-25 12:38:11 +08:00
OnMultiplayer = ( ) = > this . Push ( new Multiplayer ( ) ) ,
2020-12-25 22:45:44 +08:00
OnPlaylists = ( ) = > this . Push ( new Playlists ( ) ) ,
2024-05-17 16:39:24 +08:00
OnDailyChallenge = room = >
{
2024-08-21 02:35:26 +08:00
if ( statics . Get < bool > ( Static . DailyChallengeIntroPlayed ) )
this . Push ( new DailyChallenge ( room ) ) ;
else
this . Push ( new DailyChallengeIntro ( room ) ) ;
2024-05-17 16:39:24 +08:00
} ,
2024-11-13 18:27:20 +08:00
OnExit = e = >
2023-06-21 18:06:47 +08:00
{
2024-11-13 18:27:20 +08:00
exitConfirmedViaHoldOrClick = e is MouseEvent ;
2023-06-21 18:06:47 +08:00
this . Exit ( ) ;
}
2017-07-19 15:07:11 +08:00
}
2016-10-01 16:02:20 +08:00
}
2017-07-19 15:07:11 +08:00
} ,
2023-07-14 18:19:14 +08:00
logoTarget = new Container { RelativeSizeAxes = Axes . Both , } ,
2024-12-20 13:58:45 +08:00
sideFlashes = SeasonalUIConfig . ENABLED ? new SeasonalMenuSideFlashes ( ) : new MenuSideFlashes ( ) ,
2020-01-24 15:23:41 +08:00
songTicker = new SongTicker
{
Anchor = Anchor . TopRight ,
Origin = Anchor . TopRight ,
Margin = new MarginPadding { Right = 15 , Top = 5 }
2020-01-24 15:34:13 +08:00
} ,
2024-12-19 17:00:00 +08:00
// For now, this is too much alongside the seasonal lighting.
2024-12-20 13:46:34 +08:00
SeasonalUIConfig . ENABLED ? Empty ( ) : new KiaiMenuFountains ( ) ,
2023-12-28 15:05:20 +08:00
bottomElementsFlow = new FillFlowContainer
{
AutoSizeAxes = Axes . Both ,
Direction = FillDirection . Vertical ,
Anchor = Anchor . BottomCentre ,
Origin = Anchor . BottomCentre ,
2023-12-28 15:16:27 +08:00
Spacing = new Vector2 ( 5 ) ,
2023-12-28 15:05:20 +08:00
Children = new Drawable [ ]
{
menuTip = new MenuTip
{
Anchor = Anchor . TopCentre ,
Origin = Anchor . TopCentre ,
} ,
2024-03-23 16:41:40 +08:00
onlineMenuBanner = new OnlineMenuBanner
2023-12-28 15:05:20 +08:00
{
Anchor = Anchor . TopCentre ,
Origin = Anchor . TopCentre ,
}
}
} ,
2023-12-28 16:14:16 +08:00
supporterDisplay = new SupporterDisplay
{
Margin = new MarginPadding ( 5 ) ,
Anchor = Anchor . BottomLeft ,
Origin = Anchor . BottomLeft ,
} ,
2023-06-23 13:46:38 +08:00
holdToExitGameOverlay ? . CreateProxy ( ) ? ? Empty ( )
2019-02-26 08:54:42 +08:00
} ) ;
2018-09-21 02:13:15 +08:00
2024-12-24 16:10:48 +08:00
float baseDim = SeasonalUIConfig . ENABLED ? 0.84f : 1 ;
2022-04-19 14:46:03 +08:00
Buttons . StateChanged + = state = >
2018-09-21 02:13:15 +08:00
{
switch ( state )
{
case ButtonSystemState . Initial :
case ButtonSystemState . Exit :
2024-12-24 16:10:48 +08:00
ApplyToBackground ( b = > b . FadeColour ( OsuColour . Gray ( baseDim ) , 500 , Easing . OutSine ) ) ;
2024-03-23 16:41:40 +08:00
onlineMenuBanner . State . Value = Visibility . Hidden ;
2018-09-21 02:13:15 +08:00
break ;
2019-04-01 11:44:46 +08:00
2018-09-21 02:13:15 +08:00
default :
2024-12-24 16:10:48 +08:00
ApplyToBackground ( b = > b . FadeColour ( OsuColour . Gray ( baseDim * 0.8f ) , 500 , Easing . OutSine ) ) ;
2024-03-23 16:41:40 +08:00
onlineMenuBanner . State . Value = Visibility . Visible ;
2018-09-21 02:13:15 +08:00
break ;
}
} ;
2018-04-13 17:19:50 +08:00
2022-04-19 14:46:03 +08:00
Buttons . OnSettings = ( ) = > settings ? . ToggleVisibility ( ) ;
Buttons . OnBeatmapListing = ( ) = > beatmapListing ? . ToggleVisibility ( ) ;
2018-04-13 17:19:50 +08:00
2023-11-08 21:13:35 +08:00
reappearSampleSwoosh = audio . Samples . Get ( @"Menu/reappear-swoosh" ) ;
2017-03-17 19:09:33 +08:00
}
2018-04-13 17:19:50 +08:00
2022-05-19 15:42:43 +08:00
public void ReturnToOsuLogo ( ) = > Buttons . State = ButtonSystemState . Initial ;
2024-08-28 16:48:17 +08:00
private void loadSoloSongSelect ( ) = > this . Push ( new PlaySongSelect ( ) ) ;
2018-04-13 17:19:50 +08:00
2022-04-21 23:52:44 +08:00
public override void OnEntering ( ScreenTransitionEvent e )
2016-11-01 22:24:14 +08:00
{
2022-04-21 23:52:44 +08:00
base . OnEntering ( e ) ;
2022-04-19 14:46:03 +08:00
Buttons . FadeInFromZero ( 500 ) ;
2018-04-13 17:19:50 +08:00
2022-04-21 23:52:44 +08:00
if ( e . Last is IntroScreen & & musicController . TrackLoaded )
2017-04-25 12:33:34 +08:00
{
2021-02-18 14:01:11 +08:00
var track = musicController . CurrentTrack ;
// presume the track is the current beatmap's track. not sure how correct this assumption is but it has worked until now.
if ( ! track . IsRunning )
2017-04-23 13:36:23 +08:00
{
2022-08-17 12:20:24 +08:00
Beatmap . Value . PrepareTrackForPreview ( false ) ;
2021-02-18 14:01:11 +08:00
track . Restart ( ) ;
2017-05-23 15:26:51 +08:00
}
2017-04-25 12:33:34 +08:00
}
2020-07-06 21:03:09 +08:00
if ( storage is OsuStorage osuStorage & & osuStorage . Error ! = OsuStorageError . None )
dialogOverlay ? . Push ( new StorageErrorDialog ( osuStorage , osuStorage . Error ) ) ;
2017-07-19 12:32:16 +08:00
}
2018-04-13 17:19:50 +08:00
2023-07-31 01:05:08 +08:00
[CanBeNull]
private Drawable proxiedLogo ;
2017-11-09 16:38:20 +08:00
protected override void LogoArriving ( OsuLogo logo , bool resuming )
2017-11-01 19:54:58 +08:00
{
2017-11-09 16:38:20 +08:00
base . LogoArriving ( logo , resuming ) ;
2018-04-13 17:19:50 +08:00
2022-04-19 14:46:03 +08:00
Buttons . SetOsuLogo ( logo ) ;
2018-04-13 17:19:50 +08:00
2017-11-01 19:54:58 +08:00
logo . FadeColour ( Color4 . White , 100 , Easing . OutQuint ) ;
logo . FadeIn ( 100 , Easing . OutQuint ) ;
2018-04-13 17:19:50 +08:00
2023-07-31 01:05:08 +08:00
proxiedLogo = logo . ProxyToContainer ( logoTarget ) ;
2023-07-14 18:19:14 +08:00
2017-11-01 19:54:58 +08:00
if ( resuming )
2017-11-10 00:10:40 +08:00
{
2022-04-19 14:46:03 +08:00
Buttons . State = ButtonSystemState . TopLevel ;
2018-04-13 17:19:50 +08:00
2019-07-05 12:08:45 +08:00
this . FadeIn ( FADE_IN_DURATION , Easing . OutQuint ) ;
2020-01-11 12:08:00 +08:00
buttonsContainer . MoveTo ( new Vector2 ( 0 , 0 ) , FADE_IN_DURATION , Easing . OutQuint ) ;
2018-04-13 17:19:50 +08:00
2019-07-05 12:08:45 +08:00
sideFlashes . Delay ( FADE_IN_DURATION ) . FadeIn ( 64 , Easing . InQuint ) ;
2017-11-10 00:10:40 +08:00
}
2025-01-03 13:20:23 +08:00
else
2019-09-10 00:12:30 +08:00
{
2021-11-10 21:03:29 +08:00
// copy out old action to avoid accidentally capturing logo.Action in closure, causing a self-reference loop.
var previousAction = logo . Action ;
2025-01-03 13:20:23 +08:00
// we want to hook into logo.Action to display certain overlays, but also preserve the return value of the old action.
2021-11-10 21:03:29 +08:00
// therefore pass the old action to displayLogin, so that it can return that value.
// this ensures that the OsuLogo sample does not play when it is not desired.
2025-01-03 13:20:23 +08:00
logo . Action = ( ) = > onLogoClick ( previousAction ) ;
2019-09-10 00:17:58 +08:00
}
2025-01-03 13:20:23 +08:00
}
2019-09-10 00:17:58 +08:00
2025-01-03 13:20:23 +08:00
private bool onLogoClick ( Func < bool > originalAction )
{
if ( ! api . IsLoggedIn | | api . State . Value = = APIState . RequiresSecondFactorAuth )
2019-09-10 00:17:58 +08:00
{
2019-09-25 20:56:47 +08:00
if ( ! loginDisplayed . Value )
2019-09-10 00:12:30 +08:00
{
2025-01-03 13:20:23 +08:00
this . Delay ( 500 ) . Schedule ( ( ) = > login ? . Show ( ) ) ;
2019-09-25 20:56:47 +08:00
loginDisplayed . Value = true ;
2019-09-10 00:17:58 +08:00
}
2025-01-03 13:20:23 +08:00
}
if ( showMobileDisclaimer . Value )
{
this . Delay ( 500 ) . Schedule ( ( ) = > dialogOverlay . Push ( new MobileDisclaimerDialog ( ) ) ) ;
showMobileDisclaimer . Value = false ;
}
return originalAction . Invoke ( ) ;
}
internal partial class MobileDisclaimerDialog : PopupDialog
{
public MobileDisclaimerDialog ( )
{
HeaderText = "Mobile disclaimer" ;
BodyText = "We're releasing this for your enjoyment, but PC is still our focus and mobile is hard to support.\n\nPlease bear with us as we continue to improve the experience!" ;
2019-09-10 00:17:58 +08:00
2025-01-03 13:20:23 +08:00
Icon = FontAwesome . Solid . Mobile ;
Buttons = new PopupDialogButton [ ]
{
new PopupDialogOkButton
{
Text = "Alright!" ,
} ,
} ;
2019-09-10 00:12:30 +08:00
}
2017-11-01 19:54:58 +08:00
}
2018-04-13 17:19:50 +08:00
2017-11-09 16:38:20 +08:00
protected override void LogoSuspending ( OsuLogo logo )
2017-11-01 19:54:58 +08:00
{
2019-05-15 18:39:36 +08:00
var seq = logo . FadeOut ( 300 , Easing . InSine )
. ScaleTo ( 0.2f , 300 , Easing . InSine ) ;
2023-07-31 01:05:08 +08:00
if ( proxiedLogo ! = null )
{
logo . ReturnProxy ( ) ;
proxiedLogo = null ;
}
2023-07-14 18:19:14 +08:00
2022-04-19 14:46:03 +08:00
seq . OnComplete ( _ = > Buttons . SetOsuLogo ( null ) ) ;
seq . OnAbort ( _ = > Buttons . SetOsuLogo ( null ) ) ;
2017-11-01 19:54:58 +08:00
}
2018-04-13 17:19:50 +08:00
2023-07-31 01:05:08 +08:00
protected override void LogoExiting ( OsuLogo logo )
{
base . LogoExiting ( logo ) ;
if ( proxiedLogo ! = null )
{
logo . ReturnProxy ( ) ;
proxiedLogo = null ;
}
}
2022-04-21 23:52:44 +08:00
public override void OnSuspending ( ScreenTransitionEvent e )
2016-10-01 16:01:29 +08:00
{
2022-04-21 23:52:44 +08:00
base . OnSuspending ( e ) ;
2018-04-13 17:19:50 +08:00
2022-04-19 14:46:03 +08:00
Buttons . State = ButtonSystemState . EnteringMode ;
2018-04-13 17:19:50 +08:00
2019-07-05 12:08:45 +08:00
this . FadeOut ( FADE_OUT_DURATION , Easing . InSine ) ;
2020-01-11 12:08:00 +08:00
buttonsContainer . MoveTo ( new Vector2 ( - 800 , 0 ) , FADE_OUT_DURATION , Easing . InSine ) ;
2018-04-13 17:19:50 +08:00
2017-11-10 00:10:40 +08:00
sideFlashes . FadeOut ( 64 , Easing . OutQuint ) ;
2023-12-28 15:05:20 +08:00
bottomElementsFlow
. ScaleTo ( 0.9f , 1000 , Easing . OutQuint )
. FadeOut ( 500 , Easing . OutQuint ) ;
2023-12-28 16:14:16 +08:00
supporterDisplay
. FadeOut ( 500 , Easing . OutQuint ) ;
2016-10-01 16:01:29 +08:00
}
2018-04-13 17:19:50 +08:00
2022-04-21 23:52:44 +08:00
public override void OnResuming ( ScreenTransitionEvent e )
2016-10-01 16:01:29 +08:00
{
2022-04-21 23:52:44 +08:00
base . OnResuming ( e ) ;
2020-01-11 23:27:22 +08:00
2023-11-08 21:18:33 +08:00
// Ensures any playing `ButtonSystem` samples are stopped when returning to MainMenu (as to not overlap with the 'back' sample)
Buttons . StopSamplePlayback ( ) ;
2023-11-08 21:13:35 +08:00
reappearSampleSwoosh ? . Play ( ) ;
2021-01-04 17:32:23 +08:00
ApplyToBackground ( b = > ( b as BackgroundScreenDefault ) ? . Next ( ) ) ;
2018-04-13 17:19:50 +08:00
2020-08-16 22:04:49 +08:00
musicController . EnsurePlayingSomething ( ) ;
2023-12-28 15:05:20 +08:00
2023-12-28 15:19:12 +08:00
// Cycle tip on resuming
2023-12-28 15:05:20 +08:00
menuTip . ShowNextTip ( ) ;
bottomElementsFlow
. ScaleTo ( 1 , 1000 , Easing . OutQuint )
. FadeIn ( 1000 , Easing . OutQuint ) ;
2016-10-01 16:01:29 +08:00
}
2018-04-13 17:19:50 +08:00
2022-04-21 23:52:44 +08:00
public override bool OnExiting ( ScreenExitEvent e )
2016-12-05 18:34:52 +08:00
{
2023-06-21 18:06:47 +08:00
bool requiresConfirmation =
// we need to have a dialog overlay to confirm in the first place.
dialogOverlay ! = null
// if the dialog has already displayed and been accepted by the user, we are good.
& & ! exitConfirmedViaDialog
// Only require confirmation if there is either an ongoing operation or the user exited via a non-hold escape press.
& & ( notifications . HasOngoingOperations | | ! exitConfirmedViaHoldOrClick ) ;
if ( requiresConfirmation )
2019-09-19 15:26:22 +08:00
{
2019-12-22 21:39:25 +08:00
if ( dialogOverlay . CurrentDialog is ConfirmExitDialog exitDialog )
2024-01-04 13:30:46 +08:00
{
if ( exitDialog . Buttons . OfType < PopupDialogOkButton > ( ) . FirstOrDefault ( ) ! = null )
exitDialog . PerformOkAction ( ) ;
else
exitDialog . Flash ( ) ;
}
2019-12-22 21:39:25 +08:00
else
2023-06-21 18:06:47 +08:00
{
dialogOverlay . Push ( new ConfirmExitDialog ( ( ) = >
{
exitConfirmedViaDialog = true ;
this . Exit ( ) ;
} , ( ) = >
{
2023-06-23 13:46:38 +08:00
holdToExitGameOverlay . Abort ( ) ;
2023-06-21 18:06:47 +08:00
} ) ) ;
}
2021-05-19 15:27:38 +08:00
return true ;
2019-12-22 20:52:00 +08:00
}
2022-04-19 14:46:03 +08:00
Buttons . State = ButtonSystemState . Exit ;
2020-08-28 15:55:14 +08:00
OverlayActivationMode . Value = OverlayActivation . Disabled ;
2020-01-24 15:23:41 +08:00
2020-01-11 12:17:13 +08:00
songTicker . Hide ( ) ;
2020-01-24 15:23:41 +08:00
this . FadeOut ( 3000 ) ;
2023-12-28 16:19:41 +08:00
bottomElementsFlow
. FadeOut ( 500 , Easing . OutQuint ) ;
2023-12-28 16:14:16 +08:00
supporterDisplay
. FadeOut ( 500 , Easing . OutQuint ) ;
2023-12-28 16:19:41 +08:00
2022-04-21 23:52:44 +08:00
return base . OnExiting ( e ) ;
2016-12-05 18:34:52 +08:00
}
2021-03-03 13:06:39 +08:00
public void PresentBeatmap ( WorkingBeatmap beatmap , RulesetInfo ruleset )
{
2022-06-27 17:41:27 +08:00
Logger . Log ( $"{nameof(MainMenu)} completing {nameof(PresentBeatmap)} with beatmap {beatmap} ruleset {ruleset}" ) ;
2021-03-03 13:06:39 +08:00
Beatmap . Value = beatmap ;
Ruleset . Value = ruleset ;
Schedule ( loadSoloSongSelect ) ;
}
2022-02-23 21:06:22 +08:00
public bool OnPressed ( KeyBindingPressEvent < GlobalAction > e )
{
if ( e . Repeat )
return false ;
2022-02-25 04:11:49 +08:00
switch ( e . Action )
2022-02-23 21:06:22 +08:00
{
2022-02-25 04:11:49 +08:00
case GlobalAction . Back :
// In the case of a host being able to exit, the back action is handled by ExitConfirmOverlay.
Debug . Assert ( ! host . CanExit ) ;
return host . SuspendToBackground ( ) ;
2022-02-23 21:06:22 +08:00
}
return false ;
}
public void OnReleased ( KeyBindingReleaseEvent < GlobalAction > e )
{
}
2016-08-26 11:28:23 +08:00
}
}