mirror of
https://github.com/ppy/osu.git
synced 2024-11-11 11:20:04 +08:00
Simplify skin bindable flow
Now, nothing touches the configuration apart from `OsuGame`, making everything else flow better and avoid weird cyclic set bugs. Closes https://github.com/ppy/osu/issues/20234.
This commit is contained in:
parent
cb6d02ec3a
commit
f31deaef7c
@ -56,14 +56,12 @@ using osu.Game.Screens.Menu;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Screens.Ranking;
|
||||
using osu.Game.Screens.Select;
|
||||
using osu.Game.Skinning;
|
||||
using osu.Game.Skinning.Editor;
|
||||
using osu.Game.Updater;
|
||||
using osu.Game.Users;
|
||||
using osu.Game.Utils;
|
||||
using osuTK.Graphics;
|
||||
using Sentry;
|
||||
using Logger = osu.Framework.Logging.Logger;
|
||||
|
||||
namespace osu.Game
|
||||
{
|
||||
@ -294,25 +292,13 @@ namespace osu.Game
|
||||
|
||||
Ruleset.ValueChanged += r => configRuleset.Value = r.NewValue.ShortName;
|
||||
|
||||
// bind config int to database SkinInfo
|
||||
configSkin = LocalConfig.GetBindable<string>(OsuSetting.Skin);
|
||||
|
||||
// Transfer skin from config to realm instance once on startup.
|
||||
SkinManager.SetSkinFromConfiguration(configSkin.Value);
|
||||
|
||||
// Transfer any runtime changes back to configuration file.
|
||||
SkinManager.CurrentSkinInfo.ValueChanged += skin => configSkin.Value = skin.NewValue.ID.ToString();
|
||||
configSkin.ValueChanged += skinId =>
|
||||
{
|
||||
Live<SkinInfo> skinInfo = null;
|
||||
|
||||
if (Guid.TryParse(skinId.NewValue, out var guid))
|
||||
skinInfo = SkinManager.Query(s => s.ID == guid);
|
||||
|
||||
if (skinInfo == null)
|
||||
{
|
||||
if (guid == SkinInfo.CLASSIC_SKIN)
|
||||
skinInfo = DefaultLegacySkin.CreateInfo().ToLiveUnmanaged();
|
||||
}
|
||||
|
||||
SkinManager.CurrentSkinInfo.Value = skinInfo ?? DefaultSkin.CreateInfo().ToLiveUnmanaged();
|
||||
};
|
||||
configSkin.TriggerChange();
|
||||
|
||||
IsActive.BindValueChanged(active => updateActiveState(active.NewValue), true);
|
||||
|
||||
|
@ -14,7 +14,6 @@ using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Localisation;
|
||||
@ -36,9 +35,6 @@ namespace osu.Game.Overlays.Settings.Sections
|
||||
Icon = FontAwesome.Solid.PaintBrush
|
||||
};
|
||||
|
||||
private readonly Bindable<Live<SkinInfo>> dropdownBindable = new Bindable<Live<SkinInfo>> { Default = DefaultSkin.CreateInfo().ToLiveUnmanaged() };
|
||||
private readonly Bindable<string> configBindable = new Bindable<string>();
|
||||
|
||||
private static readonly Live<SkinInfo> random_skin_info = new SkinInfo
|
||||
{
|
||||
ID = SkinInfo.RANDOM_SKIN,
|
||||
@ -56,13 +52,14 @@ namespace osu.Game.Overlays.Settings.Sections
|
||||
private IDisposable realmSubscription;
|
||||
|
||||
[BackgroundDependencyLoader(permitNulls: true)]
|
||||
private void load(OsuConfigManager config, [CanBeNull] SkinEditorOverlay skinEditor)
|
||||
private void load([CanBeNull] SkinEditorOverlay skinEditor)
|
||||
{
|
||||
Children = new Drawable[]
|
||||
{
|
||||
skinDropdown = new SkinSettingsDropdown
|
||||
{
|
||||
LabelText = SkinSettingsStrings.CurrentSkin,
|
||||
Current = skins.CurrentSkinInfo,
|
||||
Keywords = new[] { @"skins" }
|
||||
},
|
||||
new SettingsButton
|
||||
@ -73,47 +70,30 @@ namespace osu.Game.Overlays.Settings.Sections
|
||||
new ExportSkinButton(),
|
||||
new DeleteSkinButton(),
|
||||
};
|
||||
|
||||
config.BindWith(OsuSetting.Skin, configBindable);
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
skinDropdown.Current = dropdownBindable;
|
||||
skinDropdown.Current = skins.CurrentSkinInfo;
|
||||
|
||||
realmSubscription = realm.RegisterForNotifications(_ => realm.Realm.All<SkinInfo>()
|
||||
.Where(s => !s.DeletePending)
|
||||
.OrderByDescending(s => s.Protected) // protected skins should be at the top.
|
||||
.ThenBy(s => s.Name, StringComparer.OrdinalIgnoreCase), skinsChanged);
|
||||
|
||||
configBindable.BindValueChanged(_ => Scheduler.AddOnce(updateSelectedSkinFromConfig));
|
||||
|
||||
dropdownBindable.BindValueChanged(dropdownSelectionChanged);
|
||||
}
|
||||
|
||||
private void dropdownSelectionChanged(ValueChangedEvent<Live<SkinInfo>> skin)
|
||||
{
|
||||
// Only handle cases where it's clear the user has intent to change skins.
|
||||
if (skin.OldValue == null) return;
|
||||
|
||||
if (skin.NewValue.Equals(random_skin_info))
|
||||
skinDropdown.Current.BindValueChanged(skin =>
|
||||
{
|
||||
var skinBefore = skins.CurrentSkinInfo.Value;
|
||||
|
||||
skins.SelectRandomSkin();
|
||||
|
||||
if (skinBefore == skins.CurrentSkinInfo.Value)
|
||||
if (skin.NewValue == random_skin_info)
|
||||
{
|
||||
// the random selection didn't change the skin, so we should manually update the dropdown to match.
|
||||
dropdownBindable.Value = skins.CurrentSkinInfo.Value;
|
||||
// before selecting random, set the skin back to the previous selection.
|
||||
// this is done because at this point it will be random_skin_info, and would
|
||||
// cause SelectRandomSkin to be unable to skip the previous selection.
|
||||
skins.CurrentSkinInfo.Value = skin.OldValue;
|
||||
skins.SelectRandomSkin();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
configBindable.Value = skin.NewValue.ID.ToString();
|
||||
});
|
||||
}
|
||||
|
||||
private void skinsChanged(IRealmCollection<SkinInfo> sender, ChangeSet changes, Exception error)
|
||||
@ -132,25 +112,7 @@ namespace osu.Game.Overlays.Settings.Sections
|
||||
dropdownItems.Add(skin.ToLive(realm));
|
||||
dropdownItems.Insert(protectedCount, random_skin_info);
|
||||
|
||||
Schedule(() =>
|
||||
{
|
||||
skinDropdown.Items = dropdownItems;
|
||||
|
||||
updateSelectedSkinFromConfig();
|
||||
});
|
||||
}
|
||||
|
||||
private void updateSelectedSkinFromConfig()
|
||||
{
|
||||
if (!skinDropdown.Items.Any())
|
||||
return;
|
||||
|
||||
Live<SkinInfo> skin = null;
|
||||
|
||||
if (Guid.TryParse(configBindable.Value, out var configId))
|
||||
skin = skinDropdown.Items.FirstOrDefault(s => s.ID == configId);
|
||||
|
||||
dropdownBindable.Value = skin ?? skinDropdown.Items.First();
|
||||
Schedule(() => skinDropdown.Items = dropdownItems);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
|
@ -119,7 +119,9 @@ namespace osu.Game.Skinning
|
||||
Realm.Run(r =>
|
||||
{
|
||||
// choose from only user skins, removing the current selection to ensure a new one is chosen.
|
||||
var randomChoices = r.All<SkinInfo>().Where(s => !s.DeletePending && s.ID != CurrentSkinInfo.Value.ID).ToArray();
|
||||
var randomChoices = r.All<SkinInfo>()
|
||||
.Where(s => !s.DeletePending && s.ID != CurrentSkinInfo.Value.ID)
|
||||
.ToArray();
|
||||
|
||||
if (randomChoices.Length == 0)
|
||||
{
|
||||
@ -297,5 +299,21 @@ namespace osu.Game.Skinning
|
||||
Delete(items.ToList(), silent);
|
||||
});
|
||||
}
|
||||
|
||||
public void SetSkinFromConfiguration(string guidString)
|
||||
{
|
||||
Live<SkinInfo> skinInfo = null;
|
||||
|
||||
if (Guid.TryParse(guidString, out var guid))
|
||||
skinInfo = Query(s => s.ID == guid);
|
||||
|
||||
if (skinInfo == null)
|
||||
{
|
||||
if (guid == SkinInfo.CLASSIC_SKIN)
|
||||
skinInfo = DefaultLegacySkin.SkinInfo;
|
||||
}
|
||||
|
||||
CurrentSkinInfo.Value = skinInfo ?? DefaultSkin.SkinInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user