Skip to content
This repository has been archived by the owner on Apr 3, 2022. It is now read-only.

Commit

Permalink
In MainWindow are now all the startAll, abortAll etc. buttons placed
Browse files Browse the repository at this point in the history
vertically instead of horizontally and a abortAllAndClear button has been
added.

Changed so the code for opening the user's web browser is executed on a
background thread instead of the UI thread.

Modified the code for getting localized categories, creating new playlists
and downloading all existing playlists to perform some of their work on
a background thread.
  • Loading branch information
Stekeblad committed Mar 4, 2018
1 parent ad52a4b commit bf22885
Show file tree
Hide file tree
Showing 9 changed files with 198 additions and 72 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# What I am working on and planning on maybe doing in the future

#### Right now
- Get better images and add to readme + wiki + my gh-pages
- Bugs and small things

#### More important things to do
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane fx:id="mainWindowPane" prefHeight="828.0" prefWidth="1105.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="io.github.stekeblad.videouploader.main.mainWindowController">
<ToolBar prefHeight="40.0" prefWidth="1088.0">
<Button id="btn_presets" fx:id="btn_presets" mnemonicParsing="false" onAction="#onSettingsClicked" text="Settings" />
</ToolBar>
<ListView fx:id="listView" layoutX="15.0" layoutY="350.0" prefHeight="464.0" prefWidth="1070.0" AnchorPane.bottomAnchor="14.0" AnchorPane.leftAnchor="15.0" AnchorPane.rightAnchor="15.0" AnchorPane.topAnchor="225.0" />
<ListView fx:id="listView" layoutX="15.0" layoutY="350.0" prefHeight="464.0" prefWidth="1070.0"
AnchorPane.bottomAnchor="14.0" AnchorPane.leftAnchor="15.0" AnchorPane.rightAnchor="15.0"
AnchorPane.topAnchor="200.0"/>
<ListView id="chosen_files" fx:id="chosen_files" layoutX="14.0" layoutY="40.0" prefHeight="154.0" prefWidth="309.0" AnchorPane.leftAnchor="15.0" AnchorPane.topAnchor="40.0" />
<VBox layoutX="324.0" layoutY="40.0" prefHeight="145.0" prefWidth="177.0" spacing="4.0">
<Button fx:id="buttonPickFile" mnemonicParsing="false" onAction="#onPickFileClicked" prefHeight="25.0" prefWidth="148.0" text="Pick files to upload" />
Expand All @@ -16,9 +19,18 @@
<TextField fx:id="text_autoNum" maxWidth="-Infinity" prefHeight="25.0" prefWidth="72.0" />
<Button fx:id="btn_applyPreset" mnemonicParsing="false" onAction="#onApplyPresetClicked" text="Apply preset" />
</VBox>
<HBox layoutX="877.0" layoutY="194.0" prefHeight="25.0" prefWidth="461.0" spacing="10.0" AnchorPane.rightAnchor="17.0" AnchorPane.topAnchor="195.0">
<Button fx:id="btn_abortAll" mnemonicParsing="false" onAction="#onAbortAllUploadsClicked" text="Abort All Uploads" />
<Button fx:id="btn_removeFinished" mnemonicParsing="false" onAction="#onRemoveFinishedUploadsClicked" text="Remove All Finished Uploads" />
<Button fx:id="btn_startAll" mnemonicParsing="false" onAction="#onStartAllUploadsClicked" text="Start All Ready Uploads" />
</HBox>
<VBox alignment="TOP_RIGHT" layoutX="809.0" layoutY="40.0" maxHeight="180.0" prefWidth="279.0" spacing="5.0"
AnchorPane.rightAnchor="17.0" AnchorPane.topAnchor="40.0">
<opaqueInsets>
<Insets/>
</opaqueInsets>
<Button fx:id="btn_startAll" mnemonicParsing="false" onAction="#onStartAllUploadsClicked"
text="Start All Ready Uploads"/>
<Button fx:id="btn_removeFinished" mnemonicParsing="false" onAction="#onRemoveFinishedUploadsClicked"
text="Remove All Finished Uploads"/>
<Button fx:id="btn_abortAll" mnemonicParsing="false" onAction="#onAbortAllUploadsClicked"
text="Abort All Uploads"/>
<Button fx:id="btn_abortAndClear" mnemonicParsing="false" onAction="#onAbortAndClearClicked"
text="Abort All and Clear Uploads Area"/>
</VBox>
</AnchorPane>
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public class mainWindowController implements Initializable {
public Button btn_removeFinished;
public Button btn_startAll;
public Button btn_abortAll;
public Button btn_abortAndClear;

private ConfigManager configManager;
private PlaylistUtils playlistUtils;
Expand Down Expand Up @@ -81,6 +82,7 @@ public void initialize(URL location, ResourceBundle resources) {
choice_presets.setItems(FXCollections.observableArrayList(configManager.getPresetNames()));
btn_startAll.setTooltip(new Tooltip("Starts all uploads that have the \"Start Upload\" button visible"));
btn_abortAll.setTooltip(new Tooltip("Aborts all uploads that have the \"Abort\" button visible"));
btn_abortAndClear.setTooltip(new Tooltip("Aborts all uploads and removes all uploads from the list below"));

// Only allow numbers in autoNum textField
text_autoNum.textProperty().addListener((observable, oldValue, newValue) -> {
Expand Down Expand Up @@ -382,6 +384,25 @@ public void onAbortAllUploadsClicked(ActionEvent actionEvent) {
actionEvent.consume();
}

/**
* Aborts all uploads and removes all uploads from the list (aborted, finished and not started)
*
* @param actionEvent the button click event
*/
public void onAbortAndClearClicked(ActionEvent actionEvent) {
Optional<ButtonType> choice = AlertUtils.yesNo("Confirmation", "Are you sure you want to abort all started uploads and remove" +
"all started, aborted, finished and not yet started uploads?").showAndWait();
if (choice.isPresent()) {
if (choice.get() == ButtonType.YES) {
onAbortAllUploadsClicked(new ActionEvent());
uploadQueueVideos.clear();
uploadPaneCounter = 0;
updateUploadList();
}
}
actionEvent.consume();
}

/**
* Re-adds all elements to the uploadQueuePanes so the UI is up-to-date
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,15 @@

import io.github.stekeblad.videouploader.utils.AlertUtils;
import io.github.stekeblad.videouploader.utils.ConfigManager;
import io.github.stekeblad.videouploader.utils.background.OpenInBrowser;
import io.github.stekeblad.videouploader.youtube.utils.CategoryUtils;
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.*;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.stage.Stage;

import java.awt.*;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
Expand Down Expand Up @@ -104,21 +102,43 @@ public void onGetCategoriesClicked(ActionEvent actionEvent) {
}
}

// Send the request
// Visually indicate the program is working
btn_getCategories.setText("Downloading...");
btn_cancel.setDisable(true);
btn_getCategories.setDisable(true);
categoryUtils.downloadCategories();

// Handle negative result
if (categoryUtils.getCategoryNames().size() < 2) { // < 2 because of default "no categories" category
AlertUtils.simpleClose("Error", "The selected language or country code is not valid or not " +
"supported by Youtube, did not receive any categories").showAndWait();
actionEvent.consume();
return;
}

onCancelClicked(actionEvent);
// Send the request in the background
// Tell it what to do
Task<Void> backgroundTask = new Task<Void>() {
@Override
protected Void call() throws Exception {
categoryUtils.downloadCategories();
Platform.runLater(() -> {
if (categoryUtils.getCategoryNames().size() < 2) { // < 2 because of default "no categories" category
AlertUtils.simpleClose("Error", "The selected language or country code is not valid or not " +
"supported by Youtube, did not receive any categories").showAndWait();
btn_getCategories.setText("Get Categories");
btn_cancel.setDisable(false);
btn_getCategories.setDisable(false);
return;
}
onCancelClicked(new ActionEvent());
});
return null;
}
};

Thread backgroundThread = new Thread(backgroundTask);
// Define a handler for exceptions
backgroundThread.setUncaughtExceptionHandler((t, e) -> Platform.runLater(() -> {
AlertUtils.simpleClose("Error", "Request to get categories failed").showAndWait();
e.printStackTrace();
onCancelClicked(new ActionEvent());
}));

// Actually do the thing, start the process of getting the categories!
backgroundThread.start();
actionEvent.consume();
}

/**
Expand All @@ -137,19 +157,14 @@ public void onCancelClicked(ActionEvent actionEvent) {
* @param actionEvent the click event
*/
public void onCodeListCountryClicked(ActionEvent actionEvent) {
if(Desktop.isDesktopSupported()) {
try {
Desktop.getDesktop().browse(new URI("https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2#Officially_assigned_code_elements"));
actionEvent.consume();
return;
} catch (IOException | URISyntaxException e) {
System.err.println("Failed open country code list (Wikipedia)");
}
} else {
System.err.println("Desktop not supported, cant open Wikipedia country code list");
try {
new OpenInBrowser(new URI("https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2#Officially_assigned_code_elements"),
(t, e) -> Platform.runLater(() -> AlertUtils.simpleClose("Sorry!",
"For some reason we cant open the web page in your default browser, but this is the url:\n " +
"https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2#Officially_assigned_code_elements").showAndWait()));
} catch (URISyntaxException e) {
System.err.println("URI Error");
}
AlertUtils.simpleClose("Sorry!", "For some reason we cant open the web page in your default browser, but this is the url:\n " +
"https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2#Officially_assigned_code_elements").showAndWait();
actionEvent.consume();
}

Expand All @@ -159,19 +174,15 @@ public void onCodeListCountryClicked(ActionEvent actionEvent) {
* @param actionEvent the click event
*/
public void onCodeListLangClicked(ActionEvent actionEvent) {
if(Desktop.isDesktopSupported()) {
try {
Desktop.getDesktop().browse(new URI("https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes"));
actionEvent.consume();
return;
} catch (IOException | URISyntaxException e) {
System.err.println("Failed open language code list (Wikipedia)");
}
} else {
System.err.println("Desktop not supported, cant open Wikipedia language code list");
try {
new OpenInBrowser(new URI("https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes"),
(t, e) -> Platform.runLater(() -> AlertUtils.simpleClose("Sorry!",
"For some reason we cant open the web page in your default browser, but this is the url:\n " +
"https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes").showAndWait()));
} catch (URISyntaxException e) {
System.err.println("URI Error");

}
AlertUtils.simpleClose("Sorry!", "For some reason we cant open the web page in your default browser, but this is the url:\n " +
"https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes").showAndWait();
actionEvent.consume();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
import io.github.stekeblad.videouploader.youtube.LocalPlaylist;
import io.github.stekeblad.videouploader.youtube.utils.PlaylistUtils;
import io.github.stekeblad.videouploader.youtube.utils.VisibilityStatus;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.fxml.Initializable;
import javafx.scene.control.*;
Expand Down Expand Up @@ -55,10 +57,12 @@ public void initialize(URL location, ResourceBundle resources) {
*/
public void onWindowClose(WindowEvent windowEvent) {
ObservableList<CheckBox> listItems = list_playlists.getItems();
for (CheckBox listItem : listItems) {
playlistUtils.setVisible(listItem.getText(), listItem.isSelected());
if (listItems.size() > 0) {
for (CheckBox listItem : listItems) {
playlistUtils.setVisible(listItem.getText(), listItem.isSelected());
}
playlistUtils.saveCache();
}
playlistUtils.saveCache();
// event not consumed, it would cause the window to remain open
}

Expand Down Expand Up @@ -89,8 +93,27 @@ public void onRefreshPlaylistsClicked(ActionEvent actionEvent) {
// Auth done or user is ready to allow it
// Do not allow the button to be clicked again until the window is closed and reopened
btn_refreshPlaylists.setDisable(true);
playlistUtils.refreshPlaylist();
updatePlaylistList();

// Send the request in the background
Task<Void> backgroundTask = new Task<Void>() {
@Override
protected Void call() throws Exception {
playlistUtils.refreshPlaylist();
Platform.runLater(() -> updatePlaylistList());
return null;
}
};

Thread backgroundThread = new Thread(backgroundTask);
// Define a handler for exceptions
backgroundThread.setUncaughtExceptionHandler((t, e) -> Platform.runLater(() -> {
AlertUtils.simpleClose("Error", "Request to download playlists failed").showAndWait();
e.printStackTrace();
btn_refreshPlaylists.setDisable(false);
}));

// Start downloading playlists in the background and return
backgroundThread.start();
actionEvent.consume();
}

Expand Down Expand Up @@ -124,17 +147,41 @@ public void onAddNewPlaylistClicked(ActionEvent actionEvent) {
}
}

// Auth OK
LocalPlaylist localPlaylist = playlistUtils.addPlaylist(
txt_newPlaylistName.getText(), choice_privacyStatus.getSelectionModel().getSelectedItem());
if(localPlaylist == null) {
return;
}
CheckBox cb = new CheckBox(localPlaylist.getName());
cb.setSelected(true);
list_playlists.getItems().add(cb);
txt_newPlaylistName.setText(""); // visually indicate its done by clearing the new playlist name textField
// Auth OK, add the playlist
btn_addNewPlaylist.setDisable(true);
btn_addNewPlaylist.setText("Adding...");
final String listName = txt_newPlaylistName.getText();
final String privacyLevel = choice_privacyStatus.getSelectionModel().getSelectedItem();

// Perform the request in a background thread
Task<Void> backgroundTask = new Task<Void>() {
@Override
protected Void call() throws Exception {
LocalPlaylist localPlaylist = playlistUtils.addPlaylist(listName, privacyLevel);
if (localPlaylist == null) {
Platform.runLater(() -> AlertUtils.simpleClose("Error", "Failed to create new playlist").show());
return null;
}
CheckBox cb = new CheckBox(localPlaylist.getName());
cb.setSelected(true);
Platform.runLater(() -> {
list_playlists.getItems().add(cb);
txt_newPlaylistName.setText(""); // visually indicate its done by clearing the new playlist name textField
btn_addNewPlaylist.setDisable(false);
btn_addNewPlaylist.setText("Create new playlist");
});
return null;
}
};
Thread backgroundThread = new Thread(backgroundTask);
// Exception handler
backgroundThread.setUncaughtExceptionHandler((t, e) -> Platform.runLater(() -> {
AlertUtils.simpleClose("Error", "Request to create new playlist failed").showAndWait();
e.printStackTrace();
}));

// Start the background thread and return
backgroundThread.start();
actionEvent.consume();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package io.github.stekeblad.videouploader.utils.background;

import javafx.concurrent.Task;

import java.awt.*;
import java.net.URI;

/**
* Attempts to open a web page in the user's default browser by first creating a new thread and opening it from there.
* Calling Desktop.getDesktop().browse(...) on the UI thread does not work on all systems, on some it just fails silently.
*/
public class OpenInBrowser {

/**
* Opens uri in the user's default browser or throws a Exception while trying
*
* @param uri the address to the web page that should be opened
* @param ueh A UncaughtExceptionHandler to call if an Exception is thrown, can be null
*/
public OpenInBrowser(URI uri, Thread.UncaughtExceptionHandler ueh) {
Task<Void> task = new Task<Void>() {
@Override
protected Void call() throws Exception {
if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) {
Desktop.getDesktop().browse(uri);
return null;
} else {
throw new UnsupportedOperationException("Desktop not supported");
}
}
};
Thread thread = new Thread(task);
thread.setUncaughtExceptionHandler(ueh);
thread.start();
}
}
Loading

0 comments on commit bf22885

Please sign in to comment.