diff --git a/osu.Game/Overlays/SkinEditor/SkinEditor.cs b/osu.Game/Overlays/SkinEditor/SkinEditor.cs
index ad89057d12..4ef45b8df5 100644
--- a/osu.Game/Overlays/SkinEditor/SkinEditor.cs
+++ b/osu.Game/Overlays/SkinEditor/SkinEditor.cs
@@ -125,7 +125,7 @@ namespace osu.Game.Overlays.SkinEditor
{
Items = new[]
{
- new EditorMenuItem(Resources.Localisation.Web.CommonStrings.ButtonsSave, MenuItemType.Standard, Save),
+ new EditorMenuItem(Resources.Localisation.Web.CommonStrings.ButtonsSave, MenuItemType.Standard, () => Save()),
new EditorMenuItem(CommonStrings.RevertToDefault, MenuItemType.Destructive, revert),
new EditorMenuItemSpacer(),
new EditorMenuItem(CommonStrings.Exit, MenuItemType.Standard, () => skinEditorOverlay?.Hide()),
@@ -333,7 +333,7 @@ namespace osu.Game.Overlays.SkinEditor
}
}
- public void Save()
+ public void Save(bool userTriggered = true)
{
if (!hasBegunMutating)
return;
@@ -343,8 +343,9 @@ namespace osu.Game.Overlays.SkinEditor
foreach (var t in targetContainers)
currentSkin.Value.UpdateDrawableTarget(t);
- skins.Save(skins.CurrentSkin.Value);
- onScreenDisplay?.Display(new SkinEditorToast(ToastStrings.SkinSaved, currentSkin.Value.SkinInfo.ToString() ?? "Unknown"));
+ // In the case the save was user triggered, always show the save message to make them feel confident.
+ if (skins.Save(skins.CurrentSkin.Value) || userTriggered)
+ onScreenDisplay?.Display(new SkinEditorToast(ToastStrings.SkinSaved, currentSkin.Value.SkinInfo.ToString() ?? "Unknown"));
}
protected override bool OnHover(HoverEvent e) => true;
diff --git a/osu.Game/Overlays/SkinEditor/SkinEditorOverlay.cs b/osu.Game/Overlays/SkinEditor/SkinEditorOverlay.cs
index 4eff87c5f4..b8da3e3f67 100644
--- a/osu.Game/Overlays/SkinEditor/SkinEditorOverlay.cs
+++ b/osu.Game/Overlays/SkinEditor/SkinEditorOverlay.cs
@@ -147,7 +147,7 @@ namespace osu.Game.Overlays.SkinEditor
if (skinEditor == null) return;
- skinEditor.Save();
+ skinEditor.Save(false);
// ensure the toolbar is re-hidden even if a new screen decides to try and show it.
updateComponentVisibility();
diff --git a/osu.Game/Skinning/SkinImporter.cs b/osu.Game/Skinning/SkinImporter.cs
index 1685562cc7..7485a89404 100644
--- a/osu.Game/Skinning/SkinImporter.cs
+++ b/osu.Game/Skinning/SkinImporter.cs
@@ -179,8 +179,14 @@ namespace osu.Game.Skinning
private Skin createInstance(SkinInfo item) => item.CreateInstance(skinResources);
- public void Save(Skin skin)
+ ///
+ /// Save a skin. Updates any drawable layouts that are out of date.
+ ///
+ /// Whether any change actually occurred.
+ public bool Save(Skin skin)
{
+ bool hadChanges = false;
+
skin.SkinInfo.PerformWrite(s =>
{
// Update for safety
@@ -212,8 +218,14 @@ namespace osu.Game.Skinning
}
}
- s.Hash = ComputeHash(s);
+ string newHash = ComputeHash(s);
+
+ hadChanges = newHash != s.Hash;
+
+ s.Hash = newHash;
});
+
+ return hadChanges;
}
}
}
diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs
index a4cf83b32e..70173d9c2a 100644
--- a/osu.Game/Skinning/SkinManager.cs
+++ b/osu.Game/Skinning/SkinManager.cs
@@ -192,12 +192,16 @@ namespace osu.Game.Skinning
});
}
- public void Save(Skin skin)
+ ///
+ /// Save a skin. Updates any drawable layouts that are out of date.
+ ///
+ /// Whether any change actually occurred.
+ public bool Save(Skin skin)
{
if (!skin.SkinInfo.IsManaged)
throw new InvalidOperationException($"Attempting to save a skin which is not yet tracked. Call {nameof(EnsureMutableSkin)} first.");
- skinImporter.Save(skin);
+ return skinImporter.Save(skin);
}
///