package com.github.xsavikx.androidscreencast.ui;
import com.github.xsavikx.androidscreencast.api.injector.Injector;
import com.github.xsavikx.androidscreencast.api.injector.InputKeyEvent;
import com.github.xsavikx.androidscreencast.dagger.MainComponentProvider;
import com.github.xsavikx.androidscreencast.exception.IORuntimeException;
import com.github.xsavikx.androidscreencast.ui.explorer.JFrameExplorer;
import com.github.xsavikx.androidscreencast.ui.interaction.KeyEventDispatcherFactory;
import com.github.xsavikx.androidscreencast.ui.interaction.KeyboardActionListenerFactory;
import com.github.xsavikx.androidscreencast.ui.interaction.MouseActionAdapter;
import com.google.common.io.Files;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import static com.github.xsavikx.androidscreencast.configuration.ApplicationConfigurationPropertyKeys.APP_WINDOW_HEIGHT_KEY;
import static com.github.xsavikx.androidscreencast.configuration.ApplicationConfigurationPropertyKeys.APP_WINDOW_WIDTH_KEY;
@Singleton
public class JFrameMain extends JFrame {
private static final long serialVersionUID = -2085909236767692371L;
private final JPanelScreen jp;
private final MouseActionAdapter ma;
private final Injector injector;
private final Dimension windowSize;
private final JFrameExplorer frameExplorer;
private final JDialogExecuteKeyEvent dialogExecuteKeyEvent;
private transient boolean isDisposed = false;
private JToolBar jtb = new JToolBar();
private JToolBar jtbHardkeys = new JToolBar();
private JScrollPane jsp;
private JButton jbExplorer = new JButton("Explore");
private JButton jbExecuteKeyEvent = new JButton("Execute keycode");
private JButton jbKbHome = new JButton("Home");
private JButton jbKbMenu = new JButton("Menu");
private JButton jbKbBack = new JButton("Back");
private JButton jbKbSearch = new JButton("Search");
private JButton jbKbPhoneOn = new JButton("Call");
private JButton jbKbPhoneOff = new JButton("End call");
private JButton jbRecord = new JButton("Start record");
private Dimension oldImageDimension;
@Inject
public JFrameMain(JPanelScreen jp, Injector injector, MouseActionAdapter ma,
JFrameExplorer frameExplorer, JDialogExecuteKeyEvent dialogExecuteKeyEvent, @Named(APP_WINDOW_WIDTH_KEY) int width,
@Named(APP_WINDOW_HEIGHT_KEY) int height) {
this.jp = jp;
this.injector = injector;
this.ma = ma;
this.frameExplorer = frameExplorer;
this.dialogExecuteKeyEvent = dialogExecuteKeyEvent;
this.windowSize = new Dimension(width, height);
}
@Override
public void dispose() {
if (isDisposed) {
return;
}
isDisposed = true;
super.dispose();
MainComponentProvider.mainComponent().application().stop();
}
public void initialize() {
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
KeyboardFocusManager.getCurrentKeyboardFocusManager()
.addKeyEventDispatcher(KeyEventDispatcherFactory.getKeyEventDispatcher(this));
jtb.setFocusable(false);
jbExplorer.setFocusable(false);
jbKbHome.setFocusable(false);
jbKbMenu.setFocusable(false);
jbKbBack.setFocusable(false);
jbKbSearch.setFocusable(false);
jbKbPhoneOn.setFocusable(false);
jbKbPhoneOff.setFocusable(false);
jbExecuteKeyEvent.setFocusable(false);
jbRecord.setFocusable(false);
jbKbHome.addActionListener(KeyboardActionListenerFactory.getInstance(InputKeyEvent.KEYCODE_HOME));
jbKbMenu.addActionListener(KeyboardActionListenerFactory.getInstance(InputKeyEvent.KEYCODE_MENU));
jbKbBack.addActionListener(KeyboardActionListenerFactory.getInstance(InputKeyEvent.KEYCODE_BACK));
jbKbSearch.addActionListener(KeyboardActionListenerFactory.getInstance(InputKeyEvent.KEYCODE_SEARCH));
jbKbPhoneOn.addActionListener(KeyboardActionListenerFactory.getInstance(InputKeyEvent.KEYCODE_CALL));
jbKbPhoneOff.addActionListener(KeyboardActionListenerFactory.getInstance(InputKeyEvent.KEYCODE_ENDCALL));
jbRecord.addActionListener(createRecordActionListener());
jtbHardkeys.add(jbKbHome);
jtbHardkeys.add(jbKbMenu);
jtbHardkeys.add(jbKbBack);
jtbHardkeys.add(jbKbSearch);
jtbHardkeys.add(jbKbPhoneOn);
jtbHardkeys.add(jbKbPhoneOff);
setLayout(new BorderLayout());
add(jtb, BorderLayout.NORTH);
add(jtbHardkeys, BorderLayout.SOUTH);
jsp = new JScrollPane(jp);
add(jsp, BorderLayout.CENTER);
jsp.setPreferredSize(new Dimension(100, 100));
pack();
setLocationRelativeTo(null);
setPreferredWindowSize();
jp.addMouseMotionListener(ma);
jp.addMouseListener(ma);
jp.addMouseWheelListener(ma);
jbExplorer.addActionListener(actionEvent -> {
SwingUtilities.invokeLater(() -> {
JFrameExplorer jf = frameExplorer;
jf.setIconImage(getIconImage());
jf.launch();
jf.setVisible(true);
});
});
jtb.add(jbExplorer);
jbExecuteKeyEvent.addActionListener(actionEvent -> {
SwingUtilities.invokeLater(dialogExecuteKeyEvent::open);
});
jtb.add(jbExecuteKeyEvent);
jtb.add(jbRecord);
}
private void setPreferredWindowSize() {
getContentPane().setPreferredSize(windowSize);
pack();
}
private ActionListener createRecordActionListener() {
return new ActionListener() {
private final Path tmpDir = Files.createTempDir().toPath();
private boolean recording = false;
private File tmpVideoFile;
@Override
public void actionPerformed(ActionEvent e) {
try {
if (!recording) {
recording = true;
jbRecord.setText("Stop record");
tmpVideoFile = java.nio.file.Files.createTempFile(tmpDir, "androidScreenCast", ".mov.tmp").toFile();
startRecording(tmpVideoFile);
} else {
recording = false;
stopRecording();
jbRecord.setText("Start record");
JFileChooser jFileChooser = new JFileChooser();
FileNameExtensionFilter filter = new FileNameExtensionFilter("Video file", "mov");
jFileChooser.setFileFilter(filter);
int returnVal = jFileChooser.showSaveDialog(JFrameMain.this);
if (returnVal == JFileChooser.APPROVE_OPTION) {
File resultFile = jFileChooser.getSelectedFile();
if (!resultFile.getName().endsWith(".mov")) {
resultFile = new File(resultFile.getAbsolutePath() + ".mov");
}
Files.move(tmpVideoFile, resultFile);
} else {
tmpVideoFile.deleteOnExit();
}
}
} catch (IOException ex) {
throw new IORuntimeException(ex);
}
}
};
}
public void launchInjector() {
injector.setScreenCaptureListener((size, image, landscape) -> {
if (oldImageDimension == null || !size.equals(oldImageDimension)) {
jsp.setPreferredSize(size);
JFrameMain.this.pack();
oldImageDimension = size;
}
jp.handleNewImage(size, image);
});
injector.start();
}
private void startRecording(File file) {
injector.startRecording(file);
}
private void stopRecording() {
injector.stopRecording();
}
}