package com.pokemongo; import javax.swing.*; import javax.swing.KeyStroke; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.WindowEvent; import java.io.*; import java.util.Properties; /** * Jednoduchá GUI aplikace pro Pokémon GO automatizaci * S kartami pro jednotlivé automatizace */ public class PokemonGoGUI extends JFrame { private JButton stopButton; private JTextArea logArea; private JLabel statusLabel; private volatile boolean isRunning = false; private volatile boolean shouldStop = false; private PokemonGoAutomation automation; private Thread automationThread; private int totalTransferredCount = 0; // Celkový počet transfernutých pokémonů private volatile boolean autoClickRunning = false; private GlobalHotkey globalHotkey; private static final String CONFIG_FILE = "pgo-automat-settings.properties"; private static final String VERSION = "1.0.3"; private Properties settings; private JComboBox countComboBox; private JSpinner delaySpinner; private static final Font TITLE_FONT = new Font("Segoe UI", Font.BOLD, 18); private static final Font HEADER_FONT = new Font("Segoe UI", Font.BOLD, 12); private static final Font BODY_FONT = new Font("Segoe UI", Font.PLAIN, 11); private static final Font SMALL_FONT = new Font("Segoe UI", Font.PLAIN, 10); private static final Color PANEL_BACKGROUND = new Color(248, 248, 252); private static final Color CARD_BACKGROUND = Color.WHITE; private static final Color CARD_BORDER_COLOR = new Color(210, 210, 210); private static final Color PRIMARY_GREEN = new Color(76, 175, 80); private static final Color PRIMARY_RED = new Color(244, 67, 54); private static final Color ACCENT_BLUE = new Color(33, 150, 243); private static final Color LOG_BORDER_COLOR = new Color(200, 200, 200); private static final Color STATUS_DEFAULT = new Color(33, 150, 243); private static final int CARD_MAX_WIDTH = 760; public PokemonGoGUI() { setTitle("Pokémon GO Automatizace v" + VERSION); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // Načtení uložených nastavení loadSettings(); // Obnovení velikosti a pozice okna int width = Integer.parseInt(settings.getProperty("window.width", "900")); int height = Integer.parseInt(settings.getProperty("window.height", "680")); int x = Integer.parseInt(settings.getProperty("window.x", "-1")); int y = Integer.parseInt(settings.getProperty("window.y", "-1")); setSize(width, height); if (x >= 0 && y >= 0) { setLocation(x, y); } else { setLocationRelativeTo(null); } setResizable(true); setBackground(PANEL_BACKGROUND); // Uložení nastavení při zavření okna addWindowListener(new java.awt.event.WindowAdapter() { @Override public void windowClosing(WindowEvent e) { saveSettings(); } }); // Hlavní panel JPanel mainPanel = new JPanel(new BorderLayout(10, 10)); mainPanel.setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15)); mainPanel.setBackground(PANEL_BACKGROUND); // Horní panel se stavem JLabel stateLabel = new JLabel("Stav:"); stateLabel.setFont(HEADER_FONT); stateLabel.setForeground(new Color(70, 70, 70)); statusLabel = new JLabel("Připraven k spuštění"); statusLabel.setFont(BODY_FONT); statusLabel.setForeground(STATUS_DEFAULT); JLabel versionLabel = new JLabel("verze " + VERSION); versionLabel.setFont(SMALL_FONT); versionLabel.setForeground(new Color(120, 120, 120)); stopButton = new JButton("⏹ ZASTAVIT (CTRL+ALT+X)"); stopButton.setPreferredSize(new Dimension(150, 30)); styleButton(stopButton, PRIMARY_RED, Color.WHITE, SMALL_FONT); stopButton.setEnabled(false); stopButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { stopAutomation(); } }); JPanel stopPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); stopPanel.setOpaque(false); stopPanel.add(stopButton); JLabel titleLabel = new JLabel("Pokémon GO Automatizace"); titleLabel.setFont(TITLE_FONT); titleLabel.setForeground(new Color(30, 30, 30)); JPanel titleRow = new JPanel(new BorderLayout()); titleRow.setBackground(PANEL_BACKGROUND); titleRow.add(titleLabel, BorderLayout.WEST); titleRow.add(stopPanel, BorderLayout.EAST); JPanel statusRow = new JPanel(new FlowLayout(FlowLayout.LEFT, 8, 0)); statusRow.setBackground(PANEL_BACKGROUND); statusRow.add(stateLabel); statusRow.add(statusLabel); statusRow.add(versionLabel); JPanel headerPanel = new JPanel(); headerPanel.setLayout(new BoxLayout(headerPanel, BoxLayout.Y_AXIS)); headerPanel.setBackground(PANEL_BACKGROUND); headerPanel.add(titleRow); headerPanel.add(Box.createVerticalStrut(6)); headerPanel.add(statusRow); // Panel s kartami automatizací JPanel cardsContainer = new JPanel(new GridBagLayout()); cardsContainer.setBackground(PANEL_BACKGROUND); cardsContainer.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8)); GridBagConstraints gbc = new GridBagConstraints(); gbc.gridx = 0; gbc.gridy = 0; gbc.fill = GridBagConstraints.HORIZONTAL; gbc.weightx = 1.0; gbc.anchor = GridBagConstraints.NORTH; gbc.insets = new Insets(0, 0, 12, 0); // Karta 1: Transfer automatizace JPanel transferCard = createAutomationCard( "🔄 TRANSFER AUTOMATIZACE", "Hledá Pokémony, označí je a stiskne Transfer", null ); // Najít START tlačítko - je v EAST pozici BorderLayoutu JButton startBtnTransfer = findStartButton(transferCard); if (startBtnTransfer != null) { startBtnTransfer.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { startTransferAutomation(transferCard); } }); } gbc.gridy = 0; cardsContainer.add(transferCard, gbc); gbc.gridy++; gbc.insets = new Insets(0, 0, 12, 0); // Karta 2: Autoklik JPanel autoClickCard = createAutomationCard( "🖱️ AUTOKLIK", "Automaticky klikuje na zadanou pozici", null ); // Najít START tlačítko JButton startBtnAutoClick = findStartButton(autoClickCard); if (startBtnAutoClick != null) { startBtnAutoClick.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { startAutoClick(autoClickCard); } }); } gbc.gridy++; gbc.insets = new Insets(0, 0, 0, 0); cardsContainer.add(autoClickCard, gbc); gbc.gridy++; gbc.weighty = 1.0; JPanel spacer = new JPanel(); spacer.setOpaque(false); cardsContainer.add(spacer, gbc); JPanel automationPanel = new JPanel(new BorderLayout()); automationPanel.setBackground(PANEL_BACKGROUND); automationPanel.add(cardsContainer, BorderLayout.NORTH); JScrollPane automationScrollPane = new JScrollPane(automationPanel); automationScrollPane.setBorder(null); automationScrollPane.setBackground(PANEL_BACKGROUND); automationScrollPane.getViewport().setBackground(PANEL_BACKGROUND); // Log area logArea = new JTextArea(); logArea.setEditable(false); logArea.setFont(new Font("Consolas", Font.PLAIN, 11)); logArea.setBackground(new Color(248, 248, 248)); logArea.setForeground(new Color(45, 45, 45)); logArea.setLineWrap(true); logArea.setWrapStyleWord(true); logArea.setMargin(new Insets(5, 5, 5, 5)); JScrollPane logScrollPane = new JScrollPane(logArea); logScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); logScrollPane.setBorder(BorderFactory.createTitledBorder( BorderFactory.createLineBorder(LOG_BORDER_COLOR), "Log", 0, 0, HEADER_FONT, new Color(85, 85, 85) )); logScrollPane.getViewport().setBackground(new Color(247, 247, 247)); JButton clearLogButton = new JButton("🗑 Vyčistit log"); clearLogButton.setPreferredSize(new Dimension(140, 28)); styleButton(clearLogButton, ACCENT_BLUE, Color.WHITE, SMALL_FONT); clearLogButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { logArea.setText(""); } }); JPanel logButtonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 5, 5)); logButtonPanel.setBackground(PANEL_BACKGROUND); logButtonPanel.add(clearLogButton); JPanel logPanel = new JPanel(new BorderLayout(5, 5)); logPanel.setBackground(new Color(247, 247, 247)); logPanel.add(logScrollPane, BorderLayout.CENTER); logPanel.add(logButtonPanel, BorderLayout.SOUTH); // Splitter mezi kartami a logem JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, automationScrollPane, logPanel); splitPane.setDividerSize(6); splitPane.setResizeWeight(0.6); splitPane.setContinuousLayout(true); splitPane.setBorder(null); splitPane.setBackground(PANEL_BACKGROUND); // Přidání do hlavního panelu mainPanel.add(headerPanel, BorderLayout.NORTH); mainPanel.add(splitPane, BorderLayout.CENTER); add(mainPanel); // Klávesová zkratka: Ctrl+Alt+Z pro zastavení KeyStroke hotkey = KeyStroke.getKeyStroke(KeyEvent.VK_X, KeyEvent.CTRL_DOWN_MASK | KeyEvent.ALT_DOWN_MASK); getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(hotkey, "stopAutomationAction"); getRootPane().getActionMap().put("stopAutomationAction", new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { if (isRunning) { stopAutomation(); } } }); // Globální hotkey pro ESC (bonus, když okno není fokusované) globalHotkey = new GlobalHotkey(new Runnable() { @Override public void run() { if (isRunning) { stopAutomation(); } } }); mainPanel.add(globalHotkey, BorderLayout.SOUTH); // Přesměrování System.out a System.err do GUI redirectSystemStreams(); logArea.append("=== Pokémon GO Automatizace ===\n\n"); logArea.append("Vyberte jednu z automatizací a klikněte na tlačítko START.\n"); logArea.append("Ujistěte se, že je aplikace Pokémon GO spuštěná.\n"); logArea.append("Pro zastavení stiskněte Ctrl+Alt+X nebo klikněte ZASTAVIT.\n\n"); } /** * Vytvoří kartu automatizace s nastavením */ private JPanel createAutomationCard(String title, String description, ActionListener startAction) { JPanel card = new JPanel(new BorderLayout(12, 12)); card.setBackground(CARD_BACKGROUND); card.setBorder(BorderFactory.createCompoundBorder( BorderFactory.createLineBorder(CARD_BORDER_COLOR, 1), BorderFactory.createEmptyBorder(8, 8, 8, 8) )); card.setMaximumSize(new Dimension(CARD_MAX_WIDTH, 160)); card.setPreferredSize(new Dimension(CARD_MAX_WIDTH, 160)); card.setAlignmentX(Component.CENTER_ALIGNMENT); JPanel infoPanel = new JPanel(); infoPanel.setLayout(new BoxLayout(infoPanel, BoxLayout.Y_AXIS)); infoPanel.setBackground(CARD_BACKGROUND); infoPanel.setOpaque(true); infoPanel.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4)); JLabel titleLabel = new JLabel(title); titleLabel.setFont(HEADER_FONT); titleLabel.setForeground(new Color(28, 28, 28)); JLabel descLabel = new JLabel("" + description + ""); descLabel.setFont(SMALL_FONT); descLabel.setForeground(new Color(115, 115, 115)); infoPanel.add(titleLabel); infoPanel.add(Box.createVerticalStrut(3)); infoPanel.add(descLabel); infoPanel.add(Box.createVerticalGlue()); JPanel centerPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 12, 6)); centerPanel.setBackground(CARD_BACKGROUND); centerPanel.setOpaque(true); if (title.contains("TRANSFER")) { // Načíst hodnotu a zajistit, že je v platném rozsahu nebo v seznamu povolených hodnot int savedCount = Integer.parseInt(settings.getProperty("transfer.count", "12")); // Povolené hodnoty: 1, 3, 6, 12, 24, 36, 48, 60, 72, 84, 96 int[] validCounts = {1, 3, 6, 12, 24, 36, 48, 60, 72, 84, 96}; boolean isValid = false; for (int count : validCounts) { if (savedCount == count) { isValid = true; break; } } if (!isValid) { savedCount = 12; // Nastavit na výchozí, pokud není v seznamu povolených } // Vytvořit dropdown s hodnotami 1, 3, 6, 12, 24, 36, ..., 96 Integer[] counts = {1, 3, 6, 12, 24, 36, 48, 60, 72, 84, 96}; countComboBox = new JComboBox<>(counts); countComboBox.setSelectedItem(savedCount); countComboBox.setPreferredSize(new Dimension(70, 26)); delaySpinner = new JSpinner(new SpinnerNumberModel( Integer.parseInt(settings.getProperty("transfer.delay", "2")), 0, 60, 1 )); delaySpinner.setPreferredSize(new Dimension(64, 26)); card.putClientProperty("countComboBox", countComboBox); card.putClientProperty("delaySpinner", delaySpinner); centerPanel.add(createFieldPanel("Počet:", countComboBox)); centerPanel.add(createFieldPanel("Čekání (s):", delaySpinner)); } else if (title.contains("AUTOKLIK")) { JSpinner intervalSpinner = new JSpinner(new SpinnerNumberModel( Integer.parseInt(settings.getProperty("autoklik.interval", "100")), 10, 10000, 10 )); intervalSpinner.setPreferredSize(new Dimension(80, 26)); card.putClientProperty("intervalSpinner", intervalSpinner); centerPanel.add(createFieldPanel("Interval (ms):", intervalSpinner)); } // Pravý panel - START tlačítko (a u Autokliku i STOP v rámci tlačítka) JPanel rightPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 6, 0)); rightPanel.setBackground(CARD_BACKGROUND); rightPanel.setBorder(BorderFactory.createEmptyBorder(4, 0, 0, 0)); // Tlačítko START / VYPNOUT JButton startBtn = new JButton("▶ START"); startBtn.setPreferredSize(new Dimension(100, 32)); styleButton(startBtn, PRIMARY_GREEN, Color.WHITE, SMALL_FONT); startBtn.addActionListener(startAction); // Uložit tlačítko do card pro změnu barvy během běhu card.putClientProperty("startButton", startBtn); rightPanel.add(startBtn); // Komponování karty: info nahoře, nastavení uprostřed, tlačítko dole card.add(infoPanel, BorderLayout.NORTH); card.add(centerPanel, BorderLayout.CENTER); card.add(rightPanel, BorderLayout.SOUTH); return card; } private JPanel createFieldPanel(String labelText, JComponent field) { JLabel label = new JLabel(labelText); label.setFont(BODY_FONT); label.setForeground(new Color(96, 96, 96)); field.setFont(BODY_FONT); if (field instanceof JSpinner) { ((JSpinner) field).setBorder(BorderFactory.createLineBorder(CARD_BORDER_COLOR)); field.setBackground(new Color(252, 252, 252)); } JPanel wrapper = new JPanel(new FlowLayout(FlowLayout.LEFT, 4, 2)); wrapper.setBackground(CARD_BACKGROUND); wrapper.add(label); wrapper.add(field); return wrapper; } private void styleButton(JButton button, Color background, Color foreground, Font font) { button.setFont(font); button.setBackground(background); button.setForeground(foreground); button.setFocusPainted(false); button.setBorder(BorderFactory.createEmptyBorder(4, 10, 4, 10)); } private JButton findStartButton(Container container) { for (Component comp : container.getComponents()) { if (comp instanceof JButton) { JButton button = (JButton) comp; if ("▶ START".equals(button.getText())) { return button; } } if (comp instanceof Container) { JButton nested = findStartButton((Container) comp); if (nested != null) { return nested; } } } return null; } /** * Přesměruje System.out a System.err do log area */ private void redirectSystemStreams() { System.setOut(new java.io.PrintStream(System.out) { @Override public void println(String x) { super.println(x); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { logArea.append(x + "\n"); logArea.setCaretPosition(logArea.getDocument().getLength()); } }); } }); System.setErr(new java.io.PrintStream(System.err) { @Override public void println(String x) { super.println(x); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { logArea.append("[CHYBA] " + x + "\n"); logArea.setCaretPosition(logArea.getDocument().getLength()); } }); } }); } /** * Spustí Transfer automatizaci */ private void startTransferAutomation(JPanel transferCard) { if (isRunning) { JOptionPane.showMessageDialog(this, "Automatizace již běží!", "Upozornění", JOptionPane.WARNING_MESSAGE); return; } // Získat počet pokémonů a čekání z GUI JComboBox countComboBox = (JComboBox) transferCard.getClientProperty("countComboBox"); JSpinner delaySpinner = (JSpinner) transferCard.getClientProperty("delaySpinner"); int pokemonCount = (Integer) countComboBox.getSelectedItem(); int delaySeconds = (Integer) delaySpinner.getValue(); stopButton.setEnabled(true); statusLabel.setText("Transfer automatizace běží..."); statusLabel.setForeground(new Color(255, 152, 0)); isRunning = true; // Změnit barvu START tlačítka na červenou JButton startBtn = (JButton) transferCard.getClientProperty("startButton"); if (startBtn != null) { startBtn.setEnabled(false); styleButton(startBtn, PRIMARY_RED, Color.WHITE, SMALL_FONT); } logArea.append("\n========================================\n"); logArea.append("SPOUŠTĚNÍ TRANSFER AUTOMATIZACE\n"); logArea.append("Počet pokémonů: " + pokemonCount + ", Čekání: " + delaySeconds + "s\n"); logArea.append("========================================\n\n"); shouldStop = false; automationThread = new Thread(new Runnable() { @Override public void run() { try { automation = new PokemonGoAutomation(); automation.resetTransferredCount(); // Spustit vlákno pro aktualizaci statusu Thread statusUpdateThread = new Thread(new Runnable() { @Override public void run() { while (isRunning && !shouldStop && !Thread.currentThread().isInterrupted()) { try { Thread.sleep(500); // Aktualizovat každých 500ms final int transferred = automation.getTransferredCount(); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { if (isRunning) { statusLabel.setText("Transfer běží... Transferováno: " + transferred + "/" + pokemonCount); } } }); } catch (InterruptedException e) { break; } } } }); statusUpdateThread.setDaemon(true); statusUpdateThread.start(); if (!shouldStop) { automation.runWithCount(pokemonCount, delaySeconds); totalTransferredCount += automation.getTransferredCount(); } if (!shouldStop) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { statusLabel.setText("Automatizace dokončena! Celkem transferováno: " + totalTransferredCount); statusLabel.setForeground(new Color(76, 175, 80)); logArea.append("\n✅ Transfer automatizace úspěšně dokončena! Transferováno: " + automation.getTransferredCount() + " pokémonů\n"); } }); } } catch (Exception e) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { statusLabel.setText("Chyba!"); statusLabel.setForeground(new Color(244, 67, 54)); logArea.append("\n❌ Chyba: " + e.getMessage() + "\n"); e.printStackTrace(); } }); } finally { // Čistit prostředky po automatizaci try { if (automation != null) { automation.cleanup(); } // Také vyčistit WindowFinder resources WindowFinder.cleanup(); System.gc(); } catch (Exception cleanupEx) { System.err.println("Chyba při čištění: " + cleanupEx.getMessage()); } SwingUtilities.invokeLater(new Runnable() { @Override public void run() { isRunning = false; stopButton.setEnabled(false); // Vrátit barvu START tlačítka na zelenou JButton btn = (JButton) transferCard.getClientProperty("startButton"); if (btn != null) { btn.setEnabled(true); styleButton(btn, PRIMARY_GREEN, Color.WHITE, SMALL_FONT); } } }); } } }); automationThread.start(); } /** * Spustí autoklik */ private void startAutoClick(JPanel autoClickCard) { if (autoClickRunning) { stopAutomation(); return; } if (isRunning) { JOptionPane.showMessageDialog(this, "Jiná automatizace již běží!", "Upozornění", JOptionPane.WARNING_MESSAGE); return; } // Načtení nastavení JSpinner intervalSpinner = (JSpinner) autoClickCard.getClientProperty("intervalSpinner"); int interval = (Integer) intervalSpinner.getValue(); // Uložení nastavení settings.setProperty("autoklik.interval", String.valueOf(interval)); saveSettings(); stopButton.setEnabled(true); statusLabel.setText("Autokliker aktivní (Šipka dolů)..."); statusLabel.setForeground(new Color(255, 152, 0)); isRunning = true; autoClickRunning = true; shouldStop = false; // Změnit tlačítko na VYPNOUT JButton startBtn = (JButton) autoClickCard.getClientProperty("startButton"); if (startBtn != null) { startBtn.setText("⏹ VYPNOUT"); styleButton(startBtn, PRIMARY_RED, Color.WHITE, SMALL_FONT); } logArea.append("\n========================================\n"); logArea.append("AUTOKLIKER AKTIVNÍ\n"); logArea.append("Interval: " + interval + "ms\n"); logArea.append("Ovládání: Stiskněte ŠIPKU NAHORU nebo DOLŮ pro zapnutí/vypnutí\n"); logArea.append("========================================\n\n"); automationThread = new Thread(new Runnable() { @Override public void run() { try { java.awt.Robot robot = new java.awt.Robot(); int clicksDone = 0; boolean isClickingActive = false; boolean wasKeyPressed = false; long lastClickTime = 0; long lastToggleTime = 0; while (autoClickRunning && !shouldStop) { // Kontrola obou šipek boolean isKeyPressed = globalHotkey.isKeyPressed(KeyEvent.VK_DOWN) || globalHotkey.isKeyPressed(KeyEvent.VK_UP); long currentTime = System.currentTimeMillis(); // Detekce stisku (náběžná hrana) pro přepnutí stavu if (isKeyPressed && !wasKeyPressed && (currentTime - lastToggleTime > 200)) { isClickingActive = !isClickingActive; lastToggleTime = currentTime; final boolean active = isClickingActive; SwingUtilities.invokeLater(() -> { logArea.append(active ? "▶ Klikání AKTIVOVÁNO šipkou\n" : "⏸ Klikání POZASTAVENO šipkou\n"); statusLabel.setText(active ? "Autokliker: KLIKÁM..." : "Autokliker: POZASTAVENO"); }); if (isClickingActive) { lastClickTime = 0; // Spustit klikání hned } } wasKeyPressed = isKeyPressed; if (isClickingActive) { if (currentTime - lastClickTime >= interval) { // Klik na aktuální pozici robot.mousePress(java.awt.event.InputEvent.BUTTON1_DOWN_MASK); robot.mouseRelease(java.awt.event.InputEvent.BUTTON1_DOWN_MASK); clicksDone++; if (clicksDone % 20 == 0) { final int count = clicksDone; SwingUtilities.invokeLater(() -> logArea.append(" Kliknutí: " + count + "\n")); } lastClickTime = currentTime; } } // Rychlá smyčka pro detekci kláves (10ms) Thread.sleep(10); } if (!shouldStop) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { statusLabel.setText("Autokliker zastaven."); statusLabel.setForeground(new Color(76, 175, 80)); logArea.append("\n✅ Autokliker byl vypnut.\n"); } }); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } catch (Exception e) { if (!shouldStop) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { statusLabel.setText("Chyba autoklikeru!"); statusLabel.setForeground(new Color(244, 67, 54)); logArea.append("\n❌ Chyba: " + e.getMessage() + "\n"); } }); } } finally { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { isRunning = false; autoClickRunning = false; stopButton.setEnabled(false); // Vrátit tlačítko na START JButton btn = (JButton) autoClickCard.getClientProperty("startButton"); if (btn != null) { btn.setText("▶ START"); styleButton(btn, PRIMARY_GREEN, Color.WHITE, SMALL_FONT); } } }); } } }); automationThread.start(); } /** * Zastaví automatizaci */ private void stopAutomation() { shouldStop = true; autoClickRunning = false; isRunning = false; stopButton.setEnabled(false); if (automationThread != null && automationThread.isAlive()) { automationThread.interrupt(); // Čekej max 2 sekundy na ukončení try { automationThread.join(2000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } SwingUtilities.invokeLater(new Runnable() { @Override public void run() { logArea.append("\n⚠️ Automatizace byla přerušena uživatelem\n"); statusLabel.setText("Přerušeno"); statusLabel.setForeground(new Color(244, 67, 54)); } }); } /** * Načte uložená nastavení ze souboru */ private void loadSettings() { settings = new Properties(); File configFile = new File(CONFIG_FILE); if (configFile.exists()) { try (java.io.FileInputStream fis = new java.io.FileInputStream(configFile)) { settings.load(fis); } catch (IOException e) { System.err.println("Chyba při načítání nastavení: " + e.getMessage()); } } // Výchozí hodnoty, pokud nastavení neexistují if (!settings.containsKey("transfer.count")) { settings.setProperty("transfer.count", "12"); } if (!settings.containsKey("transfer.delay")) { settings.setProperty("transfer.delay", "2"); } if (!settings.containsKey("window.width")) { settings.setProperty("window.width", "700"); } if (!settings.containsKey("window.height")) { settings.setProperty("window.height", "600"); } if (!settings.containsKey("window.x")) { settings.setProperty("window.x", "-1"); } if (!settings.containsKey("window.y")) { settings.setProperty("window.y", "-1"); } } /** * Uloží aktuální nastavení do souboru */ private void saveSettings() { // Uložení hodnot z combo boxu a spinneru if (countComboBox != null) { settings.setProperty("transfer.count", countComboBox.getSelectedItem().toString()); } if (delaySpinner != null) { settings.setProperty("transfer.delay", delaySpinner.getValue().toString()); } // Uložení velikosti a pozice okna settings.setProperty("window.width", String.valueOf(getWidth())); settings.setProperty("window.height", String.valueOf(getHeight())); settings.setProperty("window.x", String.valueOf(getX())); settings.setProperty("window.y", String.valueOf(getY())); try (java.io.FileOutputStream fos = new java.io.FileOutputStream(CONFIG_FILE)) { settings.store(fos, "Pokémon GO Automatizace - Nastavení"); } catch (IOException e) { System.err.println("Chyba při ukládání nastavení: " + e.getMessage()); } } public static void main(String[] args) { // Nastavit shutdown hook pro bezpečné ukončení Runtime.getRuntime().addShutdownHook(new Thread(() -> { System.out.println("Aplikace se vypíná..."); // Vyčistit X11 resources try { WindowFinder.cleanup(); } catch (Exception e) { System.err.println("Chyba při čištění WindowFinder: " + e.getMessage()); } })); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { PokemonGoGUI frame = new PokemonGoGUI(); frame.setVisible(true); // Nastavit window listener pro čisté ukončení frame.addWindowListener(new java.awt.event.WindowAdapter() { @Override public void windowClosing(WindowEvent e) { System.out.println("Zavírám okno..."); frame.saveSettings(); System.exit(0); } }); } }); } }