Skip to content

Commit

Permalink
Removed RXJava dependency, use JavaFX facilities instead
Browse files Browse the repository at this point in the history
  • Loading branch information
torakiki committed Apr 22, 2024
1 parent 6969e95 commit 51ea40f
Show file tree
Hide file tree
Showing 16 changed files with 233 additions and 197 deletions.
7 changes: 5 additions & 2 deletions pdfsam-core/pom.xml
Expand Up @@ -54,9 +54,12 @@
<groupId>org.pdfsam</groupId>
<artifactId>pdfsam-injector</artifactId>
</dependency>
<!-- test -->
<dependency>
<groupId>io.reactivex.rxjava3</groupId>
<artifactId>rxjava</artifactId>
<groupId>org.pdfsam</groupId>
<artifactId>pdfsam-test</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
1 change: 0 additions & 1 deletion pdfsam-core/src/main/java/module-info.java
Expand Up @@ -23,7 +23,6 @@
requires org.sejda.commons;
requires org.slf4j;

requires transitive io.reactivex.rxjava3;
requires transitive java.xml;
requires transitive javafx.graphics;
requires transitive org.apache.commons.lang3;
Expand Down
Expand Up @@ -18,7 +18,6 @@
*/
package org.pdfsam.core.context;

import io.reactivex.rxjava3.disposables.CompositeDisposable;
import javafx.application.ConditionalFeature;
import javafx.application.Platform;
import javafx.scene.Scene;
Expand Down Expand Up @@ -47,7 +46,6 @@ public class ApplicationContext implements Closeable {
private final ApplicationPersistentSettings persistentSettings;
private ApplicationRuntimeState runtimeState;
private Optional<Injector> injector = Optional.empty();
private CompositeDisposable disposable = new CompositeDisposable();

private ApplicationContext() {
this(new ApplicationPersistentSettings(new PreferencesRepository("/org/pdfsam/user/conf")), null);
Expand Down Expand Up @@ -84,11 +82,11 @@ public ApplicationRuntimeState runtimeState() {
if (Objects.isNull(this.runtimeState)) {
this.runtimeState = new ApplicationRuntimeState();
//listen for changes in the working path
disposable.add(this.persistentSettings().settingsChanges(WORKING_PATH).subscribe(path -> {
this.persistentSettings().settingsChanges(WORKING_PATH).subscribe(path -> {
this.runtimeState.defaultWorkingPath(
path.filter(StringUtils::isNotBlank).map(Paths::get).filter(Files::isDirectory)
.orElse(null));
}));
});

var workingPath = persistentSettings().get(WORKING_PATH).filter(StringUtils::isNotBlank).map(Paths::get)
.filter(Files::isDirectory).orElse(null);
Expand All @@ -104,18 +102,20 @@ public ApplicationRuntimeState runtimeState() {
* @param scene
*/
public void registerScene(Scene scene) {
disposable.add(this.runtimeState().theme().subscribe(t -> {
Platform.runLater(() -> {
scene.getStylesheets().setAll(t.stylesheets());
if (!Platform.isSupported(ConditionalFeature.TRANSPARENT_WINDOW)) {
scene.getStylesheets().addAll(t.transparentIncapableStylesheets());
}
});
}));
disposable.add(this.persistentSettings().settingsChanges(FONT_SIZE).subscribe(size -> {
this.runtimeState().theme().subscribe(t -> {
if (Objects.nonNull(t)) {
Platform.runLater(() -> {
scene.getStylesheets().setAll(t.stylesheets());
if (!Platform.isSupported(ConditionalFeature.TRANSPARENT_WINDOW)) {
scene.getStylesheets().addAll(t.transparentIncapableStylesheets());
}
});
}
});
this.persistentSettings().settingsChanges(FONT_SIZE).subscribe(size -> {
size.filter(StringUtils::isNotBlank).map(s -> String.format("-fx-font-size: %s;", s))
.ifPresentOrElse(scene.getRoot()::setStyle, () -> scene.getRoot().setStyle(""));
}));
});

this.persistentSettings().get(FONT_SIZE).filter(not(String::isBlank))
.ifPresent(size -> scene.getRoot().setStyle(String.format("-fx-font-size: %s;", size)));
Expand Down Expand Up @@ -148,9 +148,6 @@ public void clean() {
@Override
public void close() {
injector.ifPresent(Injector::close);
runtimeState().close();
persistentSettings.close();
disposable.dispose();
}

}
Expand Up @@ -18,9 +18,8 @@
*/
package org.pdfsam.core.context;

import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.subjects.PublishSubject;
import io.reactivex.rxjava3.subjects.Subject;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ObservableValue;
import org.pdfsam.persistence.PersistenceException;
import org.pdfsam.persistence.PreferencesRepository;
import org.slf4j.Logger;
Expand All @@ -30,6 +29,7 @@
import java.util.Optional;

import static java.util.Objects.nonNull;
import static java.util.Optional.empty;
import static java.util.Optional.of;
import static java.util.Optional.ofNullable;
import static org.sejda.commons.util.RequireUtils.requireNotNullArg;
Expand All @@ -39,14 +39,14 @@
*
* @author Andrea Vacondio
*/
public class ApplicationPersistentSettings implements AutoCloseable {
public class ApplicationPersistentSettings {

private static final Logger LOG = LoggerFactory.getLogger(ApplicationPersistentSettings.class);

private final PreferencesRepository repo;
private final Subject<PersistentPropertyChange<String>> stringSettingsChanges = PublishSubject.create();
private final Subject<PersistentPropertyChange<Integer>> intSettingsChanges = PublishSubject.create();
private final Subject<PersistentPropertyChange<Boolean>> boolSettingsChanges = PublishSubject.create();
private final SimpleObjectProperty<PersistentPropertyChange<String>> stringSettingsChanges = new SimpleObjectProperty<>();
private final SimpleObjectProperty<PersistentPropertyChange<Integer>> intSettingsChanges = new SimpleObjectProperty<>();
private final SimpleObjectProperty<PersistentPropertyChange<Boolean>> boolSettingsChanges = new SimpleObjectProperty<>();

ApplicationPersistentSettings(PreferencesRepository repo) {
this.repo = repo;
Expand Down Expand Up @@ -101,7 +101,7 @@ public void set(StringPersistentProperty prop, String value) {
requireNotNullArg(prop, "Cannot set value for a null property");
try {
this.repo.saveString(prop.key(), value);
stringSettingsChanges.onNext(new PersistentPropertyChange<>(prop, ofNullable(value)));
stringSettingsChanges.set(new PersistentPropertyChange<>(prop, ofNullable(value)));
} catch (PersistenceException e) {
LOG.error("Unable to save persistent property", e);
}
Expand All @@ -115,7 +115,7 @@ public void set(IntegerPersistentProperty prop, int value) {
requireNotNullArg(prop, "Cannot set value for a null property");
try {
this.repo.saveInt(prop.key(), value);
intSettingsChanges.onNext(new PersistentPropertyChange<>(prop, of(value)));
intSettingsChanges.set(new PersistentPropertyChange<>(prop, of(value)));
} catch (PersistenceException e) {
LOG.error("Unable to save persistent property", e);
}
Expand All @@ -128,7 +128,7 @@ public void set(BooleanPersistentProperty prop, boolean value) {
requireNotNullArg(prop, "Cannot set value for a null property");
try {
this.repo.saveBoolean(prop.key(), value);
boolSettingsChanges.onNext(new PersistentPropertyChange<>(prop, of(value)));
boolSettingsChanges.set(new PersistentPropertyChange<>(prop, of(value)));
} catch (PersistenceException e) {
LOG.error("Unable to save persistent property", e);
}
Expand Down Expand Up @@ -159,22 +159,40 @@ public void delete(PersistentProperty<?> property) {
/**
* @return an observable for changes to the given property
*/
public Observable<Optional<String>> settingsChanges(StringPersistentProperty prop) {
return stringSettingsChanges.hide().filter(c -> c.property().equals(prop)).map(PersistentPropertyChange::value);
public ObservableValue<Optional<String>> settingsChanges(StringPersistentProperty prop) {
var value = new SimpleObjectProperty<Optional<String>>(empty());
stringSettingsChanges.subscribe((old, c) -> {
if (c.property().equals(prop)) {
value.set(c.value());
}
});
return value;
}

/**
* @return an observable for changes to the given property
*/
public Observable<Optional<Integer>> settingsChanges(IntegerPersistentProperty prop) {
return intSettingsChanges.hide().filter(c -> c.property().equals(prop)).map(PersistentPropertyChange::value);
public ObservableValue<Optional<Integer>> settingsChanges(IntegerPersistentProperty prop) {
var value = new SimpleObjectProperty<Optional<Integer>>(empty());
intSettingsChanges.subscribe((old, c) -> {
if (c.property().equals(prop)) {
value.set(c.value());
}
});
return value;
}

/**
* @return an observable for changes to the given property
*/
public Observable<Optional<Boolean>> settingsChanges(BooleanPersistentProperty prop) {
return boolSettingsChanges.hide().filter(c -> c.property().equals(prop)).map(PersistentPropertyChange::value);
public ObservableValue<Optional<Boolean>> settingsChanges(BooleanPersistentProperty prop) {
var value = new SimpleObjectProperty<Optional<Boolean>>(empty());
boolSettingsChanges.subscribe((old, c) -> {
if (c.property().equals(prop)) {
value.set(c.value());
}
});
return value;
}

/**
Expand All @@ -189,10 +207,4 @@ public void clean() {
}
}

@Override
public void close() {
stringSettingsChanges.onComplete();
intSettingsChanges.onComplete();
boolSettingsChanges.onComplete();
}
}
Expand Up @@ -18,9 +18,8 @@
*/
package org.pdfsam.core.context;

import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.subjects.BehaviorSubject;
import io.reactivex.rxjava3.subjects.ReplaySubject;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ObservableValue;
import org.apache.commons.lang3.StringUtils;
import org.pdfsam.model.tool.Tool;
import org.pdfsam.theme.Theme;
Expand Down Expand Up @@ -49,14 +48,14 @@
*
* @author Andrea Vacondio
*/
public class ApplicationRuntimeState implements AutoCloseable {
public class ApplicationRuntimeState {

private static final Logger LOG = LoggerFactory.getLogger(ApplicationRuntimeState.class);

private Path defaultWorkingPath;
private final BehaviorSubject<Optional<Path>> workingPath = BehaviorSubject.createDefault(empty());
private final BehaviorSubject<Optional<Tool>> activeTool = BehaviorSubject.createDefault(empty());
private final ReplaySubject<Theme> theme = ReplaySubject.create(1);
private final SimpleObjectProperty<Optional<Path>> workingPath = new SimpleObjectProperty<>(empty());
private final SimpleObjectProperty<Optional<Tool>> activeTool = new SimpleObjectProperty<>(empty());
private final SimpleObjectProperty<Theme> theme = new SimpleObjectProperty<>();
private final Future<Map<String, Tool>> tools;

ApplicationRuntimeState() {
Expand All @@ -72,7 +71,7 @@ public class ApplicationRuntimeState implements AutoCloseable {
* @param path the current working directory or the parent in case of regular file. A null value clears the current working path
*/
void workingPath(Path path) {
workingPath.onNext(ofNullable(path).map(p -> {
workingPath.set(ofNullable(path).map(p -> {
if (Files.isRegularFile(p)) {
return p.getParent();
}
Expand Down Expand Up @@ -110,8 +109,8 @@ public Optional<Path> workingPathValue() {
return workingPath.getValue();
}

public Observable<Optional<Path>> workingPath() {
return workingPath.hide();
public ObservableValue<Optional<Path>> workingPath() {
return workingPath;
}

/**
Expand All @@ -130,7 +129,7 @@ public Map<String, Tool> tools() {
* @param activeTool the tool currently active
*/
public void activeTool(Tool activeTool) {
this.activeTool.onNext(ofNullable(activeTool));
this.activeTool.set(ofNullable(activeTool));
}

/**
Expand All @@ -140,33 +139,27 @@ public Optional<Tool> activeToolValue() {
return activeTool.getValue();
}

public Observable<Optional<Tool>> activeTool() {
return activeTool.hide();
public ObservableValue<Optional<Tool>> activeTool() {
return activeTool;
}

/**
* @return the current theme
*/
public Observable<Theme> theme() {
return this.theme.hide();
public ObservableValue<Theme> theme() {
return this.theme;
}

/**
* Sets the application theme
*/
public void theme(Theme theme) {
ofNullable(theme).ifPresent(this.theme::onNext);
ofNullable(theme).ifPresent(this.theme::set);
}

void defaultWorkingPath(Path defaultWorkingPath) {
this.defaultWorkingPath = defaultWorkingPath;
workingPath(defaultWorkingPath);
}

@Override
public void close() {
workingPath.onComplete();
theme.onComplete();
activeTool.onComplete();
}
}
Expand Up @@ -6,11 +6,14 @@
import org.junit.jupiter.api.io.TempDir;
import org.pdfsam.injector.Injector;
import org.pdfsam.persistence.PreferencesRepository;
import org.pdfsam.test.ValuesRecorder;

import java.nio.file.Path;
import java.util.Optional;

import static java.util.Optional.empty;
import static java.util.Optional.of;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;

Expand Down Expand Up @@ -53,9 +56,10 @@ void runtimeStateIsCreated(@TempDir Path tempDir) {
@Test
void runtimeWorkingPathIsBoundToPersistentSetting(@TempDir Path tempDir) {
var victim = new ApplicationContext(persistentSettings, null);
var testListener = victim.runtimeState().workingPath().test();
var values = new ValuesRecorder<Optional<Path>>();
victim.runtimeState().workingPath().subscribe(values);
victim.persistentSettings().set(StringPersistentProperty.WORKING_PATH, tempDir.toString());
testListener.assertValuesOnly(empty(), of(tempDir));
assertThat(values.values()).containsExactly(empty(), of(tempDir));
}

@Test
Expand All @@ -66,16 +70,6 @@ void clean() {
verify(persistentState).clean();
}

@Test
void close() {
var persistentState = mock(ApplicationPersistentSettings.class);
var runtimeState = mock(ApplicationRuntimeState.class);
var victim = new ApplicationContext(persistentState, runtimeState);
victim.close();
verify(persistentState).close();
verify(runtimeState).close();
}

@Test
void closeWithInjector() {
var persistentState = mock(ApplicationPersistentSettings.class);
Expand All @@ -84,8 +78,6 @@ void closeWithInjector() {
var victim = new ApplicationContext(persistentState, runtimeState);
victim.injector(injector);
victim.close();
verify(persistentState).close();
verify(runtimeState).close();
verify(injector).close();
}
}

0 comments on commit 51ea40f

Please sign in to comment.