From 25b37f3c548fbbc93a48ea32ec52824fb4c3277f Mon Sep 17 00:00:00 2001 From: ZackWilde27 Date: Fri, 24 Oct 2025 21:05:53 -0600 Subject: [PATCH 1/7] Added even more themes There's now Violet, Teal, and Monochrome to go along with the colours added previously, but I also got more creative and made some totally new designs There's now 2 metallic themes, Metallic_Silver and Metallic_Default I also added a recreation of Windows XP's Luna theme as a bonus --- source/Reloaded.Mod.Launcher/Theme/Luna.xaml | 53 + .../Theme/Luna/Colours.xaml | 78 + .../Theme/Luna/Controls.xaml | 229 +++ .../Theme/Luna/CustomStyles.xaml | 61 + .../Theme/Luna/Images.xaml | 19 + .../Theme/Luna/Images/IconAddApp.png | Bin 0 -> 5202 bytes .../Theme/Luna/Images/IconDiscord.png | Bin 0 -> 9963 bytes .../Theme/Luna/Images/IconDownloadMods.png | Bin 0 -> 11699 bytes .../Theme/Luna/Images/IconGitHub.png | Bin 0 -> 9981 bytes .../Theme/Luna/Images/IconInfo.png | Bin 0 -> 9560 bytes .../Theme/Luna/Images/IconMods.png | Bin 0 -> 7625 bytes .../Theme/Luna/Images/IconSearch.png | Bin 0 -> 6981 bytes .../Theme/Luna/Images/IconSettings.png | Bin 0 -> 8587 bytes .../Theme/Luna/Images/IconSponsor.png | Bin 0 -> 6372 bytes .../Theme/Luna/Images/IconTwitter.png | Bin 0 -> 8471 bytes .../Theme/Luna/Images/ModPlaceholder.png | Bin 0 -> 79448 bytes .../Theme/Luna/Images/ReloadedNoBrackets.png | Bin 0 -> 269027 bytes .../Theme/Luna/Images/bliss.jpg | Bin 0 -> 1283705 bytes .../Theme/Luna/Styles.xaml | 1645 +++++++++++++++++ .../Theme/Metallic_Default.xaml | 53 + .../Theme/Metallic_Default/Colours.xaml | 58 + .../Theme/Metallic_Default/Controls.xaml | 229 +++ .../Theme/Metallic_Default/CustomStyles.xaml | 61 + .../Theme/Metallic_Default/Images.xaml | 19 + .../Metallic_Default/Images/IconAddApp.png | Bin 0 -> 1051394 bytes .../Metallic_Default/Images/IconDiscord.png | Bin 0 -> 1051394 bytes .../Images/IconDownloadMods.png | Bin 0 -> 1051394 bytes .../Metallic_Default/Images/IconGitHub.png | Bin 0 -> 1051394 bytes .../Metallic_Default/Images/IconInfo.png | Bin 0 -> 1051394 bytes .../Metallic_Default/Images/IconMods.png | Bin 0 -> 1051394 bytes .../Metallic_Default/Images/IconSearch.png | Bin 0 -> 1051394 bytes .../Metallic_Default/Images/IconSettings.png | Bin 0 -> 1051394 bytes .../Metallic_Default/Images/IconSponsor.png | Bin 0 -> 1051394 bytes .../Metallic_Default/Images/IconTwitter.png | Bin 0 -> 1051394 bytes .../Images/ModPlaceholder.png | Bin 0 -> 79448 bytes .../Images/ReloadedNoBrackets.png | Bin 0 -> 3011939 bytes .../Theme/Metallic_Default/Styles.xaml | 1644 ++++++++++++++++ .../Theme/Metallic_Silver.xaml | 53 + .../Theme/Metallic_Silver/Colours.xaml | 73 + .../Theme/Metallic_Silver/Controls.xaml | 229 +++ .../Theme/Metallic_Silver/CustomStyles.xaml | 61 + .../Theme/Metallic_Silver/Images.xaml | 19 + .../Metallic_Silver/Images/IconAddApp.png | Bin 0 -> 1051394 bytes .../Metallic_Silver/Images/IconDiscord.png | Bin 0 -> 1051394 bytes .../Images/IconDownloadMods.png | Bin 0 -> 1051394 bytes .../Metallic_Silver/Images/IconGitHub.png | Bin 0 -> 1051394 bytes .../Theme/Metallic_Silver/Images/IconInfo.png | Bin 0 -> 1051394 bytes .../Theme/Metallic_Silver/Images/IconMods.png | Bin 0 -> 1051394 bytes .../Metallic_Silver/Images/IconSearch.png | Bin 0 -> 1051394 bytes .../Metallic_Silver/Images/IconSettings.png | Bin 0 -> 1051394 bytes .../Metallic_Silver/Images/IconSponsor.png | Bin 0 -> 1051394 bytes .../Metallic_Silver/Images/IconTwitter.png | Bin 0 -> 1051394 bytes .../Metallic_Silver/Images/ModPlaceholder.png | Bin 0 -> 79448 bytes .../Images/ReloadedNoBrackets.png | Bin 0 -> 546340 bytes .../Theme/Metallic_Silver/Styles.xaml | 1644 ++++++++++++++++ .../Theme/Monochrome.xaml | 53 + .../Theme/Monochrome/Colours.xaml | 34 + .../Theme/Monochrome/Controls.xaml | 229 +++ .../Theme/Monochrome/CustomStyles.xaml | 61 + .../Theme/Monochrome/Images.xaml | 19 + .../Theme/Monochrome/Images/IconAddApp.png | Bin 0 -> 19089 bytes .../Theme/Monochrome/Images/IconDiscord.png | Bin 0 -> 42645 bytes .../Monochrome/Images/IconDownloadMods.png | Bin 0 -> 35428 bytes .../Theme/Monochrome/Images/IconGitHub.png | Bin 0 -> 39373 bytes .../Theme/Monochrome/Images/IconInfo.png | Bin 0 -> 46520 bytes .../Theme/Monochrome/Images/IconMods.png | Bin 0 -> 61079 bytes .../Theme/Monochrome/Images/IconSearch.png | Bin 0 -> 42675 bytes .../Theme/Monochrome/Images/IconSettings.png | Bin 0 -> 49626 bytes .../Theme/Monochrome/Images/IconSponsor.png | Bin 0 -> 30052 bytes .../Theme/Monochrome/Images/IconTwitter.png | Bin 0 -> 33179 bytes .../Monochrome/Images/ModPlaceholder.png | Bin 0 -> 79448 bytes .../Monochrome/Images/ReloadedNoBrackets.png | Bin 0 -> 316267 bytes .../Theme/Monochrome/Styles.xaml | 1616 ++++++++++++++++ source/Reloaded.Mod.Launcher/Theme/Teal.xaml | 53 + .../Theme/Teal/Colours.xaml | 31 + .../Theme/Teal/Controls.xaml | 229 +++ .../Theme/Teal/CustomStyles.xaml | 62 + .../Theme/Teal/Images.xaml | 19 + .../Theme/Teal/Images/IconAddApp.png | Bin 0 -> 20476 bytes .../Theme/Teal/Images/IconDiscord.png | Bin 0 -> 45191 bytes .../Theme/Teal/Images/IconDownloadMods.png | Bin 0 -> 39968 bytes .../Theme/Teal/Images/IconGitHub.png | Bin 0 -> 40102 bytes .../Theme/Teal/Images/IconInfo.png | Bin 0 -> 49899 bytes .../Theme/Teal/Images/IconMods.png | Bin 0 -> 69772 bytes .../Theme/Teal/Images/IconSearch.png | Bin 0 -> 47289 bytes .../Theme/Teal/Images/IconSettings.png | Bin 0 -> 59264 bytes .../Theme/Teal/Images/IconSponsor.png | Bin 0 -> 31199 bytes .../Theme/Teal/Images/IconTwitter.png | Bin 0 -> 34116 bytes .../Theme/Teal/Images/ModPlaceholder.png | Bin 0 -> 79448 bytes .../Theme/Teal/Images/ReloadedNoBrackets.png | Bin 0 -> 306961 bytes .../Theme/Teal/Styles.xaml | 1616 ++++++++++++++++ .../Reloaded.Mod.Launcher/Theme/Violet.xaml | 53 + .../Theme/Violet/Colours.xaml | 34 + .../Theme/Violet/Controls.xaml | 229 +++ .../Theme/Violet/CustomStyles.xaml | 61 + .../Theme/Violet/Images.xaml | 19 + .../Theme/Violet/Images/IconAddApp.png | Bin 0 -> 20337 bytes .../Theme/Violet/Images/IconDiscord.png | Bin 0 -> 45463 bytes .../Theme/Violet/Images/IconDownloadMods.png | Bin 0 -> 40004 bytes .../Theme/Violet/Images/IconGitHub.png | Bin 0 -> 40308 bytes .../Theme/Violet/Images/IconInfo.png | Bin 0 -> 49983 bytes .../Theme/Violet/Images/IconMods.png | Bin 0 -> 70057 bytes .../Theme/Violet/Images/IconSearch.png | Bin 0 -> 47236 bytes .../Theme/Violet/Images/IconSettings.png | Bin 0 -> 59100 bytes .../Theme/Violet/Images/IconSponsor.png | Bin 0 -> 31405 bytes .../Theme/Violet/Images/IconTwitter.png | Bin 0 -> 34207 bytes .../Theme/Violet/Images/ModPlaceholder.png | Bin 0 -> 79448 bytes .../Violet/Images/ReloadedNoBrackets.png | Bin 0 -> 309773 bytes .../Theme/Violet/Styles.xaml | 1616 ++++++++++++++++ 109 files changed, 12262 insertions(+) create mode 100644 source/Reloaded.Mod.Launcher/Theme/Luna.xaml create mode 100644 source/Reloaded.Mod.Launcher/Theme/Luna/Colours.xaml create mode 100644 source/Reloaded.Mod.Launcher/Theme/Luna/Controls.xaml create mode 100644 source/Reloaded.Mod.Launcher/Theme/Luna/CustomStyles.xaml create mode 100644 source/Reloaded.Mod.Launcher/Theme/Luna/Images.xaml create mode 100644 source/Reloaded.Mod.Launcher/Theme/Luna/Images/IconAddApp.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Luna/Images/IconDiscord.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Luna/Images/IconDownloadMods.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Luna/Images/IconGitHub.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Luna/Images/IconInfo.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Luna/Images/IconMods.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Luna/Images/IconSearch.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Luna/Images/IconSettings.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Luna/Images/IconSponsor.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Luna/Images/IconTwitter.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Luna/Images/ModPlaceholder.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Luna/Images/ReloadedNoBrackets.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Luna/Images/bliss.jpg create mode 100644 source/Reloaded.Mod.Launcher/Theme/Luna/Styles.xaml create mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Default.xaml create mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Default/Colours.xaml create mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Default/Controls.xaml create mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Default/CustomStyles.xaml create mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Default/Images.xaml create mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Default/Images/IconAddApp.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Default/Images/IconDiscord.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Default/Images/IconDownloadMods.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Default/Images/IconGitHub.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Default/Images/IconInfo.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Default/Images/IconMods.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Default/Images/IconSearch.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Default/Images/IconSettings.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Default/Images/IconSponsor.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Default/Images/IconTwitter.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Default/Images/ModPlaceholder.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Default/Images/ReloadedNoBrackets.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Default/Styles.xaml create mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Silver.xaml create mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/Colours.xaml create mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/Controls.xaml create mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/CustomStyles.xaml create mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/Images.xaml create mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/Images/IconAddApp.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/Images/IconDiscord.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/Images/IconDownloadMods.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/Images/IconGitHub.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/Images/IconInfo.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/Images/IconMods.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/Images/IconSearch.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/Images/IconSettings.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/Images/IconSponsor.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/Images/IconTwitter.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/Images/ModPlaceholder.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/Images/ReloadedNoBrackets.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/Styles.xaml create mode 100644 source/Reloaded.Mod.Launcher/Theme/Monochrome.xaml create mode 100644 source/Reloaded.Mod.Launcher/Theme/Monochrome/Colours.xaml create mode 100644 source/Reloaded.Mod.Launcher/Theme/Monochrome/Controls.xaml create mode 100644 source/Reloaded.Mod.Launcher/Theme/Monochrome/CustomStyles.xaml create mode 100644 source/Reloaded.Mod.Launcher/Theme/Monochrome/Images.xaml create mode 100644 source/Reloaded.Mod.Launcher/Theme/Monochrome/Images/IconAddApp.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Monochrome/Images/IconDiscord.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Monochrome/Images/IconDownloadMods.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Monochrome/Images/IconGitHub.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Monochrome/Images/IconInfo.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Monochrome/Images/IconMods.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Monochrome/Images/IconSearch.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Monochrome/Images/IconSettings.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Monochrome/Images/IconSponsor.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Monochrome/Images/IconTwitter.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Monochrome/Images/ModPlaceholder.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Monochrome/Images/ReloadedNoBrackets.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Monochrome/Styles.xaml create mode 100644 source/Reloaded.Mod.Launcher/Theme/Teal.xaml create mode 100644 source/Reloaded.Mod.Launcher/Theme/Teal/Colours.xaml create mode 100644 source/Reloaded.Mod.Launcher/Theme/Teal/Controls.xaml create mode 100644 source/Reloaded.Mod.Launcher/Theme/Teal/CustomStyles.xaml create mode 100644 source/Reloaded.Mod.Launcher/Theme/Teal/Images.xaml create mode 100644 source/Reloaded.Mod.Launcher/Theme/Teal/Images/IconAddApp.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Teal/Images/IconDiscord.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Teal/Images/IconDownloadMods.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Teal/Images/IconGitHub.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Teal/Images/IconInfo.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Teal/Images/IconMods.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Teal/Images/IconSearch.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Teal/Images/IconSettings.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Teal/Images/IconSponsor.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Teal/Images/IconTwitter.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Teal/Images/ModPlaceholder.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Teal/Images/ReloadedNoBrackets.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Teal/Styles.xaml create mode 100644 source/Reloaded.Mod.Launcher/Theme/Violet.xaml create mode 100644 source/Reloaded.Mod.Launcher/Theme/Violet/Colours.xaml create mode 100644 source/Reloaded.Mod.Launcher/Theme/Violet/Controls.xaml create mode 100644 source/Reloaded.Mod.Launcher/Theme/Violet/CustomStyles.xaml create mode 100644 source/Reloaded.Mod.Launcher/Theme/Violet/Images.xaml create mode 100644 source/Reloaded.Mod.Launcher/Theme/Violet/Images/IconAddApp.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Violet/Images/IconDiscord.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Violet/Images/IconDownloadMods.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Violet/Images/IconGitHub.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Violet/Images/IconInfo.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Violet/Images/IconMods.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Violet/Images/IconSearch.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Violet/Images/IconSettings.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Violet/Images/IconSponsor.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Violet/Images/IconTwitter.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Violet/Images/ModPlaceholder.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Violet/Images/ReloadedNoBrackets.png create mode 100644 source/Reloaded.Mod.Launcher/Theme/Violet/Styles.xaml diff --git a/source/Reloaded.Mod.Launcher/Theme/Luna.xaml b/source/Reloaded.Mod.Launcher/Theme/Luna.xaml new file mode 100644 index 00000000..b318fa98 --- /dev/null +++ b/source/Reloaded.Mod.Launcher/Theme/Luna.xaml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Luna/Colours.xaml b/source/Reloaded.Mod.Launcher/Theme/Luna/Colours.xaml new file mode 100644 index 00000000..49b32b51 --- /dev/null +++ b/source/Reloaded.Mod.Launcher/Theme/Luna/Colours.xaml @@ -0,0 +1,78 @@ + + + + + + #b8c8ff + + + #8296d9 + + + #14286c + + + #17244f + + #191f34 + #101423 + #080a11 + + #245ADA + #4590F0 + #2963DD + #1246AD + + #90B8FF + #0445AF + + Transparent + #CCCCCC + + #DDDDDD + #b8c8ff + #b8c8ff + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Luna/Controls.xaml b/source/Reloaded.Mod.Launcher/Theme/Luna/Controls.xaml new file mode 100644 index 00000000..e2ef24fc --- /dev/null +++ b/source/Reloaded.Mod.Launcher/Theme/Luna/Controls.xaml @@ -0,0 +1,229 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Luna/CustomStyles.xaml b/source/Reloaded.Mod.Launcher/Theme/Luna/CustomStyles.xaml new file mode 100644 index 00000000..0e55a907 --- /dev/null +++ b/source/Reloaded.Mod.Launcher/Theme/Luna/CustomStyles.xaml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + None + + + + + + + + + + + + + + + + None + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Metallic_Default.xaml b/source/Reloaded.Mod.Launcher/Theme/Metallic_Default.xaml new file mode 100644 index 00000000..2c47246e --- /dev/null +++ b/source/Reloaded.Mod.Launcher/Theme/Metallic_Default.xaml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Metallic_Default/Colours.xaml b/source/Reloaded.Mod.Launcher/Theme/Metallic_Default/Colours.xaml new file mode 100644 index 00000000..2fb18172 --- /dev/null +++ b/source/Reloaded.Mod.Launcher/Theme/Metallic_Default/Colours.xaml @@ -0,0 +1,58 @@ + + + + #d6a8a8 + #B66363 + #793939 + #572929 + #452121 + #341818 + #231010 + + #572929 + #793939 + #000000 + #d6a8a8 + #452121 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Metallic_Default/Controls.xaml b/source/Reloaded.Mod.Launcher/Theme/Metallic_Default/Controls.xaml new file mode 100644 index 00000000..9d6e1715 --- /dev/null +++ b/source/Reloaded.Mod.Launcher/Theme/Metallic_Default/Controls.xaml @@ -0,0 +1,229 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Metallic_Default/CustomStyles.xaml b/source/Reloaded.Mod.Launcher/Theme/Metallic_Default/CustomStyles.xaml new file mode 100644 index 00000000..0fb98338 --- /dev/null +++ b/source/Reloaded.Mod.Launcher/Theme/Metallic_Default/CustomStyles.xaml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + None + + + + + + + + + + + + + + + + None + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Metallic_Silver.xaml b/source/Reloaded.Mod.Launcher/Theme/Metallic_Silver.xaml new file mode 100644 index 00000000..89249003 --- /dev/null +++ b/source/Reloaded.Mod.Launcher/Theme/Metallic_Silver.xaml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/Colours.xaml b/source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/Colours.xaml new file mode 100644 index 00000000..c27bff62 --- /dev/null +++ b/source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/Colours.xaml @@ -0,0 +1,73 @@ + + + + + + #9774be + + + #ffffff + + + #3d146c + + + #31174f + + #251934 + #191023 + #0c0811 + + #606057 + #888888 + #000000 + #D7D7D6 + #111111 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/Controls.xaml b/source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/Controls.xaml new file mode 100644 index 00000000..66fecc6f --- /dev/null +++ b/source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/Controls.xaml @@ -0,0 +1,229 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/CustomStyles.xaml b/source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/CustomStyles.xaml new file mode 100644 index 00000000..fcc13841 --- /dev/null +++ b/source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/CustomStyles.xaml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + None + + + + + + + + + + + + + + + + None + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Monochrome.xaml b/source/Reloaded.Mod.Launcher/Theme/Monochrome.xaml new file mode 100644 index 00000000..f9a0a71d --- /dev/null +++ b/source/Reloaded.Mod.Launcher/Theme/Monochrome.xaml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Monochrome/Colours.xaml b/source/Reloaded.Mod.Launcher/Theme/Monochrome/Colours.xaml new file mode 100644 index 00000000..3b6f408f --- /dev/null +++ b/source/Reloaded.Mod.Launcher/Theme/Monochrome/Colours.xaml @@ -0,0 +1,34 @@ + + + + + + #595959 + + + #4d4d4d + + + #404040 + + + #333333 + + #262626 + #1a1a1a + #0d0d0d + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Monochrome/Controls.xaml b/source/Reloaded.Mod.Launcher/Theme/Monochrome/Controls.xaml new file mode 100644 index 00000000..7a14fb3b --- /dev/null +++ b/source/Reloaded.Mod.Launcher/Theme/Monochrome/Controls.xaml @@ -0,0 +1,229 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Monochrome/CustomStyles.xaml b/source/Reloaded.Mod.Launcher/Theme/Monochrome/CustomStyles.xaml new file mode 100644 index 00000000..87f0ff79 --- /dev/null +++ b/source/Reloaded.Mod.Launcher/Theme/Monochrome/CustomStyles.xaml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + None + + + + + + + + + + + + + + + + None + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Teal.xaml b/source/Reloaded.Mod.Launcher/Theme/Teal.xaml new file mode 100644 index 00000000..2473d48f --- /dev/null +++ b/source/Reloaded.Mod.Launcher/Theme/Teal.xaml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Teal/Colours.xaml b/source/Reloaded.Mod.Launcher/Theme/Teal/Colours.xaml new file mode 100644 index 00000000..93e87122 --- /dev/null +++ b/source/Reloaded.Mod.Launcher/Theme/Teal/Colours.xaml @@ -0,0 +1,31 @@ + + + + + + #52a3ad + + + #2da8b9 + + + #209aac + + + #28818a + + #326167 + #285357 + #102123 + + + + + + + + + + + \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Teal/Controls.xaml b/source/Reloaded.Mod.Launcher/Theme/Teal/Controls.xaml new file mode 100644 index 00000000..db2d5960 --- /dev/null +++ b/source/Reloaded.Mod.Launcher/Theme/Teal/Controls.xaml @@ -0,0 +1,229 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Teal/CustomStyles.xaml b/source/Reloaded.Mod.Launcher/Theme/Teal/CustomStyles.xaml new file mode 100644 index 00000000..03861a85 --- /dev/null +++ b/source/Reloaded.Mod.Launcher/Theme/Teal/CustomStyles.xaml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + None + + + + + + + + + + + + + + + + None + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Violet.xaml b/source/Reloaded.Mod.Launcher/Theme/Violet.xaml new file mode 100644 index 00000000..1ad83e89 --- /dev/null +++ b/source/Reloaded.Mod.Launcher/Theme/Violet.xaml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Violet/Colours.xaml b/source/Reloaded.Mod.Launcher/Theme/Violet/Colours.xaml new file mode 100644 index 00000000..6efc3910 --- /dev/null +++ b/source/Reloaded.Mod.Launcher/Theme/Violet/Colours.xaml @@ -0,0 +1,34 @@ + + + + + + #9774be + + + #7a32cd + + + #3d146c + + + #31174f + + #251934 + #191023 + #0c0811 + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Violet/Controls.xaml b/source/Reloaded.Mod.Launcher/Theme/Violet/Controls.xaml new file mode 100644 index 00000000..55f53e7e --- /dev/null +++ b/source/Reloaded.Mod.Launcher/Theme/Violet/Controls.xaml @@ -0,0 +1,229 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Violet/CustomStyles.xaml b/source/Reloaded.Mod.Launcher/Theme/Violet/CustomStyles.xaml new file mode 100644 index 00000000..576a58a6 --- /dev/null +++ b/source/Reloaded.Mod.Launcher/Theme/Violet/CustomStyles.xaml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + None + + + + + + + + + + + + + + + + None + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 0655e289bdb82b1d168ed50e6b8cde58b4b5ec33 Mon Sep 17 00:00:00 2001 From: ZackWilde27 Date: Sun, 26 Oct 2025 18:36:08 -0600 Subject: [PATCH 2/7] Added Theme Downloader (with a catch) Added a "Fetch Themes..." option to the theme selector, which if selected will fetch all GUIs mods from GameBanana and add them to the list. clicking on any of the new entries will automatically download and install it The catch? I haven't tested it in a real scenario yet because GetByNameAsync does not return Also I removed the luna theme, I really liked that one but Microsoft might have something to say about it so it's gone now --- .../Utility/ThemeDownloader.cs | 227 +++ source/Reloaded.Mod.Launcher/App.xaml.cs | 15 +- source/Reloaded.Mod.Launcher/Theme/Luna.xaml | 53 - .../Theme/Luna/Colours.xaml | 78 - .../Theme/Luna/Controls.xaml | 229 --- .../Theme/Luna/CustomStyles.xaml | 61 - .../Theme/Luna/Images.xaml | 19 - .../Theme/Luna/Images/IconAddApp.png | Bin 5202 -> 0 bytes .../Theme/Luna/Images/IconDiscord.png | Bin 9963 -> 0 bytes .../Theme/Luna/Images/IconDownloadMods.png | Bin 11699 -> 0 bytes .../Theme/Luna/Images/IconGitHub.png | Bin 9981 -> 0 bytes .../Theme/Luna/Images/IconInfo.png | Bin 9560 -> 0 bytes .../Theme/Luna/Images/IconMods.png | Bin 7625 -> 0 bytes .../Theme/Luna/Images/IconSearch.png | Bin 6981 -> 0 bytes .../Theme/Luna/Images/IconSettings.png | Bin 8587 -> 0 bytes .../Theme/Luna/Images/IconSponsor.png | Bin 6372 -> 0 bytes .../Theme/Luna/Images/IconTwitter.png | Bin 8471 -> 0 bytes .../Theme/Luna/Images/ModPlaceholder.png | Bin 79448 -> 0 bytes .../Theme/Luna/Images/ReloadedNoBrackets.png | Bin 269027 -> 0 bytes .../Theme/Luna/Images/bliss.jpg | Bin 1283705 -> 0 bytes .../Theme/Luna/Styles.xaml | 1645 ----------------- .../Utility/XamlFileSelector.cs | 10 +- .../Utility/XamlThemeSelector.cs | 62 + 23 files changed, 310 insertions(+), 2089 deletions(-) create mode 100644 source/Reloaded.Mod.Launcher.Lib/Utility/ThemeDownloader.cs delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Luna.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Luna/Colours.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Luna/Controls.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Luna/CustomStyles.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Luna/Images.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Luna/Images/IconAddApp.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Luna/Images/IconDiscord.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Luna/Images/IconDownloadMods.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Luna/Images/IconGitHub.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Luna/Images/IconInfo.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Luna/Images/IconMods.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Luna/Images/IconSearch.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Luna/Images/IconSettings.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Luna/Images/IconSponsor.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Luna/Images/IconTwitter.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Luna/Images/ModPlaceholder.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Luna/Images/ReloadedNoBrackets.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Luna/Images/bliss.jpg delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Luna/Styles.xaml create mode 100644 source/Reloaded.Mod.Launcher/Utility/XamlThemeSelector.cs diff --git a/source/Reloaded.Mod.Launcher.Lib/Utility/ThemeDownloader.cs b/source/Reloaded.Mod.Launcher.Lib/Utility/ThemeDownloader.cs new file mode 100644 index 00000000..2ca6587f --- /dev/null +++ b/source/Reloaded.Mod.Launcher.Lib/Utility/ThemeDownloader.cs @@ -0,0 +1,227 @@ +using Reloaded.Mod.Loader.Update.Providers.GameBanana.Structures; + +namespace Reloaded.Mod.Launcher.Lib.Utility; + +/// +/// Manages updating the list of available themes, and downloading/installing them +/// +public class ThemeDownloader +{ + private static List AvailableThemes = []; + + // Things like my theme pack contain multiple themes in one (bad idea in hindsight), so now I have to account for that -zw + /// + /// The key is the name of a subtheme contained in a pack, the value is the index into AvailableThemes + /// + public static Dictionary ThemesDictionary = []; + + /// + /// Called after RefreshAvailableThemes runs + /// + public static Action? OnRefresh = null; + + private static string GetFileNameFromModName(string modName) + { + // If using the mod's name as the theme name, it will remove 'theme' from the name, fix any double spaces that might cause, trim it, and then replace spaces with underscores + return modName.Replace("Theme", "").Replace("theme", "").Replace(" ", " ").Trim().Replace(" ", "_"); + } + + /// + /// Fetches all themes from GameBanana, and updates the dictionary + /// + public static async Task RefreshAvailableThemes(bool fetch=true) + { + if (fetch) + { + ThemesDictionary.Clear(); + AvailableThemes.Clear(); + + // Hangs here forever + AvailableThemes = await GameBananaMod.GetByNameAsync("", 7486, 1, 5, "GUIs"); + + for (int i = 0; i < AvailableThemes.Count; i++) + { + var theme = AvailableThemes[i]; + if (theme.Name == null) continue; + + if (theme.Description != null && theme.Description.Contains("
    ")) + { + // Prepare for my trademark python text manipulation -zw + var startIndex = theme.Description.IndexOf("
      ") + 4; + var endIndex = theme.Description.IndexOf("
    "); + var containingThemes = theme.Description[startIndex..endIndex].Replace("
  • ", "").Replace(" ", "").Replace("\n", "").Split("
  • ")[..^1]; + foreach (var subtheme in containingThemes) + { + if (subtheme != "") + ThemesDictionary.Add(subtheme + ".xaml", i); + } + } + else + ThemesDictionary.Add(GetFileNameFromModName(theme.Name) + ".xaml", i); + } + } + + OnRefresh?.Invoke(); + } + + private static readonly string ThemeFolder = "Theme"; + private static readonly string TempFolder = "Theme/.tmp"; + private static readonly string TempZip = "Theme/tmptheme.zip"; + + private static async Task DownloadAndExtractZip(GameBananaModFile file) + { + Stream data = await SharedHttpClient.UncachedAndCompressed.GetStreamAsync(file.DownloadUrl); + var zipFile = File.Create(TempZip); + data.CopyTo(zipFile); + zipFile.Close(); + data.Close(); + + ZipFile.ExtractToDirectory(TempZip, TempFolder); + } + + private static readonly string[] ThemeContentsFilenames = [ + "Colours.xaml", + "Controls.xaml", + "CustomStyles.xaml", + "Images.xaml", + "Styles.xaml" + ]; + + // For safety, the downloader is not allowed to overwrite the default themes + // Special exceptions have been made for the already existing themes, where they are converted to a standalone theme. + private static readonly string[] InvalidMoveLocations = [ + $"{ThemeFolder}/Default", + $"{ThemeFolder}/Default.xaml", + $"{ThemeFolder}/Halogen", + $"{ThemeFolder}/Halogen.xaml", + $"{ThemeFolder}/Helpers" + ]; + + private static void CheckMoveDir(string destination) + { + if (InvalidMoveLocations.Contains(destination)) + throw new InvalidDataException("Cannot install themes that modify the default ones"); + } + + private static void MoveTempFiles(string destination) + { + CheckMoveDir(destination); + + foreach (var file in Directory.GetFiles(TempFolder)) + { + var newFile = $"{destination}/{Path.GetFileName(file)}"; + CheckMoveDir(newFile); + File.Move(file, newFile); + } + + foreach (var folder in Directory.GetDirectories(TempFolder)) + { + var newFolder = $"{destination}/{Path.GetFileName(folder)}"; + CheckMoveDir(newFolder); + Directory.Move(folder, newFolder); + } + + } + + private static void DeleteTempFiles() + { + if (File.Exists(TempZip)) + File.Delete(TempZip); + + if (Directory.Exists(TempFolder)) + Directory.Delete(TempFolder); + } + + private static async Task DownloadTheme(GameBananaMod theme) + { + // There needs to be a standard for how to upload themes + // I'll support all of the current ones but there's likely to be an edge case that causes it to break in the future -zw + + if (theme.Files == null || theme.Files.Count == 0) + return; + + // These should be deleted at the end but just in case it crashes or something + DeleteTempFiles(); + + string themeName = GetFileNameFromModName(theme.Name!); + string themeFolder = $"{ThemeFolder}/{themeName}"; + + if (theme.Files.Count == 1 && theme.Files[0].FileName.EndsWith(".zip")) + { + await DownloadAndExtractZip(theme.Files[0]); + + bool createTheme = false; + + List existingXAMLs = new(); + for (int i = 0; i < 5; i++) + existingXAMLs.Add(false); + + string[] files = Directory.GetFiles(TempFolder); + foreach (var file in files) + { + var name = Path.GetFileName(file); + if (ThemeContentsFilenames.Contains(name)) + { + // The zip contains the contents of a theme, so a new theme needs to be made from it + createTheme = true; + existingXAMLs[ThemeContentsFilenames.IndexOf(name)] = true; + } + } + + if (createTheme) + { + Directory.CreateDirectory(themeFolder); + MoveTempFiles(themeFolder); + + // Checking for the persona 4 golden theme + if (theme.Files[0].FileName == "p4g_theme.zip") + { + Directory.Move($"{themeFolder}/R-II/Images", $"{themeFolder}/Images"); + File.Move($"{themeFolder}/R-II/Settings.xaml", $"{themeFolder}/Settings.xaml"); + Directory.Delete($"{themeFolder}/R-II", true); + } + + File.WriteAllText(themeFolder + ".xaml", File.ReadAllText($"{ThemeFolder}/Halogen.xaml").Replace("Halogen", themeName)); + // For any XAMLs that don't exist, it'll copy the one from halogen and replace the name with the theme's name so the folder directories point to the correct place + for (int i = 0; i < 5; i++) + { + if (!existingXAMLs[i]) + File.WriteAllText($"{themeFolder}/{ThemeContentsFilenames[i]}", File.ReadAllText($"{ThemeFolder}/Halogen/{ThemeContentsFilenames[i]}").Replace("Halogen", themeName)); + } + } + else + MoveTempFiles(ThemeFolder); + } + // Checking for the heroes mod loader theme + else if (theme.Files.Count == 2 && theme.Files[0].FileName == "default_5073e.zip") + { + await DownloadAndExtractZip(theme.Files[0]); + Directory.Move($"{TempFolder}/Default", themeFolder); + Directory.Delete(TempFolder); + + await DownloadAndExtractZip(theme.Files[1]); + string imagesFolder = $"{ThemeFolder}/{themeName}/Images"; + Directory.CreateDirectory(imagesFolder); + Directory.Move(TempFolder, imagesFolder); + } + + DeleteTempFiles(); + } + + /// + /// Finds the theme from the given name, and then downloads and installs it + /// + /// + /// + public static async Task DownloadThemeByName(string name) + { + foreach ((var subtheme, var theme) in ThemesDictionary) + { + if (subtheme == name) + { + await DownloadTheme(AvailableThemes[theme]); + break; + } + } + } +} diff --git a/source/Reloaded.Mod.Launcher/App.xaml.cs b/source/Reloaded.Mod.Launcher/App.xaml.cs index 3478489d..05ab0261 100644 --- a/source/Reloaded.Mod.Launcher/App.xaml.cs +++ b/source/Reloaded.Mod.Launcher/App.xaml.cs @@ -42,6 +42,8 @@ private void OnStartup(object sender, StartupEventArgs e) // Need to construct MainWindow before invoking any dialog, otherwise Shutdown will be called on closing the dialog var window = new MainWindow(); + ThemeDownloader.OnRefresh = OnThemeFetch; + // Warn if OneDrive or NonAsciiChars detected in Reloaded-II directory bool reloadedPathHasNonAsciiChars = AppContext.BaseDirectory.Any(c => c > 127); if (AppContext.BaseDirectory.Contains("OneDrive") || reloadedPathHasNonAsciiChars) @@ -77,7 +79,7 @@ private void SetupResources() { var launcherFolder = AppContext.BaseDirectory; var languageSelector = new XamlFileSelector($"{launcherFolder}\\Assets\\Languages"); - var themeSelector = new XamlFileSelector($"{launcherFolder}\\Theme"); + var themeSelector = new XamlThemeSelector($"{launcherFolder}\\Theme"); var conf = Lib.IoC.GetConstant(); if (conf.FirstLaunch) @@ -189,4 +191,15 @@ protected override void OnExit(ExitEventArgs e) Caches.Shutdown(); } + + public void OnThemeFetch() + { + var themeSelector = (XamlThemeSelector)Resources.MergedDictionaries[10]; + + foreach (string theme in ThemeDownloader.ThemesDictionary.Keys) + { + if (!themeSelector.Files.Contains(theme)) + themeSelector.Files.Add(theme); + } + } } \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Luna.xaml b/source/Reloaded.Mod.Launcher/Theme/Luna.xaml deleted file mode 100644 index b318fa98..00000000 --- a/source/Reloaded.Mod.Launcher/Theme/Luna.xaml +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Luna/Colours.xaml b/source/Reloaded.Mod.Launcher/Theme/Luna/Colours.xaml deleted file mode 100644 index 49b32b51..00000000 --- a/source/Reloaded.Mod.Launcher/Theme/Luna/Colours.xaml +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - #b8c8ff - - - #8296d9 - - - #14286c - - - #17244f - - #191f34 - #101423 - #080a11 - - #245ADA - #4590F0 - #2963DD - #1246AD - - #90B8FF - #0445AF - - Transparent - #CCCCCC - - #DDDDDD - #b8c8ff - #b8c8ff - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Luna/Controls.xaml b/source/Reloaded.Mod.Launcher/Theme/Luna/Controls.xaml deleted file mode 100644 index e2ef24fc..00000000 --- a/source/Reloaded.Mod.Launcher/Theme/Luna/Controls.xaml +++ /dev/null @@ -1,229 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Luna/CustomStyles.xaml b/source/Reloaded.Mod.Launcher/Theme/Luna/CustomStyles.xaml deleted file mode 100644 index 0e55a907..00000000 --- a/source/Reloaded.Mod.Launcher/Theme/Luna/CustomStyles.xaml +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - None - - - - - - - - - - - - - - - - None - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Utility/XamlFileSelector.cs b/source/Reloaded.Mod.Launcher/Utility/XamlFileSelector.cs index e3a787e0..dbd712a9 100644 --- a/source/Reloaded.Mod.Launcher/Utility/XamlFileSelector.cs +++ b/source/Reloaded.Mod.Launcher/Utility/XamlFileSelector.cs @@ -52,7 +52,7 @@ public void SelectXamlFileByName(string fileName) } } - private void PopulateXamlFiles() + protected void PopulateXamlFiles() { var files = System.IO.Directory.GetFiles(Directory, XamlFilter, SearchOption.TopDirectoryOnly); Collections.ModifyObservableCollection(Files, files); @@ -60,7 +60,7 @@ private void PopulateXamlFiles() File = files.FirstOrDefault(); } - private void UpdateSource() + protected virtual void UpdateSource() { if (File == null) return; @@ -76,7 +76,7 @@ user loaded in complex images. As this in practice occurs over a theme or language switch, it should be largely unnoticeable to the end user. */ - NewFileSet?.Invoke(); + OnNewFileSet(); } /* Events */ @@ -95,6 +95,10 @@ private void OnAvailableXamlFilesUpdated(object sender, FileSystemEventArgs e) ActionWrappers.ExecuteWithApplicationDispatcher(PopulateXamlFiles); } + protected void OnNewFileSet() + { + NewFileSet?.Invoke(); + } #region PropertyChanged public event PropertyChangedEventHandler? PropertyChanged; diff --git a/source/Reloaded.Mod.Launcher/Utility/XamlThemeSelector.cs b/source/Reloaded.Mod.Launcher/Utility/XamlThemeSelector.cs new file mode 100644 index 00000000..d59fbe7a --- /dev/null +++ b/source/Reloaded.Mod.Launcher/Utility/XamlThemeSelector.cs @@ -0,0 +1,62 @@ +namespace Reloaded.Mod.Launcher.Utility; + +public class XamlThemeSelector : XamlFileSelector +{ + public XamlThemeSelector(string directoryPath) : base(directoryPath) + { + Files.Insert(0, "Fetch Themes..."); + } + + private void PopulateAndFetch(bool fetch=true) + { + PopulateXamlFiles(); + + ThemeDownloader.RefreshAvailableThemes(fetch).Wait(); + + Files.Insert(0, "Fetch Themes..."); + } + + protected override void UpdateSource() + { + if (File == null) + return; + + if (File == "Fetch Themes...") + { + PopulateAndFetch(); + return; + } + + try + { + Source = new Uri(File, UriKind.RelativeOrAbsolute); + } + catch + { + DownloadPackageViewModel viewModel = new([], Lib.IoC.Get()) + { + Progress = 0, + Text = "Downloading Theme", + Packages = [], + DownloadTask = ThemeDownloader.DownloadThemeByName(File) + }; + var dialog = new DownloadPackageDialog(viewModel); + dialog.ShowDialog(); + dialog.ViewModel.DownloadTask!.Wait(); + + PopulateAndFetch(false); + } + + /* + Cleanup old Dictionaries: + + Normally I wouldn't personally suggest running GC.Collect in user code however there's + potentially a lot of resources to clean up in terms of memory space. Especially if e.g. + user loaded in complex images. + + As this in practice occurs over a theme or language switch, it should be largely unnoticeable to the end user. + */ + + OnNewFileSet(); + } +} From a789a27ec854516cf3fcad6b2d586aca4f88406b Mon Sep 17 00:00:00 2001 From: ZackWilde27 Date: Sun, 26 Oct 2025 23:58:35 -0600 Subject: [PATCH 3/7] Fixes to the theme downloader I manually recreated the results the API call should be returning, so I was able to test it for real, and I immediately noticed a few flaws - Fixed installing the heroes mod loader theme - Fixed duplicates being added to the theme selector - Fixed bullet lists not being recognized - Added an admittedly hacky method to update the download window as it goes along - Attempted to make it switch to the theme you selected after it installs, but it's not working, I'll have to work on that a bit more As it is right now, you have to either restart reloaded after installing the theme, or switch to a different theme and switch back to get it to properly update I also removed all of my other themes I added previously, that was the plan anyways and I wanted to test downloading them --- .../Utility/ThemeDownloader.cs | 180 +- .../Theme/GreenApple.xaml | 56 - .../Theme/GreenApple/Colours.xaml | 22 - .../Theme/GreenApple/Controls.xaml | 229 --- .../Theme/GreenApple/CustomStyles.xaml | 61 - .../Theme/GreenApple/Images.xaml | 19 - .../Theme/GreenApple/Images/IconAddApp.png | Bin 19989 -> 0 bytes .../Theme/GreenApple/Images/IconDiscord.png | Bin 45177 -> 0 bytes .../GreenApple/Images/IconDownloadMods.png | Bin 39401 -> 0 bytes .../Theme/GreenApple/Images/IconGitHub.png | Bin 40102 -> 0 bytes .../Theme/GreenApple/Images/IconInfo.png | Bin 49643 -> 0 bytes .../Theme/GreenApple/Images/IconMods.png | Bin 69173 -> 0 bytes .../Theme/GreenApple/Images/IconSearch.png | Bin 46868 -> 0 bytes .../Theme/GreenApple/Images/IconSettings.png | Bin 57915 -> 0 bytes .../Theme/GreenApple/Images/IconSponsor.png | Bin 31262 -> 0 bytes .../Theme/GreenApple/Images/IconTwitter.png | Bin 33929 -> 0 bytes .../Theme/GreenApple/Images/LICENSE.txt | 5 - .../GreenApple/Images/ModPlaceholder.png | Bin 79448 -> 0 bytes .../GreenApple/Images/ReloadedNoBrackets.png | Bin 303502 -> 0 bytes .../Theme/GreenApple/Styles.xaml | 1616 ---------------- .../Theme/Metallic_Default.xaml | 53 - .../Theme/Metallic_Default/Colours.xaml | 58 - .../Theme/Metallic_Default/Controls.xaml | 229 --- .../Theme/Metallic_Default/CustomStyles.xaml | 61 - .../Theme/Metallic_Default/Images.xaml | 19 - .../Metallic_Default/Images/IconAddApp.png | Bin 1051394 -> 0 bytes .../Metallic_Default/Images/IconDiscord.png | Bin 1051394 -> 0 bytes .../Images/IconDownloadMods.png | Bin 1051394 -> 0 bytes .../Metallic_Default/Images/IconGitHub.png | Bin 1051394 -> 0 bytes .../Metallic_Default/Images/IconInfo.png | Bin 1051394 -> 0 bytes .../Metallic_Default/Images/IconMods.png | Bin 1051394 -> 0 bytes .../Metallic_Default/Images/IconSearch.png | Bin 1051394 -> 0 bytes .../Metallic_Default/Images/IconSettings.png | Bin 1051394 -> 0 bytes .../Metallic_Default/Images/IconSponsor.png | Bin 1051394 -> 0 bytes .../Metallic_Default/Images/IconTwitter.png | Bin 1051394 -> 0 bytes .../Images/ModPlaceholder.png | Bin 79448 -> 0 bytes .../Images/ReloadedNoBrackets.png | Bin 3011939 -> 0 bytes .../Theme/Metallic_Default/Styles.xaml | 1644 ----------------- .../Theme/Metallic_Silver.xaml | 53 - .../Theme/Metallic_Silver/Colours.xaml | 73 - .../Theme/Metallic_Silver/Controls.xaml | 229 --- .../Theme/Metallic_Silver/CustomStyles.xaml | 61 - .../Theme/Metallic_Silver/Images.xaml | 19 - .../Metallic_Silver/Images/IconAddApp.png | Bin 1051394 -> 0 bytes .../Metallic_Silver/Images/IconDiscord.png | Bin 1051394 -> 0 bytes .../Images/IconDownloadMods.png | Bin 1051394 -> 0 bytes .../Metallic_Silver/Images/IconGitHub.png | Bin 1051394 -> 0 bytes .../Theme/Metallic_Silver/Images/IconInfo.png | Bin 1051394 -> 0 bytes .../Theme/Metallic_Silver/Images/IconMods.png | Bin 1051394 -> 0 bytes .../Metallic_Silver/Images/IconSearch.png | Bin 1051394 -> 0 bytes .../Metallic_Silver/Images/IconSettings.png | Bin 1051394 -> 0 bytes .../Metallic_Silver/Images/IconSponsor.png | Bin 1051394 -> 0 bytes .../Metallic_Silver/Images/IconTwitter.png | Bin 1051394 -> 0 bytes .../Metallic_Silver/Images/ModPlaceholder.png | Bin 79448 -> 0 bytes .../Images/ReloadedNoBrackets.png | Bin 546340 -> 0 bytes .../Theme/Metallic_Silver/Styles.xaml | 1644 ----------------- .../Reloaded.Mod.Launcher/Theme/Midnight.xaml | 56 - .../Theme/Midnight/Colours.xaml | 22 - .../Theme/Midnight/Controls.xaml | 229 --- .../Theme/Midnight/CustomStyles.xaml | 61 - .../Theme/Midnight/Images.xaml | 19 - .../Theme/Midnight/Images/IconAddApp.png | Bin 14639 -> 0 bytes .../Theme/Midnight/Images/IconDiscord.png | Bin 33464 -> 0 bytes .../Midnight/Images/IconDownloadMods.png | Bin 25184 -> 0 bytes .../Theme/Midnight/Images/IconGitHub.png | Bin 30409 -> 0 bytes .../Theme/Midnight/Images/IconInfo.png | Bin 37278 -> 0 bytes .../Theme/Midnight/Images/IconMods.png | Bin 41262 -> 0 bytes .../Theme/Midnight/Images/IconSearch.png | Bin 35283 -> 0 bytes .../Theme/Midnight/Images/IconSettings.png | Bin 36103 -> 0 bytes .../Theme/Midnight/Images/IconSponsor.png | Bin 23491 -> 0 bytes .../Theme/Midnight/Images/IconTwitter.png | Bin 25837 -> 0 bytes .../Theme/Midnight/Images/LICENSE.txt | 5 - .../Theme/Midnight/Images/ModPlaceholder.png | Bin 79448 -> 0 bytes .../Midnight/Images/ReloadedNoBrackets.png | Bin 269027 -> 0 bytes .../Theme/Midnight/Styles.xaml | 1616 ---------------- .../Theme/Monochrome.xaml | 53 - .../Theme/Monochrome/Colours.xaml | 34 - .../Theme/Monochrome/Controls.xaml | 229 --- .../Theme/Monochrome/CustomStyles.xaml | 61 - .../Theme/Monochrome/Images.xaml | 19 - .../Theme/Monochrome/Images/IconAddApp.png | Bin 19089 -> 0 bytes .../Theme/Monochrome/Images/IconDiscord.png | Bin 42645 -> 0 bytes .../Monochrome/Images/IconDownloadMods.png | Bin 35428 -> 0 bytes .../Theme/Monochrome/Images/IconGitHub.png | Bin 39373 -> 0 bytes .../Theme/Monochrome/Images/IconInfo.png | Bin 46520 -> 0 bytes .../Theme/Monochrome/Images/IconMods.png | Bin 61079 -> 0 bytes .../Theme/Monochrome/Images/IconSearch.png | Bin 42675 -> 0 bytes .../Theme/Monochrome/Images/IconSettings.png | Bin 49626 -> 0 bytes .../Theme/Monochrome/Images/IconSponsor.png | Bin 30052 -> 0 bytes .../Theme/Monochrome/Images/IconTwitter.png | Bin 33179 -> 0 bytes .../Monochrome/Images/ModPlaceholder.png | Bin 79448 -> 0 bytes .../Monochrome/Images/ReloadedNoBrackets.png | Bin 316267 -> 0 bytes .../Theme/Monochrome/Styles.xaml | 1616 ---------------- .../Reloaded.Mod.Launcher/Theme/Orange.xaml | 56 - .../Theme/Orange/Colours.xaml | 22 - .../Theme/Orange/Controls.xaml | 229 --- .../Theme/Orange/CustomStyles.xaml | 61 - .../Theme/Orange/Images.xaml | 19 - .../Theme/Orange/Images/IconAddApp.png | Bin 19899 -> 0 bytes .../Theme/Orange/Images/IconDiscord.png | Bin 45065 -> 0 bytes .../Theme/Orange/Images/IconDownloadMods.png | Bin 39604 -> 0 bytes .../Theme/Orange/Images/IconGitHub.png | Bin 40053 -> 0 bytes .../Theme/Orange/Images/IconInfo.png | Bin 49631 -> 0 bytes .../Theme/Orange/Images/IconMods.png | Bin 69581 -> 0 bytes .../Theme/Orange/Images/IconSearch.png | Bin 46776 -> 0 bytes .../Theme/Orange/Images/IconSettings.png | Bin 58550 -> 0 bytes .../Theme/Orange/Images/IconSponsor.png | Bin 31075 -> 0 bytes .../Theme/Orange/Images/IconTwitter.png | Bin 33870 -> 0 bytes .../Theme/Orange/Images/LICENSE.txt | 5 - .../Theme/Orange/Images/ModPlaceholder.png | Bin 79448 -> 0 bytes .../Orange/Images/ReloadedNoBrackets.png | Bin 306136 -> 0 bytes .../Theme/Orange/Styles.xaml | 1616 ---------------- source/Reloaded.Mod.Launcher/Theme/Teal.xaml | 53 - .../Theme/Teal/Colours.xaml | 31 - .../Theme/Teal/Controls.xaml | 229 --- .../Theme/Teal/CustomStyles.xaml | 62 - .../Theme/Teal/Images.xaml | 19 - .../Theme/Teal/Images/IconAddApp.png | Bin 20476 -> 0 bytes .../Theme/Teal/Images/IconDiscord.png | Bin 45191 -> 0 bytes .../Theme/Teal/Images/IconDownloadMods.png | Bin 39968 -> 0 bytes .../Theme/Teal/Images/IconGitHub.png | Bin 40102 -> 0 bytes .../Theme/Teal/Images/IconInfo.png | Bin 49899 -> 0 bytes .../Theme/Teal/Images/IconMods.png | Bin 69772 -> 0 bytes .../Theme/Teal/Images/IconSearch.png | Bin 47289 -> 0 bytes .../Theme/Teal/Images/IconSettings.png | Bin 59264 -> 0 bytes .../Theme/Teal/Images/IconSponsor.png | Bin 31199 -> 0 bytes .../Theme/Teal/Images/IconTwitter.png | Bin 34116 -> 0 bytes .../Theme/Teal/Images/ModPlaceholder.png | Bin 79448 -> 0 bytes .../Theme/Teal/Images/ReloadedNoBrackets.png | Bin 306961 -> 0 bytes .../Theme/Teal/Styles.xaml | 1616 ---------------- .../Reloaded.Mod.Launcher/Theme/Violet.xaml | 53 - .../Theme/Violet/Colours.xaml | 34 - .../Theme/Violet/Controls.xaml | 229 --- .../Theme/Violet/CustomStyles.xaml | 61 - .../Theme/Violet/Images.xaml | 19 - .../Theme/Violet/Images/IconAddApp.png | Bin 20337 -> 0 bytes .../Theme/Violet/Images/IconDiscord.png | Bin 45463 -> 0 bytes .../Theme/Violet/Images/IconDownloadMods.png | Bin 40004 -> 0 bytes .../Theme/Violet/Images/IconGitHub.png | Bin 40308 -> 0 bytes .../Theme/Violet/Images/IconInfo.png | Bin 49983 -> 0 bytes .../Theme/Violet/Images/IconMods.png | Bin 70057 -> 0 bytes .../Theme/Violet/Images/IconSearch.png | Bin 47236 -> 0 bytes .../Theme/Violet/Images/IconSettings.png | Bin 59100 -> 0 bytes .../Theme/Violet/Images/IconSponsor.png | Bin 31405 -> 0 bytes .../Theme/Violet/Images/IconTwitter.png | Bin 34207 -> 0 bytes .../Theme/Violet/Images/ModPlaceholder.png | Bin 79448 -> 0 bytes .../Violet/Images/ReloadedNoBrackets.png | Bin 309773 -> 0 bytes .../Theme/Violet/Styles.xaml | 1616 ---------------- .../Utility/XamlThemeSelector.cs | 16 +- 149 files changed, 156 insertions(+), 16241 deletions(-) delete mode 100644 source/Reloaded.Mod.Launcher/Theme/GreenApple.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/GreenApple/Colours.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/GreenApple/Controls.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/GreenApple/CustomStyles.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/GreenApple/Images.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/GreenApple/Images/IconAddApp.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/GreenApple/Images/IconDiscord.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/GreenApple/Images/IconDownloadMods.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/GreenApple/Images/IconGitHub.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/GreenApple/Images/IconInfo.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/GreenApple/Images/IconMods.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/GreenApple/Images/IconSearch.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/GreenApple/Images/IconSettings.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/GreenApple/Images/IconSponsor.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/GreenApple/Images/IconTwitter.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/GreenApple/Images/LICENSE.txt delete mode 100644 source/Reloaded.Mod.Launcher/Theme/GreenApple/Images/ModPlaceholder.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/GreenApple/Images/ReloadedNoBrackets.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/GreenApple/Styles.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Default.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Default/Colours.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Default/Controls.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Default/CustomStyles.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Default/Images.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Default/Images/IconAddApp.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Default/Images/IconDiscord.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Default/Images/IconDownloadMods.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Default/Images/IconGitHub.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Default/Images/IconInfo.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Default/Images/IconMods.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Default/Images/IconSearch.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Default/Images/IconSettings.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Default/Images/IconSponsor.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Default/Images/IconTwitter.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Default/Images/ModPlaceholder.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Default/Images/ReloadedNoBrackets.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Default/Styles.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Silver.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/Colours.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/Controls.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/CustomStyles.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/Images.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/Images/IconAddApp.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/Images/IconDiscord.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/Images/IconDownloadMods.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/Images/IconGitHub.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/Images/IconInfo.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/Images/IconMods.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/Images/IconSearch.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/Images/IconSettings.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/Images/IconSponsor.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/Images/IconTwitter.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/Images/ModPlaceholder.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/Images/ReloadedNoBrackets.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/Styles.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Midnight.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Midnight/Colours.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Midnight/Controls.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Midnight/CustomStyles.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Midnight/Images.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Midnight/Images/IconAddApp.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Midnight/Images/IconDiscord.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Midnight/Images/IconDownloadMods.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Midnight/Images/IconGitHub.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Midnight/Images/IconInfo.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Midnight/Images/IconMods.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Midnight/Images/IconSearch.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Midnight/Images/IconSettings.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Midnight/Images/IconSponsor.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Midnight/Images/IconTwitter.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Midnight/Images/LICENSE.txt delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Midnight/Images/ModPlaceholder.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Midnight/Images/ReloadedNoBrackets.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Midnight/Styles.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Monochrome.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Monochrome/Colours.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Monochrome/Controls.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Monochrome/CustomStyles.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Monochrome/Images.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Monochrome/Images/IconAddApp.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Monochrome/Images/IconDiscord.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Monochrome/Images/IconDownloadMods.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Monochrome/Images/IconGitHub.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Monochrome/Images/IconInfo.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Monochrome/Images/IconMods.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Monochrome/Images/IconSearch.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Monochrome/Images/IconSettings.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Monochrome/Images/IconSponsor.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Monochrome/Images/IconTwitter.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Monochrome/Images/ModPlaceholder.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Monochrome/Images/ReloadedNoBrackets.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Monochrome/Styles.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Orange.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Orange/Colours.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Orange/Controls.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Orange/CustomStyles.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Orange/Images.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Orange/Images/IconAddApp.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Orange/Images/IconDiscord.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Orange/Images/IconDownloadMods.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Orange/Images/IconGitHub.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Orange/Images/IconInfo.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Orange/Images/IconMods.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Orange/Images/IconSearch.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Orange/Images/IconSettings.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Orange/Images/IconSponsor.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Orange/Images/IconTwitter.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Orange/Images/LICENSE.txt delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Orange/Images/ModPlaceholder.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Orange/Images/ReloadedNoBrackets.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Orange/Styles.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Teal.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Teal/Colours.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Teal/Controls.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Teal/CustomStyles.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Teal/Images.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Teal/Images/IconAddApp.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Teal/Images/IconDiscord.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Teal/Images/IconDownloadMods.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Teal/Images/IconGitHub.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Teal/Images/IconInfo.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Teal/Images/IconMods.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Teal/Images/IconSearch.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Teal/Images/IconSettings.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Teal/Images/IconSponsor.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Teal/Images/IconTwitter.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Teal/Images/ModPlaceholder.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Teal/Images/ReloadedNoBrackets.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Teal/Styles.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Violet.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Violet/Colours.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Violet/Controls.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Violet/CustomStyles.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Violet/Images.xaml delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Violet/Images/IconAddApp.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Violet/Images/IconDiscord.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Violet/Images/IconDownloadMods.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Violet/Images/IconGitHub.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Violet/Images/IconInfo.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Violet/Images/IconMods.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Violet/Images/IconSearch.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Violet/Images/IconSettings.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Violet/Images/IconSponsor.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Violet/Images/IconTwitter.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Violet/Images/ModPlaceholder.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Violet/Images/ReloadedNoBrackets.png delete mode 100644 source/Reloaded.Mod.Launcher/Theme/Violet/Styles.xaml diff --git a/source/Reloaded.Mod.Launcher.Lib/Utility/ThemeDownloader.cs b/source/Reloaded.Mod.Launcher.Lib/Utility/ThemeDownloader.cs index 2ca6587f..6635ed34 100644 --- a/source/Reloaded.Mod.Launcher.Lib/Utility/ThemeDownloader.cs +++ b/source/Reloaded.Mod.Launcher.Lib/Utility/ThemeDownloader.cs @@ -26,9 +26,57 @@ private static string GetFileNameFromModName(string modName) return modName.Replace("Theme", "").Replace("theme", "").Replace(" ", " ").Trim().Replace(" ", "_"); } + private static GameBananaModFile TestModFile(string filename, string description, string url) + { + var file = new GameBananaModFile(); + file.FileName = filename; + file.Description = description; + file.DownloadUrl = url; + return file; + } + + private static GameBananaMod TestMod(string name, string description, List files) + { + var mod = new GameBananaMod(); + mod.Name = name; + mod.Description = description; + mod.Files = files; + return mod; + } + + // A manual re-creation of the results the API call should get back, so I can test it out for sort-of real + private static void TestFetch() + { + var discordTheme = TestMod( + "Discord Theme", + "A theme that makes Reloaded II look and feel like Discord.", + [ TestModFile("discord.zip", "", "https://gamebanana.com/dl/489094") ] + ); + + var personaTheme = TestMod( + "Persona 4 Golden theme", + "since P4 is gonna get a update and make RII become even more outdated (for this game), i decided to make this as a goodbye.\ni tried to change the font, but it won't delete for some reason.", + [ TestModFile("p4g_theme.zip", "", "https://gamebanana.com/dl/886552") ] + ); + + var heroesTheme = TestMod( + "heroes mod loader theme", + "this mod simply replaces the logo with a custom heroes mod loader one.", + [ TestModFile("default_5073e.zip", "", "https://gamebanana.com/dl/634883"), TestModFile("reloadednobrackets.zip", "", "https://gamebanana.com/dl/635018") ] + ); + + var themePack = TestMod( + "Zack's Theme Pack Vol. 1", + "These are my set of themes for Reloaded

    • GreenApple
    • Orange
    • Teal
    • Violet
    • Midnight
    • Monochrome
    • Metallic Default
    • Metallic Silver

    I'll probably make more in the future so I'm calling this volume 1

    Installing

    To install it, copy the contents of the zip folder to the Theme folder wherever Reloaded is installed. The themes will show up in the drop down the next time Reloaded is launched.", + [ TestModFile("zacksthemepackvol1.zip", "", "https://gamebanana.com/dl/1546487") ] + ); + AvailableThemes = [discordTheme, personaTheme, heroesTheme, themePack]; + } + /// /// Fetches all themes from GameBanana, and updates the dictionary /// + /// Whether or not to fetch from the server, if not it just updates the drop down with what it's already got public static async Task RefreshAvailableThemes(bool fetch=true) { if (fetch) @@ -36,28 +84,31 @@ public static async Task RefreshAvailableThemes(bool fetch=true) ThemesDictionary.Clear(); AvailableThemes.Clear(); + TestFetch(); // Hangs here forever - AvailableThemes = await GameBananaMod.GetByNameAsync("", 7486, 1, 5, "GUIs"); + //AvailableThemes = await GameBananaMod.GetByNameAsync("", 7486, 1, 5, "GUIs"); for (int i = 0; i < AvailableThemes.Count; i++) { var theme = AvailableThemes[i]; if (theme.Name == null) continue; - if (theme.Description != null && theme.Description.Contains("
      ")) + // It checks for a bullet-point list to determine which themes are contained in a pack + if (theme.Description != null && theme.Description.Contains("") + 4; + var startIndex = theme.Description.IndexOf("", startIndex) + 1; var endIndex = theme.Description.IndexOf("
    "); - var containingThemes = theme.Description[startIndex..endIndex].Replace("
  • ", "").Replace(" ", "").Replace("\n", "").Split("
  • ")[..^1]; + var containingThemes = theme.Description[startIndex..endIndex].Replace("
  • ", "").Replace(" ", "_").Replace("\n", "").Split("
  • ")[..^1]; foreach (var subtheme in containingThemes) { if (subtheme != "") - ThemesDictionary.Add(subtheme + ".xaml", i); + ThemesDictionary.Add(GetFullPath(subtheme + ".xaml"), i); } } else - ThemesDictionary.Add(GetFileNameFromModName(theme.Name) + ".xaml", i); + ThemesDictionary.Add(GetFullPath(GetFileNameFromModName(theme.Name) + ".xaml"), i); } } @@ -68,6 +119,20 @@ public static async Task RefreshAvailableThemes(bool fetch=true) private static readonly string TempFolder = "Theme/.tmp"; private static readonly string TempZip = "Theme/tmptheme.zip"; + /// + /// Turns a .xaml filename into the full absolute path + /// + /// The .xaml from the file selector + public static string GetFullPath(string filename) + { + string path = Path.GetFullPath($"{ThemeFolder}/{filename}"); + + // I think the double slash is a bug, I'm recreating it so it works + path = path.Replace($"Launcher{Path.DirectorySeparatorChar}", $"Launcher{Path.DirectorySeparatorChar}{Path.DirectorySeparatorChar}"); + + return path; + } + private static async Task DownloadAndExtractZip(GameBananaModFile file) { Stream data = await SharedHttpClient.UncachedAndCompressed.GetStreamAsync(file.DownloadUrl); @@ -94,7 +159,8 @@ private static async Task DownloadAndExtractZip(GameBananaModFile file) $"{ThemeFolder}/Default.xaml", $"{ThemeFolder}/Halogen", $"{ThemeFolder}/Halogen.xaml", - $"{ThemeFolder}/Helpers" + $"{ThemeFolder}/Helpers", + $"{ThemeFolder}/NoCorners.xaml" ]; private static void CheckMoveDir(string destination) @@ -129,10 +195,44 @@ private static void DeleteTempFiles() File.Delete(TempZip); if (Directory.Exists(TempFolder)) - Directory.Delete(TempFolder); + Directory.Delete(TempFolder, true); + } + + private static void CopyFromHalogen(string src, string dst, string themeName) + { + File.WriteAllText(dst, File.ReadAllText(src).Replace("Halogen", themeName)); + } + + private static bool ThemeNeedsToBeCreated(out List existingXAMLs) + { + bool createTheme = false; + + existingXAMLs = []; + for (int i = 0; i < ThemeContentsFilenames.Length; i++) + existingXAMLs.Add(false); + + string[] files = Directory.GetFiles(TempFolder); + foreach (var file in files) + { + var name = Path.GetFileName(file); + if (ThemeContentsFilenames.Contains(name)) + { + // The zip contains the contents of a theme, so a new theme needs to be made from it + createTheme = true; + existingXAMLs[ThemeContentsFilenames.IndexOf(name)] = true; + } + } + + return createTheme; } - private static async Task DownloadTheme(GameBananaMod theme) + private static void UpdateDownloadWindow(DownloadPackageViewModel viewModel, double progress, string text) + { + viewModel.Progress = progress; + viewModel.Text = text; + } + + private static async Task DownloadTheme(GameBananaMod theme, DownloadPackageViewModel viewModel) { // There needs to be a standard for how to upload themes // I'll support all of the current ones but there's likely to be an edge case that causes it to break in the future -zw @@ -143,6 +243,8 @@ private static async Task DownloadTheme(GameBananaMod theme) // These should be deleted at the end but just in case it crashes or something DeleteTempFiles(); + UpdateDownloadWindow(viewModel, 0, "Downloading Theme..."); + string themeName = GetFileNameFromModName(theme.Name!); string themeFolder = $"{ThemeFolder}/{themeName}"; @@ -150,25 +252,9 @@ private static async Task DownloadTheme(GameBananaMod theme) { await DownloadAndExtractZip(theme.Files[0]); - bool createTheme = false; - - List existingXAMLs = new(); - for (int i = 0; i < 5; i++) - existingXAMLs.Add(false); - - string[] files = Directory.GetFiles(TempFolder); - foreach (var file in files) - { - var name = Path.GetFileName(file); - if (ThemeContentsFilenames.Contains(name)) - { - // The zip contains the contents of a theme, so a new theme needs to be made from it - createTheme = true; - existingXAMLs[ThemeContentsFilenames.IndexOf(name)] = true; - } - } + UpdateDownloadWindow(viewModel, 50, "Installing Theme..."); - if (createTheme) + if (ThemeNeedsToBeCreated(out var existingXAMLs)) { Directory.CreateDirectory(themeFolder); MoveTempFiles(themeFolder); @@ -181,12 +267,12 @@ private static async Task DownloadTheme(GameBananaMod theme) Directory.Delete($"{themeFolder}/R-II", true); } - File.WriteAllText(themeFolder + ".xaml", File.ReadAllText($"{ThemeFolder}/Halogen.xaml").Replace("Halogen", themeName)); + CopyFromHalogen($"{ThemeFolder}/Halogen.xaml", themeFolder + ".xaml", themeName); // For any XAMLs that don't exist, it'll copy the one from halogen and replace the name with the theme's name so the folder directories point to the correct place - for (int i = 0; i < 5; i++) + for (int i = 0; i < existingXAMLs.Count; i++) { if (!existingXAMLs[i]) - File.WriteAllText($"{themeFolder}/{ThemeContentsFilenames[i]}", File.ReadAllText($"{ThemeFolder}/Halogen/{ThemeContentsFilenames[i]}").Replace("Halogen", themeName)); + CopyFromHalogen($"{ThemeFolder}/Halogen/{ThemeContentsFilenames[i]}", $"{themeFolder}/{ThemeContentsFilenames[i]}", themeName); } } else @@ -196,30 +282,48 @@ private static async Task DownloadTheme(GameBananaMod theme) else if (theme.Files.Count == 2 && theme.Files[0].FileName == "default_5073e.zip") { await DownloadAndExtractZip(theme.Files[0]); + + UpdateDownloadWindow(viewModel, 20, "Installing Theme..."); + Directory.Move($"{TempFolder}/Default", themeFolder); Directory.Delete(TempFolder); + UpdateDownloadWindow(viewModel, 40, "Downloading Image..."); + await DownloadAndExtractZip(theme.Files[1]); - string imagesFolder = $"{ThemeFolder}/{themeName}/Images"; - Directory.CreateDirectory(imagesFolder); + + UpdateDownloadWindow(viewModel, 60, "Installing Image..."); + + string imagesFolder = $"{themeFolder}/Images"; Directory.Move(TempFolder, imagesFolder); + + UpdateDownloadWindow(viewModel, 80, "Finishing Up..."); + + File.Move($"{themeFolder}/R-II/Controls.xaml", $"{themeFolder}/Controls.xaml"); + CopyFromHalogen($"{ThemeFolder}/Halogen/CustomStyles.xaml", $"{themeFolder}/CustomStyles.xaml", themeName); + File.WriteAllText($"{themeFolder}/Images.xaml", File.ReadAllText($"{themeFolder}/R-II/Images.xaml").Replace("Default/R-II/Images/R", $"{themeName}/Images/R")); + Directory.Delete($"{themeFolder}/R-II", true); + Directory.Delete($"{themeFolder}/Fonts", true); + CopyFromHalogen($"{ThemeFolder}/Halogen.xaml", themeFolder + ".xaml", themeName); } + UpdateDownloadWindow(viewModel, 100, "Done!"); + DeleteTempFiles(); } /// - /// Finds the theme from the given name, and then downloads and installs it + /// Finds the theme from the given .xaml, and then downloads and installs it /// - /// - /// - public static async Task DownloadThemeByName(string name) + /// The .xaml to load from the theme selector + /// The view model for the download window, so it can update the progress bar and text as it goes + public static async Task DownloadThemeByName(string name, DownloadPackageViewModel viewModel) { - foreach ((var subtheme, var theme) in ThemesDictionary) + foreach ((var subtheme, var index) in ThemesDictionary) { if (subtheme == name) { - await DownloadTheme(AvailableThemes[theme]); + await DownloadTheme(AvailableThemes[index], viewModel); break; } } diff --git a/source/Reloaded.Mod.Launcher/Theme/GreenApple.xaml b/source/Reloaded.Mod.Launcher/Theme/GreenApple.xaml deleted file mode 100644 index 9c5f966c..00000000 --- a/source/Reloaded.Mod.Launcher/Theme/GreenApple.xaml +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/GreenApple/Colours.xaml b/source/Reloaded.Mod.Launcher/Theme/GreenApple/Colours.xaml deleted file mode 100644 index 9438be8b..00000000 --- a/source/Reloaded.Mod.Launcher/Theme/GreenApple/Colours.xaml +++ /dev/null @@ -1,22 +0,0 @@ - - - - #b7d3a7 - #7dc481 - #39773c - #29562b - #214422 - #173319 - #0f2110 - - - - - - - - - - - \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/GreenApple/Controls.xaml b/source/Reloaded.Mod.Launcher/Theme/GreenApple/Controls.xaml deleted file mode 100644 index 890136b3..00000000 --- a/source/Reloaded.Mod.Launcher/Theme/GreenApple/Controls.xaml +++ /dev/null @@ -1,229 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/GreenApple/CustomStyles.xaml b/source/Reloaded.Mod.Launcher/Theme/GreenApple/CustomStyles.xaml deleted file mode 100644 index 8c16b3b8..00000000 --- a/source/Reloaded.Mod.Launcher/Theme/GreenApple/CustomStyles.xaml +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - None - - - - - - - - - - - - - - - - None - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Metallic_Default.xaml b/source/Reloaded.Mod.Launcher/Theme/Metallic_Default.xaml deleted file mode 100644 index 2c47246e..00000000 --- a/source/Reloaded.Mod.Launcher/Theme/Metallic_Default.xaml +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Metallic_Default/Colours.xaml b/source/Reloaded.Mod.Launcher/Theme/Metallic_Default/Colours.xaml deleted file mode 100644 index 2fb18172..00000000 --- a/source/Reloaded.Mod.Launcher/Theme/Metallic_Default/Colours.xaml +++ /dev/null @@ -1,58 +0,0 @@ - - - - #d6a8a8 - #B66363 - #793939 - #572929 - #452121 - #341818 - #231010 - - #572929 - #793939 - #000000 - #d6a8a8 - #452121 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Metallic_Default/Controls.xaml b/source/Reloaded.Mod.Launcher/Theme/Metallic_Default/Controls.xaml deleted file mode 100644 index 9d6e1715..00000000 --- a/source/Reloaded.Mod.Launcher/Theme/Metallic_Default/Controls.xaml +++ /dev/null @@ -1,229 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Metallic_Default/CustomStyles.xaml b/source/Reloaded.Mod.Launcher/Theme/Metallic_Default/CustomStyles.xaml deleted file mode 100644 index 0fb98338..00000000 --- a/source/Reloaded.Mod.Launcher/Theme/Metallic_Default/CustomStyles.xaml +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - None - - - - - - - - - - - - - - - - None - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Metallic_Silver.xaml b/source/Reloaded.Mod.Launcher/Theme/Metallic_Silver.xaml deleted file mode 100644 index 89249003..00000000 --- a/source/Reloaded.Mod.Launcher/Theme/Metallic_Silver.xaml +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/Colours.xaml b/source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/Colours.xaml deleted file mode 100644 index c27bff62..00000000 --- a/source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/Colours.xaml +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - #9774be - - - #ffffff - - - #3d146c - - - #31174f - - #251934 - #191023 - #0c0811 - - #606057 - #888888 - #000000 - #D7D7D6 - #111111 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/Controls.xaml b/source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/Controls.xaml deleted file mode 100644 index 66fecc6f..00000000 --- a/source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/Controls.xaml +++ /dev/null @@ -1,229 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/CustomStyles.xaml b/source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/CustomStyles.xaml deleted file mode 100644 index fcc13841..00000000 --- a/source/Reloaded.Mod.Launcher/Theme/Metallic_Silver/CustomStyles.xaml +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - None - - - - - - - - - - - - - - - - None - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Midnight.xaml b/source/Reloaded.Mod.Launcher/Theme/Midnight.xaml deleted file mode 100644 index 7a90865a..00000000 --- a/source/Reloaded.Mod.Launcher/Theme/Midnight.xaml +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Midnight/Colours.xaml b/source/Reloaded.Mod.Launcher/Theme/Midnight/Colours.xaml deleted file mode 100644 index 9210a514..00000000 --- a/source/Reloaded.Mod.Launcher/Theme/Midnight/Colours.xaml +++ /dev/null @@ -1,22 +0,0 @@ - - - - #b8ccff - #718fda - #111216 - #2b303b - #111522 - #080b12 - #040506 - - - - - - - - - - - \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Midnight/Controls.xaml b/source/Reloaded.Mod.Launcher/Theme/Midnight/Controls.xaml deleted file mode 100644 index 0cb5397d..00000000 --- a/source/Reloaded.Mod.Launcher/Theme/Midnight/Controls.xaml +++ /dev/null @@ -1,229 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Midnight/CustomStyles.xaml b/source/Reloaded.Mod.Launcher/Theme/Midnight/CustomStyles.xaml deleted file mode 100644 index 09598838..00000000 --- a/source/Reloaded.Mod.Launcher/Theme/Midnight/CustomStyles.xaml +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - None - - - - - - - - - - - - - - - - None - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Monochrome.xaml b/source/Reloaded.Mod.Launcher/Theme/Monochrome.xaml deleted file mode 100644 index f9a0a71d..00000000 --- a/source/Reloaded.Mod.Launcher/Theme/Monochrome.xaml +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Monochrome/Colours.xaml b/source/Reloaded.Mod.Launcher/Theme/Monochrome/Colours.xaml deleted file mode 100644 index 3b6f408f..00000000 --- a/source/Reloaded.Mod.Launcher/Theme/Monochrome/Colours.xaml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - #595959 - - - #4d4d4d - - - #404040 - - - #333333 - - #262626 - #1a1a1a - #0d0d0d - - - - - - - - - - - - - - \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Monochrome/Controls.xaml b/source/Reloaded.Mod.Launcher/Theme/Monochrome/Controls.xaml deleted file mode 100644 index 7a14fb3b..00000000 --- a/source/Reloaded.Mod.Launcher/Theme/Monochrome/Controls.xaml +++ /dev/null @@ -1,229 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Monochrome/CustomStyles.xaml b/source/Reloaded.Mod.Launcher/Theme/Monochrome/CustomStyles.xaml deleted file mode 100644 index 87f0ff79..00000000 --- a/source/Reloaded.Mod.Launcher/Theme/Monochrome/CustomStyles.xaml +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - None - - - - - - - - - - - - - - - - None - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Orange.xaml b/source/Reloaded.Mod.Launcher/Theme/Orange.xaml deleted file mode 100644 index a5a45a33..00000000 --- a/source/Reloaded.Mod.Launcher/Theme/Orange.xaml +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Orange/Colours.xaml b/source/Reloaded.Mod.Launcher/Theme/Orange/Colours.xaml deleted file mode 100644 index 5c88e6b5..00000000 --- a/source/Reloaded.Mod.Launcher/Theme/Orange/Colours.xaml +++ /dev/null @@ -1,22 +0,0 @@ - - - - #CEBDA5 - #dfb67c - #b17822 - #896129 - #423420 - #332717 - #1E170E - - - - - - - - - - - \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Orange/Controls.xaml b/source/Reloaded.Mod.Launcher/Theme/Orange/Controls.xaml deleted file mode 100644 index e864813e..00000000 --- a/source/Reloaded.Mod.Launcher/Theme/Orange/Controls.xaml +++ /dev/null @@ -1,229 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Orange/CustomStyles.xaml b/source/Reloaded.Mod.Launcher/Theme/Orange/CustomStyles.xaml deleted file mode 100644 index e1a2f271..00000000 --- a/source/Reloaded.Mod.Launcher/Theme/Orange/CustomStyles.xaml +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - None - - - - - - - - - - - - - - - - None - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Teal.xaml b/source/Reloaded.Mod.Launcher/Theme/Teal.xaml deleted file mode 100644 index 2473d48f..00000000 --- a/source/Reloaded.Mod.Launcher/Theme/Teal.xaml +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Teal/Colours.xaml b/source/Reloaded.Mod.Launcher/Theme/Teal/Colours.xaml deleted file mode 100644 index 93e87122..00000000 --- a/source/Reloaded.Mod.Launcher/Theme/Teal/Colours.xaml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - #52a3ad - - - #2da8b9 - - - #209aac - - - #28818a - - #326167 - #285357 - #102123 - - - - - - - - - - - \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Teal/Controls.xaml b/source/Reloaded.Mod.Launcher/Theme/Teal/Controls.xaml deleted file mode 100644 index db2d5960..00000000 --- a/source/Reloaded.Mod.Launcher/Theme/Teal/Controls.xaml +++ /dev/null @@ -1,229 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Teal/CustomStyles.xaml b/source/Reloaded.Mod.Launcher/Theme/Teal/CustomStyles.xaml deleted file mode 100644 index 03861a85..00000000 --- a/source/Reloaded.Mod.Launcher/Theme/Teal/CustomStyles.xaml +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - None - - - - - - - - - - - - - - - - None - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Violet.xaml b/source/Reloaded.Mod.Launcher/Theme/Violet.xaml deleted file mode 100644 index 1ad83e89..00000000 --- a/source/Reloaded.Mod.Launcher/Theme/Violet.xaml +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Violet/Colours.xaml b/source/Reloaded.Mod.Launcher/Theme/Violet/Colours.xaml deleted file mode 100644 index 6efc3910..00000000 --- a/source/Reloaded.Mod.Launcher/Theme/Violet/Colours.xaml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - #9774be - - - #7a32cd - - - #3d146c - - - #31174f - - #251934 - #191023 - #0c0811 - - - - - - - - - - - - - - \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Violet/Controls.xaml b/source/Reloaded.Mod.Launcher/Theme/Violet/Controls.xaml deleted file mode 100644 index 55f53e7e..00000000 --- a/source/Reloaded.Mod.Launcher/Theme/Violet/Controls.xaml +++ /dev/null @@ -1,229 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Theme/Violet/CustomStyles.xaml b/source/Reloaded.Mod.Launcher/Theme/Violet/CustomStyles.xaml deleted file mode 100644 index 576a58a6..00000000 --- a/source/Reloaded.Mod.Launcher/Theme/Violet/CustomStyles.xaml +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - None - - - - - - - - - - - - - - - - None - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Utility/XamlThemeSelector.cs b/source/Reloaded.Mod.Launcher/Utility/XamlThemeSelector.cs index d59fbe7a..68412582 100644 --- a/source/Reloaded.Mod.Launcher/Utility/XamlThemeSelector.cs +++ b/source/Reloaded.Mod.Launcher/Utility/XamlThemeSelector.cs @@ -33,18 +33,30 @@ protected override void UpdateSource() } catch { + var selectedTheme = File; + DownloadPackageViewModel viewModel = new([], Lib.IoC.Get()) { Progress = 0, - Text = "Downloading Theme", + Text = "Downloading Theme...", Packages = [], - DownloadTask = ThemeDownloader.DownloadThemeByName(File) }; + + viewModel.DownloadTask = ThemeDownloader.DownloadThemeByName(File, viewModel); var dialog = new DownloadPackageDialog(viewModel); dialog.ShowDialog(); dialog.ViewModel.DownloadTask!.Wait(); PopulateAndFetch(false); + + if (System.IO.File.Exists(ThemeDownloader.GetFullPath(selectedTheme))) + { + File = selectedTheme; + UpdateSource(); + OnPropertyChanged(); + return; + } + } /* From 88b227f5791eac2cc81613080ce4fcf7e65ac4b9 Mon Sep 17 00:00:00 2001 From: ZackWilde27 Date: Tue, 28 Oct 2025 01:44:35 -0600 Subject: [PATCH 4/7] Finished the theme downloader Finished all the polishing to tie everything together - Moved ThemeDownloader.cs from Launcher/Lib/Utility to Launcher/Utility, so I can do the window stuff from there - Created a new download window for themes which *should* update along with the download, it doesn't for some reason but it should - The theme doesn't switch back to default anymore when 'Fetch Themes...' is selected - The new themes are inserted into the drop down alphabetically to keep the sorting - Implemented the most bodgeyest of bodges to get it to switch to the theme after downloading --- source/Reloaded.Mod.Launcher/App.xaml.cs | 4 +- .../Pages/BaseSubpages/SettingsPage.xaml | 3 +- .../Pages/BaseSubpages/SettingsPage.xaml.cs | 7 ++ .../Pages/Dialogs/ThemeDownloadDialog.xaml | 29 ++++++ .../Pages/Dialogs/ThemeDownloadDialog.xaml.cs | 54 +++++++++++ .../Utility/ThemeDownloader.cs | 62 ++++--------- .../Utility/XamlThemeSelector.cs | 90 +++++++++++++------ 7 files changed, 175 insertions(+), 74 deletions(-) create mode 100644 source/Reloaded.Mod.Launcher/Pages/Dialogs/ThemeDownloadDialog.xaml create mode 100644 source/Reloaded.Mod.Launcher/Pages/Dialogs/ThemeDownloadDialog.xaml.cs rename source/{Reloaded.Mod.Launcher.Lib => Reloaded.Mod.Launcher}/Utility/ThemeDownloader.cs (86%) diff --git a/source/Reloaded.Mod.Launcher/App.xaml.cs b/source/Reloaded.Mod.Launcher/App.xaml.cs index 05ab0261..91a70f04 100644 --- a/source/Reloaded.Mod.Launcher/App.xaml.cs +++ b/source/Reloaded.Mod.Launcher/App.xaml.cs @@ -197,9 +197,9 @@ public void OnThemeFetch() var themeSelector = (XamlThemeSelector)Resources.MergedDictionaries[10]; foreach (string theme in ThemeDownloader.ThemesDictionary.Keys) - { + { if (!themeSelector.Files.Contains(theme)) - themeSelector.Files.Add(theme); + themeSelector.InsertAlphabetical(theme); } } } \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Pages/BaseSubpages/SettingsPage.xaml b/source/Reloaded.Mod.Launcher/Pages/BaseSubpages/SettingsPage.xaml index de51df81..f2f91194 100644 --- a/source/Reloaded.Mod.Launcher/Pages/BaseSubpages/SettingsPage.xaml +++ b/source/Reloaded.Mod.Launcher/Pages/BaseSubpages/SettingsPage.xaml @@ -122,7 +122,8 @@ ItemsSource="{Binding ThemeSelector.Files, UpdateSourceTrigger=PropertyChanged}" MaxWidth="{StaticResource ComboBoxWidth}" Width="{StaticResource ComboBoxWidth}" AutomationProperties.Name="{DynamicResource LoaderSettingsConfigTheme}" - SelectionChanged="ThemeChanged"> + SelectionChanged="ThemeChanged" + PreviewMouseDown="ThemeDropdown_PreviewMouseDown"> diff --git a/source/Reloaded.Mod.Launcher/Pages/BaseSubpages/SettingsPage.xaml.cs b/source/Reloaded.Mod.Launcher/Pages/BaseSubpages/SettingsPage.xaml.cs index 3f360f38..0e556701 100644 --- a/source/Reloaded.Mod.Launcher/Pages/BaseSubpages/SettingsPage.xaml.cs +++ b/source/Reloaded.Mod.Launcher/Pages/BaseSubpages/SettingsPage.xaml.cs @@ -51,4 +51,11 @@ private void Tutorial_Click(object sender, System.Windows.RoutedEventArgs e) } private void ControllerConfig_Click(object sender, RoutedEventArgs e) => ControllerSupport.Controller.Configure(true); + + private void ThemeDropdown_PreviewMouseDown(object sender, MouseButtonEventArgs e) + { + // TODO: Figure out why the fetch button disappears so I don't have to do this -zw + if (ViewModel.ThemeSelector?.Files[0] != XamlThemeSelector.FetchText) + ViewModel.ThemeSelector!.Files.Insert(0, XamlThemeSelector.FetchText); + } } \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Pages/Dialogs/ThemeDownloadDialog.xaml b/source/Reloaded.Mod.Launcher/Pages/Dialogs/ThemeDownloadDialog.xaml new file mode 100644 index 00000000..78892134 --- /dev/null +++ b/source/Reloaded.Mod.Launcher/Pages/Dialogs/ThemeDownloadDialog.xaml @@ -0,0 +1,29 @@ + + + + + + + + + + + diff --git a/source/Reloaded.Mod.Launcher/Pages/Dialogs/ThemeDownloadDialog.xaml.cs b/source/Reloaded.Mod.Launcher/Pages/Dialogs/ThemeDownloadDialog.xaml.cs new file mode 100644 index 00000000..1c60e7b8 --- /dev/null +++ b/source/Reloaded.Mod.Launcher/Pages/Dialogs/ThemeDownloadDialog.xaml.cs @@ -0,0 +1,54 @@ +using Reloaded.Mod.Loader.Update.Providers.GameBanana.Structures; +using System.IO.Compression; +using System.Net.Http; +using System.Net.Http.Handlers; + +namespace Reloaded.Mod.Launcher.Pages.Dialogs; + +/// +/// Interaction logic for ThemeDownloadDialog.xaml +/// +public partial class ThemeDownloadDialog : ReloadedWindow +{ + private readonly CancellationTokenSource CancellationToken; + private readonly Task DownloadTask; + + public ThemeDownloadDialog(GameBananaModFile file) + { + InitializeComponent(); + + CancellationToken = new CancellationTokenSource(); + + DownloadTask = DownloadAndExtractZip(file); + ShowDialog(); + DownloadTask.Wait(); + } + + public async Task DownloadAndExtractZip(GameBananaModFile file) + { + ThemeTextBlock.Text = $"Downloading {file.FileName}..."; + + var handler = new HttpClientHandler() { AllowAutoRedirect = true }; + var progressHandler = new ProgressMessageHandler(handler); + + // This is supposed to update the progress bar as it's downloading, emphasis on supposed to + progressHandler.HttpReceiveProgress += (obj, args) => { ThemeProgressBar.Value = (args.BytesTransferred / (double)args.TotalBytes!) * 100.0; }; + + var zipStream = await new HttpClient(progressHandler).GetStreamAsync(file.DownloadUrl); + + ThemeTextBlock.Text = $"Extracting {file.FileName}..."; + ZipFile.ExtractToDirectory(zipStream, ThemeDownloader.TempFolder); + + zipStream.Close(); + + Close(); + } + + private void CancelButton_PreviewMouseDown(object sender, MouseButtonEventArgs e) + { + if (CancellationToken.Token.CanBeCanceled) + CancellationToken.Cancel(); + + Close(); + } +} diff --git a/source/Reloaded.Mod.Launcher.Lib/Utility/ThemeDownloader.cs b/source/Reloaded.Mod.Launcher/Utility/ThemeDownloader.cs similarity index 86% rename from source/Reloaded.Mod.Launcher.Lib/Utility/ThemeDownloader.cs rename to source/Reloaded.Mod.Launcher/Utility/ThemeDownloader.cs index 6635ed34..8c855e30 100644 --- a/source/Reloaded.Mod.Launcher.Lib/Utility/ThemeDownloader.cs +++ b/source/Reloaded.Mod.Launcher/Utility/ThemeDownloader.cs @@ -1,6 +1,8 @@ -using Reloaded.Mod.Loader.Update.Providers.GameBanana.Structures; +//#define TEST_MODE -namespace Reloaded.Mod.Launcher.Lib.Utility; +using Reloaded.Mod.Loader.Update.Providers.GameBanana.Structures; + +namespace Reloaded.Mod.Launcher.Utility; /// /// Manages updating the list of available themes, and downloading/installing them @@ -26,6 +28,7 @@ private static string GetFileNameFromModName(string modName) return modName.Replace("Theme", "").Replace("theme", "").Replace(" ", " ").Trim().Replace(" ", "_"); } +#if TEST_MODE private static GameBananaModFile TestModFile(string filename, string description, string url) { var file = new GameBananaModFile(); @@ -72,6 +75,7 @@ [ TestModFile("zacksthemepackvol1.zip", "", "https://gamebanana.com/dl/1546487") ); AvailableThemes = [discordTheme, personaTheme, heroesTheme, themePack]; } +#endif /// /// Fetches all themes from GameBanana, and updates the dictionary @@ -84,9 +88,12 @@ public static async Task RefreshAvailableThemes(bool fetch=true) ThemesDictionary.Clear(); AvailableThemes.Clear(); +#if TEST_MODE TestFetch(); +#else // Hangs here forever - //AvailableThemes = await GameBananaMod.GetByNameAsync("", 7486, 1, 5, "GUIs"); + AvailableThemes = await GameBananaMod.GetByNameAsync("", 7486, 1, 5, "GUIs"); +#endif for (int i = 0; i < AvailableThemes.Count; i++) { @@ -116,11 +123,11 @@ public static async Task RefreshAvailableThemes(bool fetch=true) } private static readonly string ThemeFolder = "Theme"; - private static readonly string TempFolder = "Theme/.tmp"; - private static readonly string TempZip = "Theme/tmptheme.zip"; + public static readonly string TempFolder = "Theme/.tmp"; + public static readonly string TempZip = "Theme/tmptheme.zip"; /// - /// Turns a .xaml filename into the full absolute path + /// Turns a .xaml filename into the full absolute path for the merged dictionary /// /// The .xaml from the file selector public static string GetFullPath(string filename) @@ -133,17 +140,6 @@ public static string GetFullPath(string filename) return path; } - private static async Task DownloadAndExtractZip(GameBananaModFile file) - { - Stream data = await SharedHttpClient.UncachedAndCompressed.GetStreamAsync(file.DownloadUrl); - var zipFile = File.Create(TempZip); - data.CopyTo(zipFile); - zipFile.Close(); - data.Close(); - - ZipFile.ExtractToDirectory(TempZip, TempFolder); - } - private static readonly string[] ThemeContentsFilenames = [ "Colours.xaml", "Controls.xaml", @@ -226,13 +222,7 @@ private static bool ThemeNeedsToBeCreated(out List existingXAMLs) return createTheme; } - private static void UpdateDownloadWindow(DownloadPackageViewModel viewModel, double progress, string text) - { - viewModel.Progress = progress; - viewModel.Text = text; - } - - private static async Task DownloadTheme(GameBananaMod theme, DownloadPackageViewModel viewModel) + private static void DownloadTheme(GameBananaMod theme) { // There needs to be a standard for how to upload themes // I'll support all of the current ones but there's likely to be an edge case that causes it to break in the future -zw @@ -243,16 +233,12 @@ private static async Task DownloadTheme(GameBananaMod theme, DownloadPackageView // These should be deleted at the end but just in case it crashes or something DeleteTempFiles(); - UpdateDownloadWindow(viewModel, 0, "Downloading Theme..."); - string themeName = GetFileNameFromModName(theme.Name!); string themeFolder = $"{ThemeFolder}/{themeName}"; if (theme.Files.Count == 1 && theme.Files[0].FileName.EndsWith(".zip")) { - await DownloadAndExtractZip(theme.Files[0]); - - UpdateDownloadWindow(viewModel, 50, "Installing Theme..."); + new ThemeDownloadDialog(theme.Files[0]); if (ThemeNeedsToBeCreated(out var existingXAMLs)) { @@ -281,24 +267,16 @@ private static async Task DownloadTheme(GameBananaMod theme, DownloadPackageView // Checking for the heroes mod loader theme else if (theme.Files.Count == 2 && theme.Files[0].FileName == "default_5073e.zip") { - await DownloadAndExtractZip(theme.Files[0]); - - UpdateDownloadWindow(viewModel, 20, "Installing Theme..."); + new ThemeDownloadDialog(theme.Files[0]); Directory.Move($"{TempFolder}/Default", themeFolder); Directory.Delete(TempFolder); - UpdateDownloadWindow(viewModel, 40, "Downloading Image..."); - - await DownloadAndExtractZip(theme.Files[1]); - - UpdateDownloadWindow(viewModel, 60, "Installing Image..."); + new ThemeDownloadDialog(theme.Files[1]); string imagesFolder = $"{themeFolder}/Images"; Directory.Move(TempFolder, imagesFolder); - UpdateDownloadWindow(viewModel, 80, "Finishing Up..."); - File.Move($"{themeFolder}/R-II/Controls.xaml", $"{themeFolder}/Controls.xaml"); CopyFromHalogen($"{ThemeFolder}/Halogen/CustomStyles.xaml", $"{themeFolder}/CustomStyles.xaml", themeName); File.WriteAllText($"{themeFolder}/Images.xaml", File.ReadAllText($"{themeFolder}/R-II/Images.xaml").Replace("Default/R-II/Images/R", $"{themeName}/Images/R")); @@ -307,8 +285,6 @@ private static async Task DownloadTheme(GameBananaMod theme, DownloadPackageView CopyFromHalogen($"{ThemeFolder}/Halogen.xaml", themeFolder + ".xaml", themeName); } - UpdateDownloadWindow(viewModel, 100, "Done!"); - DeleteTempFiles(); } @@ -317,13 +293,13 @@ private static async Task DownloadTheme(GameBananaMod theme, DownloadPackageView /// /// The .xaml to load from the theme selector /// The view model for the download window, so it can update the progress bar and text as it goes - public static async Task DownloadThemeByName(string name, DownloadPackageViewModel viewModel) + public static void DownloadThemeByName(string name) { foreach ((var subtheme, var index) in ThemesDictionary) { if (subtheme == name) { - await DownloadTheme(AvailableThemes[index], viewModel); + DownloadTheme(AvailableThemes[index]); break; } } diff --git a/source/Reloaded.Mod.Launcher/Utility/XamlThemeSelector.cs b/source/Reloaded.Mod.Launcher/Utility/XamlThemeSelector.cs index 68412582..ea828cd7 100644 --- a/source/Reloaded.Mod.Launcher/Utility/XamlThemeSelector.cs +++ b/source/Reloaded.Mod.Launcher/Utility/XamlThemeSelector.cs @@ -2,18 +2,30 @@ public class XamlThemeSelector : XamlFileSelector { + public static readonly string FetchText = "Fetch Themes..."; + + private void InsertFetchButton() + { + Files.Insert(0, FetchText); + } + public XamlThemeSelector(string directoryPath) : base(directoryPath) { - Files.Insert(0, "Fetch Themes..."); + InsertFetchButton(); } - private void PopulateAndFetch(bool fetch=true) + private void PopulateAndFetch(string selectedTheme, bool fetch=true) { PopulateXamlFiles(); - ThemeDownloader.RefreshAvailableThemes(fetch).Wait(); + InsertFetchButton(); - Files.Insert(0, "Fetch Themes..."); + if (System.IO.File.Exists(selectedTheme)) + { + // Why do I need to do it twice? I don't know -zw + File = selectedTheme; + File = selectedTheme; + } } protected override void UpdateSource() @@ -21,9 +33,9 @@ protected override void UpdateSource() if (File == null) return; - if (File == "Fetch Themes...") + if (File == FetchText) { - PopulateAndFetch(); + PopulateAndFetch(ThemeDownloader.GetFullPath(Path.GetFileName(Source.ToString()))); return; } @@ -34,29 +46,12 @@ protected override void UpdateSource() catch { var selectedTheme = File; + ThemeDownloader.DownloadThemeByName(File); + PopulateAndFetch(selectedTheme, false); - DownloadPackageViewModel viewModel = new([], Lib.IoC.Get()) - { - Progress = 0, - Text = "Downloading Theme...", - Packages = [], - }; - - viewModel.DownloadTask = ThemeDownloader.DownloadThemeByName(File, viewModel); - var dialog = new DownloadPackageDialog(viewModel); - dialog.ShowDialog(); - dialog.ViewModel.DownloadTask!.Wait(); - - PopulateAndFetch(false); - - if (System.IO.File.Exists(ThemeDownloader.GetFullPath(selectedTheme))) - { - File = selectedTheme; - UpdateSource(); - OnPropertyChanged(); - return; - } - + // Probably the bodgey-est bodge I've ever done -zw + File = Files.FirstOrDefault(); + File = selectedTheme; } /* @@ -71,4 +66,43 @@ user loaded in complex images. OnNewFileSet(); } + + private static int LetterIndex(string str, int letterIndex) + { + string letterChart = "abcdefghijklmnopqrstuvwxyz"; + return letterChart.IndexOf(str.ToLower()[letterIndex]); + } + + // Returns true if str1 should be ordered after str2 + private static bool AlphabeticalCompare(string str1, string str2) + { + int length = Math.Min(str1.Length, str2.Length); + for (int i = 0; i < length; i++) + { + int index1 = LetterIndex(str1, i); + int index2 = LetterIndex(str2, i); + if (index1 == index2) continue; + + return index1 > index2; + } + + return str1.Length > str2.Length; + } + + /// + /// Places the new entry in a spot to keep the alphabetical sorting + /// + public void InsertAlphabetical(string item) + { + for (int i = Files[0] == FetchText ? 1 : 0; i < Files.Count; i++) + { + if (AlphabeticalCompare(Files[i], item)) + { + Files.Insert(i, item); + return; + } + } + + Files.Add(item); + } } From 47754cc0853971ac53fac7ae91dc2153875d6268 Mon Sep 17 00:00:00 2001 From: ZackWilde27 Date: Wed, 29 Oct 2025 03:29:32 -0600 Subject: [PATCH 5/7] Added a retry policy I added a retry policy to both downloading themes, and fetching them Also cleaned up a couple things while I was doing that - Removed the unnecessary binding to ThemeDownloadDialog's progress bar value - Removed the documentation for a parameter on DownloadThemeByName that isn't there anymore --- .../Pages/Dialogs/ThemeDownloadDialog.xaml | 2 +- .../Pages/Dialogs/ThemeDownloadDialog.xaml.cs | 20 ++++++++++++++- .../Utility/ThemeDownloader.cs | 25 +++++++++++++++---- 3 files changed, 40 insertions(+), 7 deletions(-) diff --git a/source/Reloaded.Mod.Launcher/Pages/Dialogs/ThemeDownloadDialog.xaml b/source/Reloaded.Mod.Launcher/Pages/Dialogs/ThemeDownloadDialog.xaml index 78892134..791f2335 100644 --- a/source/Reloaded.Mod.Launcher/Pages/Dialogs/ThemeDownloadDialog.xaml +++ b/source/Reloaded.Mod.Launcher/Pages/Dialogs/ThemeDownloadDialog.xaml @@ -17,7 +17,7 @@ - + { ThemeProgressBar.Value = (args.BytesTransferred / (double)args.TotalBytes!) * 100.0; }; - var zipStream = await new HttpClient(progressHandler).GetStreamAsync(file.DownloadUrl); + int attempts = 0; + Stream zipStream; + Retry: + try + { + zipStream = await new HttpClient(progressHandler).GetStreamAsync(file.DownloadUrl); + } + catch (Exception e) + { + if (attempts++ < 10) + goto Retry; + + var messageBox = new MessageBox("Theme Download Error", "Failed to download the mod! Check your internet connection, and if that's good, it might just be GameBanana's servers acting up, try again later"); + messageBox.ShowDialog(); + + // I know, I know, gotos are bad, but in this case it saves a few lines of code -zw + goto Exit; + } ThemeTextBlock.Text = $"Extracting {file.FileName}..."; ZipFile.ExtractToDirectory(zipStream, ThemeDownloader.TempFolder); zipStream.Close(); + Exit: Close(); } diff --git a/source/Reloaded.Mod.Launcher/Utility/ThemeDownloader.cs b/source/Reloaded.Mod.Launcher/Utility/ThemeDownloader.cs index 8c855e30..aeb05b80 100644 --- a/source/Reloaded.Mod.Launcher/Utility/ThemeDownloader.cs +++ b/source/Reloaded.Mod.Launcher/Utility/ThemeDownloader.cs @@ -1,6 +1,7 @@ //#define TEST_MODE using Reloaded.Mod.Loader.Update.Providers.GameBanana.Structures; +using MessageBox = Reloaded.Mod.Launcher.Pages.Dialogs.MessageBox; namespace Reloaded.Mod.Launcher.Utility; @@ -91,8 +92,23 @@ public static async Task RefreshAvailableThemes(bool fetch=true) #if TEST_MODE TestFetch(); #else - // Hangs here forever - AvailableThemes = await GameBananaMod.GetByNameAsync("", 7486, 1, 5, "GUIs"); + int attempts = 0; + Retry: + try + { + // Hangs here forever + AvailableThemes = await GameBananaMod.GetByNameAsync("", 7486, 1, 5, "GUIs"); + } + catch (Exception e) + { + if (attempts++ < 10) + goto Retry; + + var messageBox = new MessageBox("Fetch Error", "Failed to fetch the mods! Check your internet connection, and if that's good, it might just be GameBanana's servers acting up, try again later"); + messageBox.ShowDialog(); + + return; + } #endif for (int i = 0; i < AvailableThemes.Count; i++) @@ -123,8 +139,8 @@ public static async Task RefreshAvailableThemes(bool fetch=true) } private static readonly string ThemeFolder = "Theme"; - public static readonly string TempFolder = "Theme/.tmp"; - public static readonly string TempZip = "Theme/tmptheme.zip"; + public static readonly string TempFolder = $"{ThemeFolder}/.tmp"; + public static readonly string TempZip = $"{ThemeFolder}/tmptheme.zip"; /// /// Turns a .xaml filename into the full absolute path for the merged dictionary @@ -292,7 +308,6 @@ private static void DownloadTheme(GameBananaMod theme) /// Finds the theme from the given .xaml, and then downloads and installs it /// /// The .xaml to load from the theme selector - /// The view model for the download window, so it can update the progress bar and text as it goes public static void DownloadThemeByName(string name) { foreach ((var subtheme, var index) in ThemesDictionary) From 4792969ec3f41d7b62bb6d66959d561bd3150930 Mon Sep 17 00:00:00 2001 From: ZackWilde27 Date: Wed, 29 Oct 2025 18:50:31 -0600 Subject: [PATCH 6/7] Final (I think) fixes to the theme downloader - Added a cancel button and associated logic when downloading themes - Made the text colour be the opposite of the progress bar below it - Added a try catch around extracting a theme, just in case - Moved the dialog handling to a task, which I was hoping would allow the progress bar to update but sadly still no - The download dialog is only created once and then reused, so it doesn't pop up twice when downloading the heroes mod loader theme --- .../Pages/Dialogs/ThemeDownloadDialog.xaml | 18 ++++-- .../Pages/Dialogs/ThemeDownloadDialog.xaml.cs | 60 ++++++++++++++----- .../Utility/ThemeDownloader.cs | 16 +++-- .../Utility/XamlThemeSelector.cs | 30 +++++++--- 4 files changed, 92 insertions(+), 32 deletions(-) diff --git a/source/Reloaded.Mod.Launcher/Pages/Dialogs/ThemeDownloadDialog.xaml b/source/Reloaded.Mod.Launcher/Pages/Dialogs/ThemeDownloadDialog.xaml index 791f2335..97c43d27 100644 --- a/source/Reloaded.Mod.Launcher/Pages/Dialogs/ThemeDownloadDialog.xaml +++ b/source/Reloaded.Mod.Launcher/Pages/Dialogs/ThemeDownloadDialog.xaml @@ -16,13 +16,23 @@ - - + + + VerticalAlignment="Center"> + + + + + + + + + + + diff --git a/source/Reloaded.Mod.Launcher/Pages/Dialogs/ThemeDownloadDialog.xaml.cs b/source/Reloaded.Mod.Launcher/Pages/Dialogs/ThemeDownloadDialog.xaml.cs index 4874485a..9268aa6d 100644 --- a/source/Reloaded.Mod.Launcher/Pages/Dialogs/ThemeDownloadDialog.xaml.cs +++ b/source/Reloaded.Mod.Launcher/Pages/Dialogs/ThemeDownloadDialog.xaml.cs @@ -5,61 +5,91 @@ namespace Reloaded.Mod.Launcher.Pages.Dialogs; +public enum ThemeDownloadDialogResult +{ + Ok, + Cancelled, + Failed +} + + /// /// Interaction logic for ThemeDownloadDialog.xaml /// public partial class ThemeDownloadDialog : ReloadedWindow { - private readonly CancellationTokenSource CancellationToken; - private readonly Task DownloadTask; + private CancellationTokenSource CancellationToken; - public ThemeDownloadDialog(GameBananaModFile file) + public ThemeDownloadDialog() { InitializeComponent(); CancellationToken = new CancellationTokenSource(); + } + + // progress is measured from 0-1 + private void UpdateProgressBar(double progress) + { + for (int i = 0; i < 2; i++) + ((System.Windows.Media.LinearGradientBrush)ThemeTextBlock.Foreground).GradientStops[i].Offset = progress; - DownloadTask = DownloadAndExtractZip(file); - ShowDialog(); - DownloadTask.Wait(); + ThemeProgressBar.Value = progress * 100; } - public async Task DownloadAndExtractZip(GameBananaModFile file) + public async Task DownloadAndExtractZip(GameBananaModFile file) { + CancellationToken = new CancellationTokenSource(); + + var result = ThemeDownloadDialogResult.Ok; + + UpdateProgressBar(0); ThemeTextBlock.Text = $"Downloading {file.FileName}..."; var handler = new HttpClientHandler() { AllowAutoRedirect = true }; var progressHandler = new ProgressMessageHandler(handler); - // This is supposed to update the progress bar as it's downloading, emphasis on supposed to - progressHandler.HttpReceiveProgress += (obj, args) => { ThemeProgressBar.Value = (args.BytesTransferred / (double)args.TotalBytes!) * 100.0; }; + progressHandler.HttpReceiveProgress += (obj, args) => { UpdateProgressBar(args.BytesTransferred / (double)args.TotalBytes!); }; int attempts = 0; Stream zipStream; Retry: try { - zipStream = await new HttpClient(progressHandler).GetStreamAsync(file.DownloadUrl); + zipStream = await new HttpClient(progressHandler).GetStreamAsync(file.DownloadUrl, CancellationToken.Token); } - catch (Exception e) + catch { if (attempts++ < 10) goto Retry; - var messageBox = new MessageBox("Theme Download Error", "Failed to download the mod! Check your internet connection, and if that's good, it might just be GameBanana's servers acting up, try again later"); + var messageBox = new MessageBox("Theme Download Error", "Failed to download the theme! Check your internet connection, and if that's good, it might just be GameBanana's servers acting up, try again later"); messageBox.ShowDialog(); + result = ThemeDownloadDialogResult.Failed; // I know, I know, gotos are bad, but in this case it saves a few lines of code -zw goto Exit; } - ThemeTextBlock.Text = $"Extracting {file.FileName}..."; - ZipFile.ExtractToDirectory(zipStream, ThemeDownloader.TempFolder); + if (CancellationToken.IsCancellationRequested) + result = ThemeDownloadDialogResult.Cancelled; + else + { + ThemeTextBlock.Text = $"Extracting {file.FileName}..."; + try + { + ZipFile.ExtractToDirectory(zipStream, ThemeDownloader.TempFolder); + } + catch + { + result = ThemeDownloadDialogResult.Failed; + goto Exit; + } + } zipStream.Close(); Exit: - Close(); + return result; } private void CancelButton_PreviewMouseDown(object sender, MouseButtonEventArgs e) diff --git a/source/Reloaded.Mod.Launcher/Utility/ThemeDownloader.cs b/source/Reloaded.Mod.Launcher/Utility/ThemeDownloader.cs index aeb05b80..b6aed108 100644 --- a/source/Reloaded.Mod.Launcher/Utility/ThemeDownloader.cs +++ b/source/Reloaded.Mod.Launcher/Utility/ThemeDownloader.cs @@ -238,7 +238,7 @@ private static bool ThemeNeedsToBeCreated(out List existingXAMLs) return createTheme; } - private static void DownloadTheme(GameBananaMod theme) + private static async Task DownloadTheme(GameBananaMod theme, ThemeDownloadDialog dialog) { // There needs to be a standard for how to upload themes // I'll support all of the current ones but there's likely to be an edge case that causes it to break in the future -zw @@ -254,7 +254,8 @@ private static void DownloadTheme(GameBananaMod theme) if (theme.Files.Count == 1 && theme.Files[0].FileName.EndsWith(".zip")) { - new ThemeDownloadDialog(theme.Files[0]); + if (await dialog.DownloadAndExtractZip(theme.Files[0]) != ThemeDownloadDialogResult.Ok) + goto Exit; if (ThemeNeedsToBeCreated(out var existingXAMLs)) { @@ -283,12 +284,13 @@ private static void DownloadTheme(GameBananaMod theme) // Checking for the heroes mod loader theme else if (theme.Files.Count == 2 && theme.Files[0].FileName == "default_5073e.zip") { - new ThemeDownloadDialog(theme.Files[0]); + + if (await dialog.DownloadAndExtractZip(theme.Files[0]) != ThemeDownloadDialogResult.Ok) goto Exit; Directory.Move($"{TempFolder}/Default", themeFolder); Directory.Delete(TempFolder); - new ThemeDownloadDialog(theme.Files[1]); + if (await dialog.DownloadAndExtractZip(theme.Files[1]) != ThemeDownloadDialogResult.Ok) goto Exit; string imagesFolder = $"{themeFolder}/Images"; Directory.Move(TempFolder, imagesFolder); @@ -301,6 +303,8 @@ private static void DownloadTheme(GameBananaMod theme) CopyFromHalogen($"{ThemeFolder}/Halogen.xaml", themeFolder + ".xaml", themeName); } + Exit: + dialog.Close(); DeleteTempFiles(); } @@ -308,13 +312,13 @@ private static void DownloadTheme(GameBananaMod theme) /// Finds the theme from the given .xaml, and then downloads and installs it /// /// The .xaml to load from the theme selector - public static void DownloadThemeByName(string name) + public static async Task DownloadThemeByName(string name, ThemeDownloadDialog dialog) { foreach ((var subtheme, var index) in ThemesDictionary) { if (subtheme == name) { - DownloadTheme(AvailableThemes[index]); + await DownloadTheme(AvailableThemes[index], dialog); break; } } diff --git a/source/Reloaded.Mod.Launcher/Utility/XamlThemeSelector.cs b/source/Reloaded.Mod.Launcher/Utility/XamlThemeSelector.cs index ea828cd7..9b9c4f8c 100644 --- a/source/Reloaded.Mod.Launcher/Utility/XamlThemeSelector.cs +++ b/source/Reloaded.Mod.Launcher/Utility/XamlThemeSelector.cs @@ -28,6 +28,27 @@ private void PopulateAndFetch(string selectedTheme, bool fetch=true) } } + private async Task DownloadTheme() + { + string selectedTheme = File!; + + var dialog = new ThemeDownloadDialog(); + var task = ThemeDownloader.DownloadThemeByName(File, dialog); + dialog.ShowDialog(); + await task; + + bool exists = System.IO.File.Exists(selectedTheme); + + PopulateAndFetch(exists ? selectedTheme : ThemeDownloader.GetFullPath("Default.xaml"), false); + + if (exists) + { + // Probably the bodgey-est bodge I've ever done -zw + File = Files.FirstOrDefault(); + File = selectedTheme; + } + } + protected override void UpdateSource() { if (File == null) @@ -45,13 +66,8 @@ protected override void UpdateSource() } catch { - var selectedTheme = File; - ThemeDownloader.DownloadThemeByName(File); - PopulateAndFetch(selectedTheme, false); - - // Probably the bodgey-est bodge I've ever done -zw - File = Files.FirstOrDefault(); - File = selectedTheme; + DownloadTheme(); + return; } /* From 9f736458a5d70721acc82e3180bdffcae628b617 Mon Sep 17 00:00:00 2001 From: ZackWilde27 Date: Sun, 16 Nov 2025 17:32:09 -0700 Subject: [PATCH 7/7] New standard for uploading themes, and fixes A standard for uploading themes has been decided, and some fixes on top of that - Changed theme fetching to match the standard (with some exceptions for existing themes) - Implemented the deadlock fix that Sewer suggested - Themes now fetch from the default category, and have a take of 50 Once the other themes have been changed to match the standard, I'll be back to remove the exceptions --- .../Utility/ThemeDownloader.cs | 84 +++++++++++-------- .../Utility/XamlThemeSelector.cs | 7 +- 2 files changed, 52 insertions(+), 39 deletions(-) diff --git a/source/Reloaded.Mod.Launcher/Utility/ThemeDownloader.cs b/source/Reloaded.Mod.Launcher/Utility/ThemeDownloader.cs index b6aed108..c47e0b23 100644 --- a/source/Reloaded.Mod.Launcher/Utility/ThemeDownloader.cs +++ b/source/Reloaded.Mod.Launcher/Utility/ThemeDownloader.cs @@ -12,21 +12,25 @@ public class ThemeDownloader { private static List AvailableThemes = []; - // Things like my theme pack contain multiple themes in one (bad idea in hindsight), so now I have to account for that -zw /// - /// The key is the name of a subtheme contained in a pack, the value is the index into AvailableThemes + /// The key is the name of a subtheme contained in a pack, the value is a 32-bit index into available themes concatenated with a 32-bit file index /// - public static Dictionary ThemesDictionary = []; + public static Dictionary ThemesDictionary = []; /// /// Called after RefreshAvailableThemes runs /// public static Action? OnRefresh = null; - private static string GetFileNameFromModName(string modName) + // If using the mod's name as the theme name, it will remove 'theme' from the name, fix any double spaces that might cause, trim it, and then replace spaces with underscores + private static string GetFileNameFromModName(string modName) => modName.Replace("Theme", "").Replace("theme", "").Replace(" ", " ").Trim().Replace(" ", "_"); + + private static ulong CombineIndices(int themeIndex, int fileIndex) => ((ulong)themeIndex << 32) | (uint)fileIndex; + + private static void SeparateIndices(ulong index, out int themeIndex, out int fileIndex) { - // If using the mod's name as the theme name, it will remove 'theme' from the name, fix any double spaces that might cause, trim it, and then replace spaces with underscores - return modName.Replace("Theme", "").Replace("theme", "").Replace(" ", " ").Trim().Replace(" ", "_"); + themeIndex = (int)(index >> 32); + fileIndex = (int)(index & uint.MaxValue); } #if TEST_MODE @@ -96,8 +100,7 @@ public static async Task RefreshAvailableThemes(bool fetch=true) Retry: try { - // Hangs here forever - AvailableThemes = await GameBananaMod.GetByNameAsync("", 7486, 1, 5, "GUIs"); + AvailableThemes = await GameBananaMod.GetByNameAsync("theme", 7486, 1, 50); } catch (Exception e) { @@ -111,27 +114,34 @@ public static async Task RefreshAvailableThemes(bool fetch=true) } #endif - for (int i = 0; i < AvailableThemes.Count; i++) + for (int themeIndex = 0; themeIndex < AvailableThemes.Count; themeIndex++) { - var theme = AvailableThemes[i]; + var theme = AvailableThemes[themeIndex]; if (theme.Name == null) continue; - // It checks for a bullet-point list to determine which themes are contained in a pack - if (theme.Description != null && theme.Description.Contains("", startIndex) + 1; - var endIndex = theme.Description.IndexOf("
"); - var containingThemes = theme.Description[startIndex..endIndex].Replace("
  • ", "").Replace(" ", "_").Replace("\n", "").Split("
  • ")[..^1]; - foreach (var subtheme in containingThemes) - { - if (subtheme != "") - ThemesDictionary.Add(GetFullPath(subtheme + ".xaml"), i); - } + case "default_5073e.zip": + ThemesDictionary.Add(GetFullPath("heroes_mod_loader.xaml"), CombineIndices(themeIndex, 0)); + continue; + + case "p4g_theme.zip": + ThemesDictionary.Add(GetFullPath("Persona_4_Golden.xaml"), CombineIndices(themeIndex, 0)); + continue; + + // Unfortunately even the discord theme needs an exception here since the zip name isn't capitalized like the xaml + case "discord.zip": + ThemesDictionary.Add(GetFullPath("Discord.xaml"), CombineIndices(themeIndex, 0)); + continue; + + default: + for (int fileIndex = 0; fileIndex < theme.Files.Count; fileIndex++) + { + if (theme.Files[fileIndex].FileName.EndsWith(".zip")) + ThemesDictionary.Add(GetFullPath(theme.Files[fileIndex].FileName[..^4] + ".xaml"), CombineIndices(themeIndex, fileIndex)); + } + break; } - else - ThemesDictionary.Add(GetFullPath(GetFileNameFromModName(theme.Name) + ".xaml"), i); } } @@ -238,10 +248,10 @@ private static bool ThemeNeedsToBeCreated(out List existingXAMLs) return createTheme; } - private static async Task DownloadTheme(GameBananaMod theme, ThemeDownloadDialog dialog) + private static async Task DownloadTheme(GameBananaMod theme, string themeName, int fileIndex, ThemeDownloadDialog dialog) { - // There needs to be a standard for how to upload themes - // I'll support all of the current ones but there's likely to be an edge case that causes it to break in the future -zw + // The standard is 1 theme per zip file + // I'll still support all of the current ones as of writing this though if (theme.Files == null || theme.Files.Count == 0) return; @@ -249,12 +259,14 @@ private static async Task DownloadTheme(GameBananaMod theme, ThemeDownloadDialog // These should be deleted at the end but just in case it crashes or something DeleteTempFiles(); - string themeName = GetFileNameFromModName(theme.Name!); string themeFolder = $"{ThemeFolder}/{themeName}"; - if (theme.Files.Count == 1 && theme.Files[0].FileName.EndsWith(".zip")) + GameBananaModFile file = theme.Files[fileIndex]; + + // It would make more sense to have it be == and then return, but I want the diff to be as clean as possible -zw + if (file.FileName != "default_5073e.zip") { - if (await dialog.DownloadAndExtractZip(theme.Files[0]) != ThemeDownloadDialogResult.Ok) + if (await dialog.DownloadAndExtractZip(file) != ThemeDownloadDialogResult.Ok) goto Exit; if (ThemeNeedsToBeCreated(out var existingXAMLs)) @@ -263,7 +275,7 @@ private static async Task DownloadTheme(GameBananaMod theme, ThemeDownloadDialog MoveTempFiles(themeFolder); // Checking for the persona 4 golden theme - if (theme.Files[0].FileName == "p4g_theme.zip") + if (theme.Files[fileIndex].FileName == "p4g_theme.zip") { Directory.Move($"{themeFolder}/R-II/Images", $"{themeFolder}/Images"); File.Move($"{themeFolder}/R-II/Settings.xaml", $"{themeFolder}/Settings.xaml"); @@ -282,9 +294,8 @@ private static async Task DownloadTheme(GameBananaMod theme, ThemeDownloadDialog MoveTempFiles(ThemeFolder); } // Checking for the heroes mod loader theme - else if (theme.Files.Count == 2 && theme.Files[0].FileName == "default_5073e.zip") + else { - if (await dialog.DownloadAndExtractZip(theme.Files[0]) != ThemeDownloadDialogResult.Ok) goto Exit; Directory.Move($"{TempFolder}/Default", themeFolder); @@ -314,11 +325,12 @@ private static async Task DownloadTheme(GameBananaMod theme, ThemeDownloadDialog /// The .xaml to load from the theme selector public static async Task DownloadThemeByName(string name, ThemeDownloadDialog dialog) { - foreach ((var subtheme, var index) in ThemesDictionary) + foreach ((var theme, var index) in ThemesDictionary) { - if (subtheme == name) + if (theme == name) { - await DownloadTheme(AvailableThemes[index], dialog); + SeparateIndices(index, out var themeIndex, out var fileIndex); + await DownloadTheme(AvailableThemes[themeIndex], Path.GetFileName(name)[..^5], fileIndex, dialog); break; } } diff --git a/source/Reloaded.Mod.Launcher/Utility/XamlThemeSelector.cs b/source/Reloaded.Mod.Launcher/Utility/XamlThemeSelector.cs index 9b9c4f8c..463bf5e7 100644 --- a/source/Reloaded.Mod.Launcher/Utility/XamlThemeSelector.cs +++ b/source/Reloaded.Mod.Launcher/Utility/XamlThemeSelector.cs @@ -6,7 +6,8 @@ public class XamlThemeSelector : XamlFileSelector private void InsertFetchButton() { - Files.Insert(0, FetchText); + if (Files[0] != FetchText) + Files.Insert(0, FetchText); } public XamlThemeSelector(string directoryPath) : base(directoryPath) @@ -14,10 +15,10 @@ public XamlThemeSelector(string directoryPath) : base(directoryPath) InsertFetchButton(); } - private void PopulateAndFetch(string selectedTheme, bool fetch=true) + private async void PopulateAndFetch(string selectedTheme, bool fetch=true) { PopulateXamlFiles(); - ThemeDownloader.RefreshAvailableThemes(fetch).Wait(); + await ThemeDownloader.RefreshAvailableThemes(fetch); InsertFetchButton(); if (System.IO.File.Exists(selectedTheme))