From 36ab743b7dc8e21ec325931aba6b341cc112f4b7 Mon Sep 17 00:00:00 2001 From: Patrick <147879351+WinniePatGG@users.noreply.github.com> Date: Sun, 21 Jun 2026 00:48:38 +0200 Subject: [PATCH] Settings Menu. Please help me find someone who can do this better --- .../parrotmod/ui/BaseTabFragment.java | 59 +++++++-- .../parrotmod/ui/DiscordTabFragment.java | 16 +-- .../parrotmod/ui/GeneralTabFragment.java | 16 ++- .../parrotmod/ui/InfoTabFragment.java | 20 +-- .../parrotmod/ui/SettingsFragment.java | 114 ++++++++++++------ 5 files changed, 154 insertions(+), 71 deletions(-) diff --git a/src/main/java/de/winniepat/parrotmod/ui/BaseTabFragment.java b/src/main/java/de/winniepat/parrotmod/ui/BaseTabFragment.java index 919ac3f..af89160 100644 --- a/src/main/java/de/winniepat/parrotmod/ui/BaseTabFragment.java +++ b/src/main/java/de/winniepat/parrotmod/ui/BaseTabFragment.java @@ -11,8 +11,12 @@ import icyllis.modernui.widget.TextView; public abstract class BaseTabFragment extends Fragment { - protected static final int COLOR_CARD = 0xFF1A1A22; - protected static final int COLOR_ACCENT = 0xFF00E5FF; + protected static final int COLOR_CARD = 0xFF23232D; + protected static final int COLOR_ACCENT = 0xFF5CF392; + protected static final int COLOR_ACCENT_DIM = 0xFF3E8E5A; + protected static final int COLOR_TEXT_MAIN = 0xFFF0F0F0; + protected static final int COLOR_TEXT_SEC = 0xFF9EA3AF; + protected static final int COLOR_CARD_BORDER = 0x265CF392; protected int dp(float dp) { return (int) (dp * getContext().getResources().getDisplayMetrics().density); @@ -22,7 +26,7 @@ public abstract class BaseTabFragment extends Fragment { TextView tv = new TextView(getContext()); tv.setText(text); tv.setTextSize(14); - tv.setTextColor(0xFFEEEEEE); + tv.setTextColor(COLOR_TEXT_MAIN); var p = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); p.topMargin = dp(12); p.bottomMargin = dp(4); @@ -37,20 +41,45 @@ public abstract class BaseTabFragment extends Fragment { tv.setTextColor(COLOR_ACCENT); var p = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); p.topMargin = dp(24); - p.bottomMargin = dp(8); + p.bottomMargin = dp(10); p.leftMargin = dp(4); parent.addView(tv, p); } + protected void addTabHeader(LinearLayout parent, String title, String description) { + TextView titleView = new TextView(getContext()); + titleView.setText(title); + titleView.setTextSize(24); + titleView.setTextColor(0xFFFFFFFF); + titleView.setPadding(0, 0, 0, dp(2)); + parent.addView(titleView); + + if (description != null) { + TextView descView = new TextView(getContext()); + descView.setText(description); + descView.setTextSize(13); + descView.setTextColor(COLOR_TEXT_SEC); + descView.setPadding(0, 0, 0, dp(16)); + parent.addView(descView); + } + + View divider = new View(getContext()); + var divParams = new LinearLayout.LayoutParams(dp(40), dp(3)); + divParams.bottomMargin = dp(16); + divider.setLayoutParams(divParams); + divider.setBackground(makeRoundedBg(COLOR_ACCENT, 2)); + parent.addView(divider); + } + protected LinearLayout createSettingCard(String title, String description) { LinearLayout card = new LinearLayout(getContext()); card.setOrientation(LinearLayout.HORIZONTAL); card.setGravity(Gravity.CENTER_VERTICAL); - card.setPadding(dp(16), dp(12), dp(16), dp(12)); - card.setBackground(makeRoundedBg(COLOR_CARD, 12)); + card.setPadding(dp(18), dp(14), dp(18), dp(14)); + card.setBackground(makeBorderedBg(COLOR_CARD, COLOR_CARD_BORDER, 10, 1)); var cardParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); - cardParams.bottomMargin = dp(8); + cardParams.bottomMargin = dp(10); card.setLayoutParams(cardParams); LinearLayout textLayout = new LinearLayout(getContext()); @@ -60,15 +89,15 @@ public abstract class BaseTabFragment extends Fragment { TextView titleView = new TextView(getContext()); titleView.setText(title); - titleView.setTextSize(15); - titleView.setTextColor(0xFFFFFFFF); + titleView.setTextSize(15.5f); + titleView.setTextColor(COLOR_TEXT_MAIN); textLayout.addView(titleView); if (description != null) { TextView descView = new TextView(getContext()); descView.setText(description); - descView.setTextSize(12); - descView.setTextColor(0xFF888888); + descView.setTextSize(12.5f); + descView.setTextColor(COLOR_TEXT_SEC); textLayout.addView(descView); } @@ -82,6 +111,14 @@ public abstract class BaseTabFragment extends Fragment { return d; } + protected ShapeDrawable makeBorderedBg(int color, int strokeColor, float radius, float strokeWidth) { + ShapeDrawable d = new ShapeDrawable(); + d.setCornerRadius(dp(radius)); + d.setColor(color); + d.setStroke(dp(strokeWidth), strokeColor); + return d; + } + @Override public void onViewCreated(View view, icyllis.modernui.util.DataSet savedInstanceState) { super.onViewCreated(view, savedInstanceState); diff --git a/src/main/java/de/winniepat/parrotmod/ui/DiscordTabFragment.java b/src/main/java/de/winniepat/parrotmod/ui/DiscordTabFragment.java index 06d7248..19a6fc6 100644 --- a/src/main/java/de/winniepat/parrotmod/ui/DiscordTabFragment.java +++ b/src/main/java/de/winniepat/parrotmod/ui/DiscordTabFragment.java @@ -21,33 +21,35 @@ public class DiscordTabFragment extends BaseTabFragment { LinearLayout layout = new LinearLayout(getContext()); layout.setOrientation(LinearLayout.VERTICAL); - layout.setPadding(dp(24), dp(8), dp(24), dp(24)); + layout.setPadding(dp(28), dp(24), dp(28), dp(24)); scrollView.addView(layout); - addSectionHeader(layout, "Discord Integration"); + addTabHeader(layout, "Discord Rich Presence", "Connect your Minecraft activity to your Discord profile."); - addSwitchRow(layout, "Enable DiscordRPC", "Show your game status on Discord", + addSectionHeader(layout, "Core Integration"); + + addSwitchRow(layout, "Status Integration", "Toggle Discord Rich Presence globally.", ConfigManager.getInstance().enableDiscordRPC, (v, checked) -> { ConfigManager.getInstance().enableDiscordRPC = checked; ConfigManager.save(); updateRPCDetailsEnabled(checked); }); - addSectionHeader(layout, "RPC Details"); + addSectionHeader(layout, "Status Customization"); - rpcDetailViews.add(addSwitchRow(layout, "Show Biome", "Display current biome in status", + rpcDetailViews.add(addSwitchRow(layout, "Location Tracking", "Broadcast your current biome.", ConfigManager.getInstance().showBiomeInRPC, (v, checked) -> { ConfigManager.getInstance().showBiomeInRPC = checked; ConfigManager.save(); })); - rpcDetailViews.add(addSwitchRow(layout, "Show Held Item", "Display what you are holding", + rpcDetailViews.add(addSwitchRow(layout, "Equipment Status", "Show your currently held items.", ConfigManager.getInstance().showHeldItemInRPC, (v, checked) -> { ConfigManager.getInstance().showHeldItemInRPC = checked; ConfigManager.save(); })); - rpcDetailViews.add(addSwitchRow(layout, "Show Health", "Display your current HP", + rpcDetailViews.add(addSwitchRow(layout, "Vitality Info", "Display your current health status.", ConfigManager.getInstance().showHealthInRPC, (v, checked) -> { ConfigManager.getInstance().showHealthInRPC = checked; ConfigManager.save(); diff --git a/src/main/java/de/winniepat/parrotmod/ui/GeneralTabFragment.java b/src/main/java/de/winniepat/parrotmod/ui/GeneralTabFragment.java index c21162a..d4bca3a 100644 --- a/src/main/java/de/winniepat/parrotmod/ui/GeneralTabFragment.java +++ b/src/main/java/de/winniepat/parrotmod/ui/GeneralTabFragment.java @@ -15,23 +15,27 @@ public class GeneralTabFragment extends BaseTabFragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, DataSet savedInstanceData) { LinearLayout layout = new LinearLayout(getContext()); layout.setOrientation(LinearLayout.VERTICAL); - layout.setPadding(dp(24), dp(8), dp(24), dp(24)); + layout.setPadding(dp(28), dp(24), dp(28), dp(24)); - addSectionHeader(layout, "Client Info"); - layout.addView(createSettingCard("Minecraft Version", Minecraft.getInstance().getLaunchedVersion())); + addTabHeader(layout, "Client Settings", "Configure your client-side experience and mod data."); - addSectionHeader(layout, "Config Management"); + addSectionHeader(layout, "Information"); + layout.addView(createSettingCard("Version", "Running on Minecraft " + Minecraft.getInstance().getLaunchedVersion())); - LinearLayout reloadCard = createSettingCard("Reload Config", "Reset all settings to saved values"); + addSectionHeader(layout, "Data Management"); + + LinearLayout reloadCard = createSettingCard("Reload configuration", "Discard unsaved changes and reload from disk."); Button reloadBtn = new Button(getContext()); reloadBtn.setText("Reload"); + reloadBtn.setPadding(dp(16), 0, dp(16), 0); reloadBtn.setOnClickListener(v -> ConfigManager.load()); reloadCard.addView(reloadBtn); layout.addView(reloadCard); - LinearLayout saveCard = createSettingCard("Save Config", "Persist current settings to disk"); + LinearLayout saveCard = createSettingCard("Commit changes", "Save all current settings to the configuration file."); Button saveBtn = new Button(getContext()); saveBtn.setText("Save"); + saveBtn.setPadding(dp(16), 0, dp(16), 0); saveBtn.setOnClickListener(v -> ConfigManager.save()); saveCard.addView(saveBtn); layout.addView(saveCard); diff --git a/src/main/java/de/winniepat/parrotmod/ui/InfoTabFragment.java b/src/main/java/de/winniepat/parrotmod/ui/InfoTabFragment.java index 1120f8a..31e987f 100644 --- a/src/main/java/de/winniepat/parrotmod/ui/InfoTabFragment.java +++ b/src/main/java/de/winniepat/parrotmod/ui/InfoTabFragment.java @@ -18,28 +18,30 @@ public class InfoTabFragment extends BaseTabFragment { LinearLayout layout = new LinearLayout(getContext()); layout.setOrientation(LinearLayout.VERTICAL); - layout.setPadding(dp(24), dp(8), dp(24), dp(24)); + layout.setPadding(dp(28), dp(24), dp(28), dp(24)); scrollView.addView(layout); - addSectionHeader(layout, "Mod Versions"); + addTabHeader(layout, "System Overview", "Detailed information about your environment and mod versions."); + + addSectionHeader(layout, "Software Manifest"); String parrotVersion = FabricLoader.getInstance().getModContainer("parrotmod").orElseThrow().getMetadata().getVersion().getFriendlyString(); - layout.addView(createSettingCard("Parrotmod", parrotVersion)); + layout.addView(createSettingCard("ParrotMod", "Stable Build v" + parrotVersion)); String mcVersion = FabricLoader.getInstance().getModContainer("minecraft").orElseThrow().getMetadata().getVersion().getFriendlyString(); - layout.addView(createSettingCard("Minecraft", Minecraft.getInstance().getLaunchedVersion() + " (" + mcVersion + ")")); + layout.addView(createSettingCard("Minecraft Engine", Minecraft.getInstance().getLaunchedVersion() + " (" + mcVersion + ")")); String loaderVersion = FabricLoader.getInstance().getModContainer("fabricloader").orElseThrow().getMetadata().getVersion().getFriendlyString(); - layout.addView(createSettingCard("Fabric Loader", loaderVersion)); + layout.addView(createSettingCard("Fabric Loader", "Build " + loaderVersion)); - addSectionHeader(layout, "System Info"); - layout.addView(createSettingCard("Java", System.getProperty("java.version") + " (" + System.getProperty("os.arch") + ")")); - layout.addView(createSettingCard("OS", System.getProperty("os.name") + " (" + System.getProperty("os.version") + ")")); + addSectionHeader(layout, "Runtime Environment"); + layout.addView(createSettingCard("Java Runtime", System.getProperty("java.version") + " [" + System.getProperty("os.arch") + "]")); + layout.addView(createSettingCard("Operating System", System.getProperty("os.name") + " [" + System.getProperty("os.version") + "]")); long maxMemory = Runtime.getRuntime().maxMemory(); long totalMemory = Runtime.getRuntime().totalMemory(); long freeMemory = Runtime.getRuntime().freeMemory(); long usedMemory = totalMemory - freeMemory; - layout.addView(createSettingCard("Memory Usage", String.format("%dMB / %dMB", usedMemory / 1024 / 1024, maxMemory / 1024 / 1024))); + layout.addView(createSettingCard("Memory Allocation", String.format("%d MiB / %d MiB in use", usedMemory / 1024 / 1024, maxMemory / 1024 / 1024))); return scrollView; } diff --git a/src/main/java/de/winniepat/parrotmod/ui/SettingsFragment.java b/src/main/java/de/winniepat/parrotmod/ui/SettingsFragment.java index c06f84b..5c796f5 100644 --- a/src/main/java/de/winniepat/parrotmod/ui/SettingsFragment.java +++ b/src/main/java/de/winniepat/parrotmod/ui/SettingsFragment.java @@ -12,18 +12,20 @@ import net.fabricmc.loader.api.FabricLoader; public class SettingsFragment extends Fragment { - private static final int COLOR_BACKGROUND = 0xFF0F0F13; - private static final int COLOR_SIDEBAR = 0xFF15151B; - private static final int COLOR_ACCENT = 0xFF00E5FF; - private static final int COLOR_TEXT_DIM = 0xFFAAAAAA; + private static final int COLOR_BACKGROUND = 0xFF18181F; + private static final int COLOR_SIDEBAR = 0xFF121217; + private static final int COLOR_ACCENT = 0xFF5CF392; + private static final int COLOR_TEXT_DIM = 0xFF9EA3AF; + private static final int COLOR_TAB_SELECTED = 0x125CF392; + private static final int COLOR_BORDER = 0x1AFFFFFF; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, DataSet savedInstanceState) { FrameLayout root = new FrameLayout(getContext()); - root.setLayoutParams(new FrameLayout.LayoutParams(dp(720), dp(480), Gravity.CENTER)); + root.setLayoutParams(new FrameLayout.LayoutParams(dp(760), dp(520), Gravity.CENTER)); View bg = new View(getContext()); - bg.setBackground(makeRoundedBg(COLOR_BACKGROUND, 16)); + bg.setBackground(makeBorderedBg(COLOR_BACKGROUND, COLOR_BORDER, 14, 1.2f)); root.addView(bg); LinearLayout layout = new LinearLayout(getContext()); @@ -31,26 +33,37 @@ public class SettingsFragment extends Fragment { root.addView(layout); FrameLayout sidebarContainer = new FrameLayout(getContext()); - var sidebarParams = new LinearLayout.LayoutParams(dp(170), ViewGroup.LayoutParams.MATCH_PARENT); + var sidebarParams = new LinearLayout.LayoutParams(dp(190), ViewGroup.LayoutParams.MATCH_PARENT); layout.addView(sidebarContainer, sidebarParams); View sidebarBg = new View(getContext()); - sidebarBg.setBackground(makeRoundedBg(COLOR_SIDEBAR, 16)); + sidebarBg.setBackground(makeRoundedBg(COLOR_SIDEBAR, 14)); sidebarContainer.addView(sidebarBg); LinearLayout sidebarContent = new LinearLayout(getContext()); sidebarContent.setOrientation(LinearLayout.VERTICAL); - sidebarContent.setPadding(0, dp(24), 0, dp(16)); + sidebarContent.setPadding(0, dp(28), 0, dp(16)); sidebarContainer.addView(sidebarContent, new FrameLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + View separator = new View(getContext()); + var sepParams = new LinearLayout.LayoutParams(dp(1), ViewGroup.LayoutParams.MATCH_PARENT); + separator.setOutlineAmbientShadowColor(COLOR_BORDER); + layout.addView(separator, sepParams); + + LinearLayout titleLayout = new LinearLayout(getContext()); + titleLayout.setOrientation(LinearLayout.VERTICAL); + titleLayout.setGravity(Gravity.CENTER); + titleLayout.setPadding(0, 0, 0, dp(32)); + TextView title = new TextView(getContext()); title.setText("PARROT"); title.setTextSize(22); title.setGravity(Gravity.CENTER); title.setTextColor(COLOR_ACCENT); - title.setPadding(dp(16), 0, dp(16), dp(32)); - sidebarContent.addView(title); + titleLayout.addView(title); + + sidebarContent.addView(titleLayout); FrameLayout tabsContainer = new FrameLayout(getContext()); sidebarContent.addView(tabsContainer, new LinearLayout.LayoutParams( @@ -58,8 +71,9 @@ public class SettingsFragment extends Fragment { LinearLayout tabsLayout = new LinearLayout(getContext()); tabsLayout.setOrientation(LinearLayout.VERTICAL); + tabsLayout.setPadding(dp(12), 0, dp(12), 0); tabsContainer.addView(tabsLayout, new FrameLayout.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.CENTER)); + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.TOP)); FrameLayout contentArea = new FrameLayout(getContext()); @@ -74,56 +88,72 @@ public class SettingsFragment extends Fragment { new DiscordTabFragment() }; - Button[] tabButtons = new Button[tabNames.length]; + View[] tabContainers = new View[tabNames.length]; + View[] indicators = new View[tabNames.length]; + TextView[] textViews = new TextView[tabNames.length]; + for (int i = 0; i < tabNames.length; i++) { final int index = i; - Button tab = new Button(getContext()); - tab.setText(tabNames[index]); - tab.setTextSize(14); - tab.setGravity(Gravity.START | Gravity.CENTER_VERTICAL); - tab.setPadding(dp(32), 0, dp(16), 0); - tab.setBackground(null); - tab.setTextColor(COLOR_TEXT_DIM); + + FrameLayout tabContainer = new FrameLayout(getContext()); + + View indicator = new View(getContext()); + indicator.setBackground(makeRoundedBg(COLOR_ACCENT, 2)); + indicator.setVisibility(View.INVISIBLE); + var indParams = new FrameLayout.LayoutParams(dp(3), dp(18), Gravity.START | Gravity.CENTER_VERTICAL); + tabContainer.addView(indicator, indParams); - tab.setOnClickListener(v -> { + TextView tabText = new TextView(getContext()); + tabText.setText(tabNames[index]); + tabText.setTextSize(14); + tabText.setPadding(dp(24), 0, dp(16), 0); + tabText.setTextColor(COLOR_TEXT_DIM); + tabText.setGravity(Gravity.START | Gravity.CENTER_VERTICAL); + tabContainer.addView(tabText, new FrameLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, dp(40))); + + tabContainer.setOnClickListener(v -> { getChildFragmentManager().beginTransaction() .setReorderingAllowed(true) .replace(contentArea.getId(), tabFragments[index]) .commit(); - for (int j = 0; j < tabButtons.length; j++) { + for (int j = 0; j < tabNames.length; j++) { boolean selected = (j == index); - tabButtons[j].setTextColor(selected ? 0xFFFFFFFF : COLOR_TEXT_DIM); - tabButtons[j].setBackground(selected ? makeRoundedBg(0x12FFFFFF, 8) : null); + textViews[j].setTextColor(selected ? 0xFFFFFFFF : COLOR_TEXT_DIM); + tabContainers[j].setBackground(selected ? makeRoundedBg(COLOR_TAB_SELECTED, 8) : null); + indicators[j].setVisibility(selected ? View.VISIBLE : View.INVISIBLE); } - }); - var tabParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, dp(44)); - tabParams.bottomMargin = dp(4); - tabsLayout.addView(tab, tabParams); - tabButtons[index] = tab; + var tabParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, dp(40)); + tabParams.bottomMargin = dp(6); + tabsLayout.addView(tabContainer, tabParams); + + tabContainers[index] = tabContainer; + indicators[index] = indicator; + textViews[index] = tabText; } TextView footer = new TextView(getContext()); String version = FabricLoader.getInstance().getModContainer("parrotmod") .map(m -> m.getMetadata().getVersion().getFriendlyString()).orElse("?.?.?"); - footer.setText("ParrotMod v" + version); - footer.setTextSize(11); - footer.setTextColor(0x44FFFFFF); + footer.setText("v" + version); + footer.setTextSize(10); + footer.setTextColor(0x33FFFFFF); footer.setGravity(Gravity.CENTER); footer.setPadding(dp(16), dp(12), dp(16), dp(12)); sidebarContent.addView(footer); root.setAlpha(0); - root.setScaleX(0.96f); - root.setScaleY(0.96f); - ObjectAnimator.ofFloat(root, View.ALPHA, 0, 1).setDuration(450).start(); - ObjectAnimator.ofFloat(root, View.SCALE_X, 0.96f, 1).setDuration(450).start(); - ObjectAnimator.ofFloat(root, View.SCALE_Y, 0.96f, 1).setDuration(450).start(); + root.setScaleX(0.98f); + root.setScaleY(0.98f); + ObjectAnimator.ofFloat(root, View.ALPHA, 0, 1).setDuration(350).start(); + ObjectAnimator.ofFloat(root, View.SCALE_X, 0.98f, 1).setDuration(350).start(); + ObjectAnimator.ofFloat(root, View.SCALE_Y, 0.98f, 1).setDuration(350).start(); root.post(() -> { - tabButtons[0].callOnClick(); + tabContainers[0].callOnClick(); }); return root; @@ -139,4 +169,12 @@ public class SettingsFragment extends Fragment { d.setColor(color); return d; } + + private ShapeDrawable makeBorderedBg(int color, int strokeColor, float radius, float strokeWidth) { + ShapeDrawable d = new ShapeDrawable(); + d.setCornerRadius(dp(radius)); + d.setColor(color); + d.setStroke(dp(strokeWidth), strokeColor); + return d; + } } \ No newline at end of file