package com.spotifymc.config; import com.spotifymc.auth.SpotifyAuthManager; import com.spotifymc.playback.SpotifyPlaybackManager; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.widget.ButtonWidget; import net.minecraft.client.gui.widget.SliderWidget; import net.minecraft.client.gui.widget.TextFieldWidget; import net.minecraft.text.Text; /** * Clean in-game configuration screen for managing Spotify authentication and HUD options. */ public class SpotifyConfigScreen extends Screen { private final Screen parent; private final SpotifyConfig config; private final SpotifyAuthManager authManager; private final SpotifyPlaybackManager playbackManager; private TextFieldWidget clientIdField; private ButtonWidget connectButton; public SpotifyConfigScreen(Screen parent, SpotifyConfig config, SpotifyAuthManager authManager, SpotifyPlaybackManager playbackManager) { super(Text.translatable("spotifymc.config.title")); this.parent = parent; this.config = config; this.authManager = authManager; this.playbackManager = playbackManager; } @Override protected void init() { int centerX = this.width / 2; int startY = 36; int colWidth = 150; int rowHeight = 24; // 1. Client ID input this.clientIdField = new TextFieldWidget(this.textRenderer, centerX - 150, startY + 14, 300, 20, Text.translatable("spotifymc.config.client_id")); this.clientIdField.setMaxLength(64); this.clientIdField.setText(config.getClientId()); this.clientIdField.setChangedListener(text -> { config.setClientId(text); config.save(); }); this.addDrawableChild(this.clientIdField); // 2. Auth Action Button (Connect / Disconnect) int authBtnY = startY + 40; this.connectButton = ButtonWidget.builder( Text.literal(authManager.isAuthenticated() ? "Disconnect" : "Connect Spotify"), btn -> { if (authManager.isAuthenticated()) { authManager.logout(); updateAuthButton(); } else { config.setClientId(clientIdField.getText()); config.save(); btn.active = false; btn.setMessage(Text.literal("Opening browser...")); authManager.startPkceLoginFlow().whenComplete((res, err) -> { if (this.client != null) { this.client.execute(this::updateAuthButton); } }); } } ).dimensions(centerX - 100, authBtnY, 200, 20).build(); this.addDrawableChild(this.connectButton); // 3. Left Column: Toggles int optionsY = authBtnY + 38; // HUD Enabled toggle this.addDrawableChild(ButtonWidget.builder( getHudEnabledText(), btn -> { config.setHudEnabled(!config.isHudEnabled()); config.save(); btn.setMessage(getHudEnabledText()); } ).dimensions(centerX - colWidth - 5, optionsY, colWidth, 20).build()); // Show Album Art toggle this.addDrawableChild(ButtonWidget.builder( getAlbumArtText(), btn -> { config.setShowAlbumArt(!config.isShowAlbumArt()); config.save(); btn.setMessage(getAlbumArtText()); } ).dimensions(centerX + 5, optionsY, colWidth, 20).build()); // Auto Hide toggle this.addDrawableChild(ButtonWidget.builder( getAutoHideText(), btn -> { config.setAutoHideWhenInactive(!config.isAutoHideWhenInactive()); config.save(); btn.setMessage(getAutoHideText()); } ).dimensions(centerX - colWidth - 5, optionsY + rowHeight, colWidth, 20).build()); // Anchor Cycle button this.addDrawableChild(ButtonWidget.builder( getAnchorText(), btn -> { SpotifyConfig.Anchor[] anchors = SpotifyConfig.Anchor.values(); int nextIdx = (config.getAnchor().ordinal() + 1) % anchors.length; config.setAnchor(anchors[nextIdx]); config.save(); btn.setMessage(getAnchorText()); } ).dimensions(centerX + 5, optionsY + rowHeight, colWidth, 20).build()); // 4. Sliders (Scale, Opacity, Polling Rate) int slidersY = optionsY + (rowHeight * 2); // Scale Slider (0.5x to 2.0x) double initialScaleProgress = (config.getHudScale() - 0.5f) / 1.5f; this.addDrawableChild(new SliderWidget(centerX - colWidth - 5, slidersY, colWidth, 20, getScaleText(), initialScaleProgress) { @Override protected void updateMessage() { this.setMessage(getScaleText()); } @Override protected void applyValue() { float val = 0.5f + (float) this.value * 1.5f; config.setHudScale(Math.round(val * 10.0f) / 10.0f); config.save(); } }); // Opacity Slider (20% to 100%) double initialOpacityProgress = (config.getHudOpacity() - 0.2f) / 0.8f; this.addDrawableChild(new SliderWidget(centerX + 5, slidersY, colWidth, 20, getOpacityText(), initialOpacityProgress) { @Override protected void updateMessage() { this.setMessage(getOpacityText()); } @Override protected void applyValue() { float val = 0.2f + (float) this.value * 0.8f; config.setHudOpacity(Math.round(val * 100.0f) / 100.0f); config.save(); } }); // Polling Rate Slider (1s to 10s) double initialPollProgress = (config.getPollingIntervalSec() - 1.0) / 9.0; this.addDrawableChild(new SliderWidget(centerX - 100, slidersY + rowHeight, 200, 20, getPollRateText(), initialPollProgress) { @Override protected void updateMessage() { this.setMessage(getPollRateText()); } @Override protected void applyValue() { int sec = 1 + (int) Math.round(this.value * 9.0); config.setPollingIntervalSec(sec); config.save(); } }); // Done button this.addDrawableChild(ButtonWidget.builder( Text.translatable("spotifymc.config.done"), btn -> this.close() ).dimensions(centerX - 100, this.height - 28, 200, 20).build()); updateAuthButton(); } private void updateAuthButton() { if (connectButton == null) return; connectButton.active = true; if (authManager.isAuthenticated()) { connectButton.setMessage(Text.translatable("spotifymc.config.btn_disconnect")); } else if (authManager.isAuthenticating()) { connectButton.setMessage(Text.translatable("spotifymc.config.auth_status.waiting")); connectButton.active = false; } else { connectButton.setMessage(Text.translatable("spotifymc.config.btn_connect")); } } private Text getHudEnabledText() { return Text.literal("HUD Overlay: " + (config.isHudEnabled() ? "§aON" : "§cOFF")); } private Text getAlbumArtText() { return Text.literal("Album Art: " + (config.isShowAlbumArt() ? "§aON" : "§cOFF")); } private Text getAutoHideText() { return Text.literal("Auto-Hide Paused: " + (config.isAutoHideWhenInactive() ? "§aON" : "§cOFF")); } private Text getAnchorText() { return Text.literal("Anchor: §e" + config.getAnchor().name()); } private Text getScaleText() { return Text.literal(String.format("HUD Scale: %.1fx", config.getHudScale())); } private Text getOpacityText() { return Text.literal(String.format("Opacity: %d%%", Math.round(config.getHudOpacity() * 100.0f))); } private Text getPollRateText() { return Text.literal("Update Interval: " + config.getPollingIntervalSec() + "s"); } @Override public void render(DrawContext context, int mouseX, int mouseY, float delta) { super.render(context, mouseX, mouseY, delta); int centerX = this.width / 2; // Title context.drawCenteredTextWithShadow(this.textRenderer, this.title, centerX, 12, 0xFFFFFF); // Client ID label & hint context.drawTextWithShadow(this.textRenderer, "Spotify Developer Client ID:", centerX - 150, 36, 0xAAAAAA); // Status badge String statusText; int statusColor; if (authManager.isAuthenticated()) { statusText = "● Connected"; statusColor = 0x1DB954; } else if (authManager.isAuthenticating()) { statusText = "○ Waiting for authorization..."; statusColor = 0xFFD700; } else { statusText = "○ Not Connected"; statusColor = 0xFF5555; } context.drawCenteredTextWithShadow(this.textRenderer, statusText, centerX, 66, statusColor); } @Override public void close() { config.save(); if (this.client != null) { this.client.setScreen(this.parent); } } }