package chatty.gui.components.admin; import chatty.Chatty; import chatty.gui.MainGui; import chatty.gui.components.LinkLabel; import chatty.gui.components.settings.DurationSetting; import chatty.util.DateTime; import chatty.util.api.ChannelInfo; import chatty.util.api.CommunitiesManager.Community; import chatty.util.api.TwitchApi; import chatty.util.api.TwitchApi.RequestResultCode; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; import javax.swing.*; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; /** * Dialog to change stream info and run commercials. * * @author tduva */ public class AdminDialog extends JDialog { private final static String EDITOR_TEXT = "[help-admin:status Help]"; private final static String EDITOR_TEXT_NO_ACCESS = "No Editor Access available. [help-admin:top More information..]"; private final static String COMMERCIALS_TEXT = "[help-admin:commercials Help]"; private final static String COMMERCIALS_TEXT_NO_ACCESS = "No Commercial Access available. [help-admin:top More information..]"; // Colors for hideable labels private static final Color LABEL_INVISIBLE = new Color(0, 0, 0, 0); private static final Color LABEL_VISIBLE = new Color(120, 150, 150); // Insets for smaller kind of buttons public static final Insets SMALL_BUTTON_INSETS = new Insets(-1,15,-1,15); // How often to call update() which updates times and runs commercials. private static final int UPDATE_DELAY = 4000; private final MainGui main; private final TwitchApi api; private final ActionListener actionListener = new MyActionListener(); private final StatusPanel statusPanel; private final CommercialPanel commercialPanel; // Shared private final JTabbedPane tabs; private final JButton close = new JButton("Close"); private final LinkLabel infoText; // Current state/settings (currentChannel specific) private String currentChannel; // Current access (not currentChannel specific) private boolean commercialAccess; private boolean editorAccess; public AdminDialog(MainGui main, TwitchApi api) { super(main); setTitle("Channel Admin - No Channel"); this.main = main; this.api = api; setResizable(false); addWindowListener(new WindowClosingListener()); setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); // Special objects infoText = new LinkLabel("Test",main.getLinkLabelListener()); statusPanel = new StatusPanel(this, main, api); commercialPanel = new CommercialPanel(main); setLayout(new GridBagLayout()); GridBagConstraints gbc; // Add to tab pane tabs = new JTabbedPane(); tabs.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { updateInfoText(); } }); tabs.addTab("Status", statusPanel); tabs.addTab("Commercial", commercialPanel); gbc = makeGbc(0,0,2,1); gbc.insets = new Insets(0,0,0,0); add(tabs, gbc); gbc = makeGbc(0,1,1,1); gbc.anchor = GridBagConstraints.WEST; gbc.fill = GridBagConstraints.HORIZONTAL; gbc.weightx = 1; add(infoText, gbc); gbc = makeGbc(1,1,1,1); //gbc.fill = GridBagConstraints.HORIZONTAL; gbc.anchor = GridBagConstraints.EAST; close.setMnemonic(KeyEvent.VK_C); add(close,gbc); close.addActionListener(actionListener); finishDialog(); startUpdateTimer(); } /** * Starts the timer that updates the dialog on the set delay (texts, running * commercials) */ private void startUpdateTimer() { Timer timer = new Timer(UPDATE_DELAY, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { update(); } }); timer.start(); } private void finishDialog() { pack(); } /** * Updates times and runs scheduled commercials. */ private void update() { if (isVisible()) { statusPanel.update(); commercialPanel.update(); // In case the text is going to be too big, breaking the dialog finishDialog(); } commercialPanel.checkScheduled(); } /** * Update the info text based on the current tab and access. */ private void updateInfoText() { if (tabs.getSelectedIndex() == 0) { if (editorAccess) { infoText.setText(EDITOR_TEXT); } else { infoText.setText(EDITOR_TEXT_NO_ACCESS); } } else { if (commercialAccess) { infoText.setText(COMMERCIALS_TEXT); } else { infoText.setText(COMMERCIALS_TEXT_NO_ACCESS); } } } /** * Set the kind of access the current token grants. To be able to show * appropriate info texts. * * @param editor * @param commercials */ public void updateAccess(boolean editor, boolean commercials) { this.editorAccess = editor; this.commercialAccess = commercials; updateInfoText(); } /** * Opens the dialog with the given currentChannel, positioning it correctly. * * @param channel */ public void open(String channel) { if (channel == null || channel.isEmpty()) { JOptionPane.showMessageDialog(main, "No channel specified. Can't" + " open admin dialog."); if (!Chatty.DEBUG) { return; } } statusPanel.setPutResult(""); setChannel(channel); setVisible(true); } public void commercialHotkey(int length) { commercialPanel.commercialHotkey(length); } public boolean isCommercialsTabVisible() { return isVisible() && tabs.getSelectedIndex() == 1; } /** * Sets the currentChannel, performing some actions only if it was changed. * Asks the user if it should be changed if a commercial is scheduled. * * @param channel */ private void setChannel(String channel) { if (channel != null && !channel.equals(currentChannel)) { if (commercialPanel.confirmChannelChange(channel)) { changeChannel(channel); } } if (channel != null && !channel.isEmpty()) { //update.setEnabled(true); } setTitle("Channel Admin - "+currentChannel); } /** * Change the currentChannel this dialog is about, so some loading/resetting * of currentChannel specific stuff is required. * * @param channel */ private void changeChannel(String channel) { this.currentChannel = channel; statusPanel.changeChannel(channel); commercialPanel.changeChannel(channel); update(); } /** * Changes the text on the given label, making it invisible if the text is * empty or visible again otherwise. * * @param label * @param text */ protected static void hideableLabel(JLabel label, String text) { if (text.isEmpty()) { label.setForeground(LABEL_INVISIBLE); } else { label.setForeground(LABEL_VISIBLE); label.setText(text); } } protected static GridBagConstraints makeGbc(int x, int y, int w, int h) { GridBagConstraints gbc = new GridBagConstraints(); gbc.gridx = x; gbc.gridy = y; gbc.gridwidth = w; gbc.gridheight = h; gbc.insets = new Insets(5,5,5,5); gbc.weighty = 0; return gbc; } /** * Closes the dialog, unless a commercial is scheduled, then ask the user * whether it should be continued or canceled. Closing the prompt keeps the * dialog open so the user can check the commercial again. */ private void close() { commercialPanel.saveSettings(); if (commercialPanel.checkOnClose()) { super.setVisible(false); } } @Override public void setVisible(boolean state) { if (state) { super.setVisible(true); } else { close(); } } public void setChannelInfo(String channel, ChannelInfo info, RequestResultCode result) { statusPanel.setChannelInfo(channel, info, result); } public void setPutResult(RequestResultCode result) { statusPanel.setPutResult(result); } public void commercialResult(String stream, String text, RequestResultCode result) { commercialPanel.commercialResult(stream, text, result); } public void updateCommercialDelaySettings(boolean enabled, long length) { commercialPanel.updateCommercialDelaySettings(enabled, length); } public void setStatusHistorySorting(String string) { statusPanel.setStatusHistorySorting(string); } public String getStatusHistorySorting() { return statusPanel.getStatusHistorySorting(); } /** * Main listener for button actions, commercial buttons have their own * listener which is created where the buttons are created. */ private class MyActionListener implements ActionListener { @Override public void actionPerformed(ActionEvent e) { if (e.getSource() == close) { close(); } } } /** * To get when the dialog is closed by the default (x) button and then close * it properly. */ private class WindowClosingListener extends WindowAdapter { @Override public void windowClosing(WindowEvent e) { close(); } } }