TransferBot/src/main/java/it/cavallium/PrimaryController.java
2020-10-19 13:59:35 +02:00

273 lines
10 KiB
Java

package it.cavallium;
import com.google.i18n.phonenumbers.NumberParseException;
import com.google.i18n.phonenumbers.PhoneNumberUtil;
import com.google.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberFormat;
import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber;
import java.io.IOException;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.event.Event;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.ButtonType;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ListView;
import javafx.scene.control.TextField;
import javafx.scene.control.TextInputDialog;
import javafx.scene.input.InputMethodEvent;
import javafx.scene.layout.Pane;
import javafx.scene.text.Text;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;
public class PrimaryController {
@FXML private Pane main;
@FXML private TextField phoneNumber;
@FXML private ListView<Text> userbotsList;
@FXML private ComboBox<BaseChatInfo> sourceGroupCombo;
@FXML private ComboBox<BaseChatInfo> destGroupCombo;
@FXML private ListView<LogEntry> log;
@FXML
protected void initialize() {
for (PhoneNumber number : App.getTransferService().getPhoneNumbers()) {
userbotsList
.getItems()
.add(0,
new Text(getUserbotPrettyPrintPhoneNumber(number))
);
}
var srcItems = sourceGroupCombo.getItems();
srcItems.clear();
for (BaseChatInfo originSupergroups : App.getTransferService().getAdminSupergroups(true, false)) {
srcItems.add(originSupergroups);
}
var destItems = destGroupCombo.getItems();
destItems.clear();
for (BaseChatInfo destSupergroups : App.getTransferService().getAdminSupergroups(false, true)) {
destItems.add(destSupergroups);
}
App.getLogService().listenUpdates().subscribeOn(Schedulers.boundedElastic()).flatMap(logString -> MonoFxUtils.runLater(() -> {
if (log.getItems().size() >= App.getLogService().getMaxSize()) {
log.getItems().remove(0);
}
log.getItems().add(logString);
log.scrollTo(logString);
return Mono.empty();
})).subscribe();
}
private void disableClicks() {
main.setDisable(true);
}
private void enableClicks() {
main.setDisable(false);
}
@FXML
public void openSettings(ActionEvent actionEvent) throws IOException {
App.setRoot("settings");
}
@FXML
public void quit(ActionEvent actionEvent) {
Platform.exit();
}
@FXML
public void addUserbot(ActionEvent actionEvent) {
var eventSource = (Node) actionEvent.getSource();
var phoneNumberText = phoneNumber.getText();
try {
var phoneNumber = getUserbotPhoneNumber(phoneNumberText);
var phoneNumberPrettyText = getUserbotPrettyPrintPhoneNumber(phoneNumber);
disableClicks();
App.getTransferService().addUserbot(phoneNumber, (client) -> MonoFxUtils.runLater(() -> {
var authCodeAlert = new TextInputDialog();
authCodeAlert.setHeaderText("Insert authentication code that you received");
return PrimaryController.<Integer>loopAlert(authCodeAlert, (authCodeText) -> {
if (authCodeText.matches("^[0-9]{3,8}$")) {
try {
int authCode = Integer.parseUnsignedInt(authCodeText);
return Mono.just(authCode);
} catch (NumberFormatException ex) {
var alert = new Alert(AlertType.ERROR, "Can't parse authentication code number", ButtonType.CLOSE);
return MonoFxUtils.showAndWait(alert).then(Mono.empty());
}
} else {
var alert = new Alert(AlertType.ERROR, "Wrong authentication code number format", ButtonType.CLOSE);
return MonoFxUtils.showAndWait(alert).then(Mono.empty());
}
});
}), (client, hint) -> MonoFxUtils.runLater(() -> {
String hintText = "";
if (hint != null && !hint.isBlank()) {
hintText = " (hint: " + hint + ")";
}
var otpAlert = new TextInputDialog();
otpAlert.setHeaderText("Insert user password" + hintText + ":");
return loopAlert(otpAlert, (otpText) -> {
if (otpText.length() > 0) {
return Mono.just(otpText);
} else {
var alert = new Alert(AlertType.ERROR, "Wrong user password format", ButtonType.CLOSE);
alert.showAndWait();
return Mono.empty();
}
});
}), () -> {
// closed, remove from list
return MonoFxUtils.runLater(() -> {
userbotsList.getItems().removeIf(textBox -> {
try {
return getUserbotPhoneNumber(textBox.getText()).equals(phoneNumber);
} catch (NumberParseException e) {
// Can't happen
e.printStackTrace();
return false;
}
});
return Mono.empty();
});
}).handle((result, sink) -> {
if (result.failed()) {
sink.error(new Exception(result.getErrorMessage()));
} else {
sink.next(result);
}
}).flatMap((_v) -> MonoFxUtils.runLater(() -> {
var alert = new Alert(AlertType.INFORMATION,
"Added userbot " + PhoneNumberUtil
.getInstance()
.format(phoneNumber, PhoneNumberFormat.INTERNATIONAL),
ButtonType.CLOSE
);
return MonoFxUtils.showAndWait(alert);
})).doOnSuccess((_v) -> {
userbotsList
.getItems()
.add(0,
new Text(phoneNumberPrettyText)
);
this.phoneNumber.setText("");
})
.doOnTerminate(this::enableClicks)
.subscribe(_v -> {}, error -> {
Platform.runLater(() -> {
var alert = new Alert(AlertType.ERROR,
"Error while adding the userbot " + PhoneNumberUtil
.getInstance()
.format(phoneNumber, PhoneNumberFormat.INTERNATIONAL),
ButtonType.CLOSE
);
alert.setContentText(error.getLocalizedMessage());
MonoFxUtils.showAndWait(alert).subscribe();
enableClicks();
});
});
} catch (NumberFormatException | NumberParseException ex) {
var alert = new Alert(AlertType.ERROR, "Can't parse phone number format", ButtonType.CLOSE);
alert.showAndWait();
}
}
private String getUserbotPrettyPrintPhoneNumber(PhoneNumber phoneNumber) {
return PhoneNumberUtil
.getInstance()
.format(phoneNumber, PhoneNumberFormat.INTERNATIONAL);
}
public static PhoneNumber getUserbotPhoneNumber(String phoneNumberText) throws NumberParseException {
return PhoneNumberUtil
.getInstance()
.parse(phoneNumberText, PhoneNumberUtil.getCountryMobileToken(1));
}
private static <T> Mono<T> loopAlert(TextInputDialog alert, Function<String, Mono<T>> resultParser) {
return MonoFxUtils.showAndWaitOpt(alert)
.flatMap(resultOpt -> {
if (resultOpt.isEmpty()) {
return Mono.just(Optional.<T>empty());
} else {
return resultParser.apply(resultOpt.get()).filter(Objects::nonNull).map(Optional::of);
}
})
.repeatWhen(s -> s.takeWhile(n -> n == 0))
.last(Optional.empty())
.flatMap(opt -> opt.map(Mono::just).orElseGet(Mono::empty));
}
@FXML
public void removeUserbot(ActionEvent actionEvent) {
var selectedItem = userbotsList.getSelectionModel().getSelectedItem();
if (selectedItem != null) {
disableClicks();
try {
var phoneNumber = getUserbotPhoneNumber(selectedItem.getText());
App.getTransferService()
.closeUserbot(phoneNumber)
.subscribeOn(Schedulers.boundedElastic())
.then(MonoFxUtils.runLater(() -> {
// closed, remove from list
userbotsList.getItems().remove(selectedItem);
return Mono.empty();
}))
.doOnTerminate(this::enableClicks)
.subscribe();
} catch (NumberParseException e) {
e.printStackTrace();
}
}
}
@FXML
public void onSourceGroupAction(ActionEvent actionEvent) {
}
@FXML
public void onSourceGroupHiding(Event event) {
}
@FXML
public void onSourceGroupTextChanged(InputMethodEvent inputMethodEvent) {
}
@FXML
public void onSourceGroupShowing(Event event) {
}
@FXML
public void onDestGroupAction(ActionEvent actionEvent) {
}
@FXML
public void onDestGroupHiding(Event event) {
}
@FXML
public void onDestGroupTextChanged(InputMethodEvent inputMethodEvent) {
}
@FXML
public void onDestGroupShowing(Event event) {
}
@FXML
public void onDoTransfer(ActionEvent actionEvent) {
}
}