Initial commit

This commit is contained in:
2025-08-28 22:38:53 +02:00
commit f15208fe6d
232 changed files with 16821 additions and 0 deletions

21
gui/api/pom.xml Normal file
View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>ch.gtache.fro.gui</groupId>
<artifactId>gui</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>gui-api</artifactId>
<dependencies>
<dependency>
<groupId>ch.gtache.fro</groupId>
<artifactId>fro-api</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,14 @@
package ch.gtache.fro.gui;
/**
* Represents a GUI controller
*/
public interface Controller {
/**
* Returns the model for this controller
*
* @return The model
*/
Model model();
}

View File

@@ -0,0 +1,21 @@
package ch.gtache.fro.gui;
/**
* Controller for the fetch view
*/
public interface FetchController extends Controller {
/**
* Fetches the data for the currently selected bird
*
*/
void fetch();
/**
* Fetches all the data
*/
void fetchAll();
@Override
FetchModel model();
}

View File

@@ -0,0 +1,7 @@
package ch.gtache.fro.gui;
/**
* Model for the fetch view
*/
public interface FetchModel extends Model {
}

View File

@@ -0,0 +1,10 @@
package ch.gtache.fro.gui;
/**
* Controller for the main view
*/
public interface MainController extends Controller {
@Override
MainModel model();
}

View File

@@ -0,0 +1,7 @@
package ch.gtache.fro.gui;
/**
* Model for the main view
*/
public interface MainModel extends Model {
}

View File

@@ -0,0 +1,7 @@
package ch.gtache.fro.gui;
/**
* Represents a GUI model
*/
public interface Model {
}

View File

@@ -0,0 +1,10 @@
package ch.gtache.fro.gui;
/**
* Controller for the settings view
*/
public interface SettingsController extends Controller {
@Override
SettingsModel model();
}

View File

@@ -0,0 +1,7 @@
package ch.gtache.fro.gui;
/**
* Model for the settings view
*/
public interface SettingsModel extends Model {
}

View File

@@ -0,0 +1,12 @@
package ch.gtache.fro.practice.gui;
import ch.gtache.fro.gui.Controller;
/**
* Controller for the practice view
*/
public interface PracticeController extends Controller {
@Override
PracticeModel model();
}

View File

@@ -0,0 +1,23 @@
package ch.gtache.fro.practice.gui;
import ch.gtache.fro.gui.Model;
/**
* Model for the practice view - exact guess
*/
public interface PracticeExactModel extends Model {
/**
* Returns the user's current guess
*
* @return The user's current guess
*/
String guess();
/**
* Sets the guess
*
* @param guess The guess
*/
void guess(String guess);
}

View File

@@ -0,0 +1,14 @@
package ch.gtache.fro.practice.gui;
import ch.gtache.fro.gui.Controller;
/**
* Controller for a guess practice view
*/
public interface PracticeGuessController extends Controller {
/**
* Confirms the current guess
*/
void confirm();
}

View File

@@ -0,0 +1,11 @@
package ch.gtache.fro.practice.gui;
import ch.gtache.fro.gui.Model;
/**
* Model for the practice view
*/
public interface PracticeModel extends Model {
}

View File

@@ -0,0 +1,33 @@
package ch.gtache.fro.practice.gui;
import ch.gtache.fro.Bird;
import ch.gtache.fro.gui.Model;
import java.util.List;
/**
* Model for the practice view - multichoice guess
*/
public interface PracticeMultichoiceModel extends Model {
/**
* Returns the suggestions
*
* @return The suggestions
*/
List<Bird> suggestions();
/**
* Returns the selected suggestion
*
* @return The selected bird
*/
Bird selected();
/**
* Sets the selected suggestion
*
* @param selected The selected bird
*/
void selected(Bird selected);
}

View File

@@ -0,0 +1,11 @@
package ch.gtache.fro.practice.gui;
/**
* Controller for the practice view - exact picture
*/
public interface PracticePictureExactController extends PracticeGuessController {
@Override
PracticePictureExactModel model();
}

View File

@@ -0,0 +1,8 @@
package ch.gtache.fro.practice.gui;
/**
* Model for the practice view - exact picture
*/
public interface PracticePictureExactModel extends PracticePictureModel, PracticeExactModel {
}

View File

@@ -0,0 +1,24 @@
package ch.gtache.fro.practice.gui;
import ch.gtache.fro.Picture;
import ch.gtache.fro.gui.Model;
/**
* Represents a model for a practice view with a picture
*/
public interface PracticePictureModel extends Model {
/**
* Returns the picture to guess
*
* @return The picture
*/
Picture picture();
/**
* Sets the picture
*
* @param picture The picture
*/
void picture(Picture picture);
}

View File

@@ -0,0 +1,11 @@
package ch.gtache.fro.practice.gui;
/**
* Controller for the practice view - multichoice picture
*/
public interface PracticePictureMultichoiceController extends PracticeGuessController {
@Override
PracticePictureMultichoiceModel model();
}

View File

@@ -0,0 +1,8 @@
package ch.gtache.fro.practice.gui;
/**
* Model for the practice view - multichoice picture
*/
public interface PracticePictureMultichoiceModel extends PracticePictureModel, PracticeMultichoiceModel {
}

View File

@@ -0,0 +1,12 @@
package ch.gtache.fro.practice.gui;
import ch.gtache.fro.gui.Controller;
/**
* Controller for the practice result view
*/
public interface PracticeResultController extends Controller {
@Override
PracticeResultModel model();
}

View File

@@ -0,0 +1,9 @@
package ch.gtache.fro.practice.gui;
import ch.gtache.fro.gui.Model;
/**
* Model for the practice result view
*/
public interface PracticeResultModel extends Model {
}

View File

@@ -0,0 +1,17 @@
package ch.gtache.fro.practice.gui;
import ch.gtache.fro.gui.Controller;
/**
* Controller for the practice settings view
*/
public interface PracticeSettingsController extends Controller {
/**
* Starts a practice
*/
void startPractice();
@Override
PracticeSettingsModel model();
}

View File

@@ -0,0 +1,54 @@
package ch.gtache.fro.practice.gui;
import ch.gtache.fro.gui.Model;
import ch.gtache.fro.practice.PracticeType;
import java.util.List;
/**
* Model for the practice settings view
*/
public interface PracticeSettingsModel extends Model {
/**
* Returns the list of practice types
*
* @return The list of practice types
*/
List<PracticeType> practiceTypes();
/**
* Returns the currently selected practice type
*
* @return The practice type
*/
PracticeType practiceType();
/**
* Sets the practice type
*
* @param practiceType The practice type
*/
void practiceType(PracticeType practiceType);
/**
* Returns true if the practice type has suggestions
*
* @return True if the practice type has suggestions
*/
boolean hasSuggestions();
/**
* Returns the currently selected number of suggestions
*
* @return The number of suggestions
*/
int suggestionsNumber();
/**
* Sets the number of suggestions
*
* @param suggestionsNumber The number of suggestions
*/
void suggestionsNumber(int suggestionsNumber);
}

View File

@@ -0,0 +1,11 @@
package ch.gtache.fro.practice.gui;
/**
* Controller for the practice view - exact sound
*/
public interface PracticeSoundExactController extends PracticeGuessController {
@Override
PracticeSoundExactModel model();
}

View File

@@ -0,0 +1,8 @@
package ch.gtache.fro.practice.gui;
/**
* Model for the practice view - exact sound
*/
public interface PracticeSoundExactModel extends PracticeSoundModel, PracticeExactModel {
}

View File

@@ -0,0 +1,24 @@
package ch.gtache.fro.practice.gui;
import ch.gtache.fro.Sound;
import ch.gtache.fro.gui.Model;
/**
* Represents a model for a practice view with a sound
*/
public interface PracticeSoundModel extends Model {
/**
* Returns the sound to guess
*
* @return The sound
*/
Sound sound();
/**
* Sets the sound
*
* @param sound The sound
*/
void sound(Sound sound);
}

View File

@@ -0,0 +1,11 @@
package ch.gtache.fro.practice.gui;
/**
* Controller for the practice view - multichoice sound
*/
public interface PracticeSoundMultichoiceController extends PracticeGuessController {
@Override
PracticeSoundMultichoiceModel model();
}

View File

@@ -0,0 +1,8 @@
package ch.gtache.fro.practice.gui;
/**
* Model for the practice view - multichoice sound
*/
public interface PracticeSoundMultichoiceModel extends PracticeSoundModel, PracticeMultichoiceModel {
}

View File

@@ -0,0 +1,10 @@
package ch.gtache.fro.practice.gui;
/**
* Controller for the practice view - multipicture choice sound
*/
public interface PracticeSoundMultichoicePictureController extends PracticeGuessController {
@Override
PracticeSoundMultichoicePictureModel model();
}

View File

@@ -0,0 +1,32 @@
package ch.gtache.fro.practice.gui;
import ch.gtache.fro.Picture;
import java.util.List;
/**
* Model for the practice view - multipicture choice sound
*/
public interface PracticeSoundMultichoicePictureModel extends PracticeSoundModel {
/**
* Returns the suggestions
*
* @return The suggestions
*/
List<Picture> suggestions();
/**
* Returns the selected suggestion
*
* @return The selected picture
*/
Picture selected();
/**
* Sets the selected suggestion
*
* @param selected The selected picture
*/
void selected(Picture selected);
}

View File

@@ -0,0 +1,9 @@
/**
* GUI API module for the FRO project
*/
module ch.gtache.fro.gui.api {
requires transitive ch.gtache.fro.api;
exports ch.gtache.fro.gui;
exports ch.gtache.fro.practice.gui;
}

24
gui/core/pom.xml Normal file
View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>ch.gtache.fro.gui</groupId>
<artifactId>gui</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>gui-core</artifactId>
<dependencies>
<dependency>
<groupId>ch.gtache.fro.gui</groupId>
<artifactId>gui-api</artifactId>
</dependency>
<dependency>
<groupId>ch.gtache.fro</groupId>
<artifactId>fro-core</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,41 @@
package ch.gtache.fro.gui.impl;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.stream.Collectors;
/**
* Combination of multiple resource bundles
*/
@Singleton
public class CombinedResourceBundle extends ResourceBundle {
private final Map<String, String> entries;
@Inject
CombinedResourceBundle(final Set<ResourceBundle> resourceBundles) {
this.entries = resourceBundles.stream()
.flatMap(r -> r.keySet().stream().map(k -> new KeyValue(k, r.getString(k))))
.collect(Collectors.toUnmodifiableMap(KeyValue::key, KeyValue::value));
}
@Override
protected Object handleGetObject(final String key) {
return entries.get(key);
}
@Override
public Enumeration<String> getKeys() {
return Collections.enumeration(entries.keySet());
}
private record KeyValue(String key, String value) {
}
}

View File

@@ -0,0 +1,34 @@
package ch.gtache.fro.modules.gui.impl;
import ch.gtache.fro.modules.practice.gui.impl.GuiPracticeCoreModule;
import dagger.Module;
import dagger.Provides;
import dagger.multibindings.IntoSet;
import java.util.ResourceBundle;
@Module(includes = GuiPracticeCoreModule.class)
public abstract class GuiCoreModule {
private GuiCoreModule() {
}
@Provides
@IntoSet
static ResourceBundle providesFetchBundle() {
return ResourceBundle.getBundle("ch.gtache.fro.gui.impl.FetchBundle");
}
@Provides
@IntoSet
static ResourceBundle providesMainBundle() {
return ResourceBundle.getBundle("ch.gtache.fro.gui.impl.MainBundle");
}
@Provides
@IntoSet
static ResourceBundle providesSettingsBundle() {
return ResourceBundle.getBundle("ch.gtache.fro.gui.impl.SettingsBundle");
}
}

View File

@@ -0,0 +1,63 @@
package ch.gtache.fro.modules.practice.gui.impl;
import dagger.Module;
import dagger.Provides;
import dagger.multibindings.IntoSet;
import java.util.ResourceBundle;
@Module
public abstract class GuiPracticeCoreModule {
private GuiPracticeCoreModule() {
}
@Provides
@IntoSet
static ResourceBundle providesPracticeBundle() {
return ResourceBundle.getBundle("ch.gtache.fro.practice.gui.impl.PracticeBundle");
}
@Provides
@IntoSet
static ResourceBundle providesPracticePictureExactBundle() {
return ResourceBundle.getBundle("ch.gtache.fro.practice.gui.impl.PracticePictureExactBundle");
}
@Provides
@IntoSet
static ResourceBundle providesPracticePictureMultichoiceBundle() {
return ResourceBundle.getBundle("ch.gtache.fro.practice.gui.impl.PracticePictureMultichoiceBundle");
}
@Provides
@IntoSet
static ResourceBundle providesPracticeResultBundle() {
return ResourceBundle.getBundle("ch.gtache.fro.practice.gui.impl.PracticeResultBundle");
}
@Provides
@IntoSet
static ResourceBundle providesPracticeSettingsBundle() {
return ResourceBundle.getBundle("ch.gtache.fro.practice.gui.impl.PracticeSettingsBundle");
}
@Provides
@IntoSet
static ResourceBundle providesPracticeSoundExactBundle() {
return ResourceBundle.getBundle("ch.gtache.fro.practice.gui.impl.PracticeSoundExactBundle");
}
@Provides
@IntoSet
static ResourceBundle providesPracticeSoundMultichoiceBundle() {
return ResourceBundle.getBundle("ch.gtache.fro.practice.gui.impl.PracticeSoundMultichoiceBundle");
}
@Provides
@IntoSet
static ResourceBundle providesPracticeSoundMultichoicePictureBundle() {
return ResourceBundle.getBundle("ch.gtache.fro.practice.gui.impl.PracticeSoundMultichoicePictureBundle");
}
}

View File

@@ -0,0 +1,13 @@
/**
* GUI core module for the FRO project
*/
module ch.gtache.fro.gui.core {
requires transitive ch.gtache.fro.gui.api;
requires ch.gtache.fro.core;
requires jakarta.inject;
requires dagger;
exports ch.gtache.fro.gui.impl;
exports ch.gtache.fro.modules.gui.impl;
exports ch.gtache.fro.modules.practice.gui.impl;
}

View File

@@ -0,0 +1,3 @@
fetch.button.all.label=Fetch all
fetch.button.fetch.label=Fetch
fetch.providers.label=Providers

View File

@@ -0,0 +1,3 @@
fetch.button.all.label=Fetch all
fetch.button.fetch.label=Fetch
fetch.providers.label=Providers

View File

@@ -0,0 +1,3 @@
fetch.button.all.label=Télécharger tous
fetch.button.fetch.label=Télécharger
fetch.providers.label=Sources

View File

@@ -0,0 +1,3 @@
main.tab.fetch.label=Fetch
main.tab.practice.label=Practice
main.tab.settings.label=Settings

View File

@@ -0,0 +1,3 @@
main.tab.fetch.label=Fetch
main.tab.practice.label=Practice
main.tab.settings.label=Settings

View File

@@ -0,0 +1,3 @@
main.tab.fetch.label=Téléchargement
main.tab.practice.label=Entraînement
main.tab.settings.label=Paramètres

View File

@@ -0,0 +1,5 @@
settings.table.column.bird=Bird
settings.table.column.enabled=Enabled
settings.table.column.fetchers=Fetchers
settings.table.column.pictures=Pictures
settings.table.column.sounds=Sounds

View File

@@ -0,0 +1,5 @@
settings.table.column.bird=Bird
settings.table.column.enabled=Enabled
settings.table.column.fetchers=Fetchers
settings.table.column.pictures=Pictures
settings.table.column.sounds=Sounds

View File

@@ -0,0 +1,5 @@
settings.table.column.bird=Oiseau
settings.table.column.enabled=Activé
settings.table.column.fetchers=Fournisseurs
settings.table.column.pictures=Images
settings.table.column.sounds=Sons

View File

@@ -0,0 +1 @@
practice.picture.exact.validate.button.label=Confirm

View File

@@ -0,0 +1 @@
practice.picture.exact.validate.button.label=Confirm

View File

@@ -0,0 +1 @@
practice.picture.exact.validate.button.label=Confirmer

View File

@@ -0,0 +1 @@
practice.picture.multichoice.validate.button.label=Confirm

View File

@@ -0,0 +1 @@
practice.picture.multichoice.validate.button.label=Confirm

View File

@@ -0,0 +1 @@
practice.picture.multichoice.validate.button.label=Confirmer

View File

@@ -0,0 +1,3 @@
practice.result.failure.label=Failed guesses
practice.result.label=Practice result
practice.result.success.label=Correct guesses

View File

@@ -0,0 +1,3 @@
practice.result.failure.label=Failed guesses
practice.result.label=Practice result
practice.result.success.label=Correct guesses

View File

@@ -0,0 +1,3 @@
practice.result.failure.label=Choix incorrects
practice.result.label=Résultat
practice.result.success.label=Choix corrects

View File

@@ -0,0 +1,3 @@
practice.settings.start.button.label=Start
practice.settings.suggestions.number.label=Number of suggestions
practice.settings.type.label=Practice type

View File

@@ -0,0 +1,3 @@
practice.settings.start.button.label=Start
practice.settings.suggestions.number.label=Number of suggestions
practice.settings.type.label=Practice type

View File

@@ -0,0 +1,3 @@
practice.settings.start.button.label=Démarrer
practice.settings.suggestions.number.label=Nombre de suggestions
practice.settings.type.label=Type d'entraînement

View File

@@ -0,0 +1 @@
practice.sound.exact.validate.button.label=Confirm

View File

@@ -0,0 +1 @@
practice.sound.exact.validate.button.label=Confirm

View File

@@ -0,0 +1 @@
practice.sound.exact.validate.button.label=Confirmer

View File

@@ -0,0 +1 @@
practice.sound.multichoice.validate.button.label=Confirm

View File

@@ -0,0 +1 @@
practice.sound.multichoice.validate.button.label=Confirm

View File

@@ -0,0 +1 @@
practice.sound.multichoice.validate.button.label=Confirmer

View File

@@ -0,0 +1 @@
practice.sound.multichoice.picture.validate.button.label=Confirm

View File

@@ -0,0 +1 @@
practice.sound.multichoice.picture.validate.button.label=Confirm

View File

@@ -0,0 +1 @@
practice.sound.multichoice.picture.validate.button.label=Confirmer

50
gui/fx/pom.xml Normal file
View File

@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>ch.gtache.fro.gui</groupId>
<artifactId>gui</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>gui-fx</artifactId>
<properties>
<javafx.version>24.0.2</javafx.version>
<controlsfx.version>11.2.2</controlsfx.version>
</properties>
<dependencies>
<dependency>
<groupId>ch.gtache.fro.gui</groupId>
<artifactId>gui-core</artifactId>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>${javafx.version}</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>${javafx.version}</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-media</artifactId>
<version>${javafx.version}</version>
</dependency>
<dependency>
<groupId>org.controlsfx</groupId>
<artifactId>controlsfx</artifactId>
<version>${controlsfx.version}</version>
</dependency>
<dependency>
<groupId>com.google.dagger</groupId>
<artifactId>dagger</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,61 @@
package ch.gtache.fro.gui.fx;
import ch.gtache.fro.Bird;
import ch.gtache.fro.Fetcher;
import ch.gtache.fro.gui.FetchController;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import org.controlsfx.control.CheckComboBox;
import org.controlsfx.control.PrefixSelectionComboBox;
import java.util.Objects;
/**
* FX implementation of {@link FetchController}
*/
@Singleton
public final class FXFetchController implements FetchController {
private final FXFetchModel model;
@FXML
private PrefixSelectionComboBox<Bird> birdCombobox;
@FXML
private Button fetchButton;
@FXML
private Button fetchAllButton;
@FXML
private CheckComboBox<Fetcher> providersCombobox;
@Inject
FXFetchController(final FXFetchModel model) {
this.model = Objects.requireNonNull(model);
}
@Override
public void fetch() {
throw new UnsupportedOperationException();
}
@Override
public void fetchAll() {
throw new UnsupportedOperationException();
}
@Override
public FXFetchModel model() {
return model;
}
@FXML
private void fetchBirdPressed() {
fetch();
}
@FXML
private void fetchAllPressed() {
fetchAll();
}
}

View File

@@ -0,0 +1,17 @@
package ch.gtache.fro.gui.fx;
import ch.gtache.fro.gui.FetchModel;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
/**
* FX implementation of {@link FetchModel}
*/
@Singleton
public final class FXFetchModel implements FetchModel {
@Inject
FXFetchModel() {
}
}

View File

@@ -0,0 +1,35 @@
package ch.gtache.fro.gui.fx;
import ch.gtache.fro.gui.MainController;
import ch.gtache.fro.practice.gui.fx.FXPracticeController;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import javafx.fxml.FXML;
import java.util.Objects;
/**
* FX implementation of {@link MainController}
*/
@Singleton
public final class FXMainController implements MainController {
@FXML
private FXFetchController fetchController;
@FXML
private FXSettingsController settingsController;
@FXML
private FXPracticeController practiceController;
private final FXMainModel model;
@Inject
FXMainController(final FXMainModel model) {
this.model = Objects.requireNonNull(model);
}
@Override
public FXMainModel model() {
return model;
}
}

View File

@@ -0,0 +1,17 @@
package ch.gtache.fro.gui.fx;
import ch.gtache.fro.gui.MainModel;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
/**
* FX implementation of {@link MainModel}
*/
@Singleton
public final class FXMainModel implements MainModel {
@Inject
FXMainModel() {
}
}

View File

@@ -0,0 +1,32 @@
package ch.gtache.fro.gui.fx;
import ch.gtache.fro.Bird;
import ch.gtache.fro.gui.SettingsController;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import javafx.fxml.FXML;
import javafx.scene.control.TableView;
import java.util.Objects;
/**
* FX implementation of {@link SettingsController}
*/
@Singleton
public final class FXSettingsController implements SettingsController {
private final FXSettingsModel model;
@FXML
private TableView<Bird> table;
@Inject
FXSettingsController(final FXSettingsModel model) {
this.model = Objects.requireNonNull(model);
}
@Override
public FXSettingsModel model() {
return model;
}
}

View File

@@ -0,0 +1,16 @@
package ch.gtache.fro.gui.fx;
import ch.gtache.fro.gui.SettingsModel;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
/**
* FX implementation of {@link SettingsModel}
*/
@Singleton
public final class FXSettingsModel implements SettingsModel {
@Inject
FXSettingsModel() {
}
}

View File

@@ -0,0 +1,104 @@
package ch.gtache.fro.modules.gui.fx;
import ch.gtache.fro.gui.FetchController;
import ch.gtache.fro.gui.FetchModel;
import ch.gtache.fro.gui.MainController;
import ch.gtache.fro.gui.MainModel;
import ch.gtache.fro.gui.SettingsController;
import ch.gtache.fro.gui.SettingsModel;
import ch.gtache.fro.gui.fx.FXFetchController;
import ch.gtache.fro.gui.fx.FXFetchModel;
import ch.gtache.fro.gui.fx.FXMainController;
import ch.gtache.fro.gui.fx.FXMainModel;
import ch.gtache.fro.gui.fx.FXSettingsController;
import ch.gtache.fro.gui.fx.FXSettingsModel;
import ch.gtache.fro.gui.impl.CombinedResourceBundle;
import ch.gtache.fro.modules.practice.gui.fx.FXPracticeModule;
import ch.gtache.fro.practice.gui.fx.FXPracticeController;
import ch.gtache.fro.practice.gui.fx.FXPracticePictureExactController;
import ch.gtache.fro.practice.gui.fx.FXPracticePictureMultichoiceController;
import ch.gtache.fro.practice.gui.fx.FXPracticeResultController;
import ch.gtache.fro.practice.gui.fx.FXPracticeSettingsController;
import ch.gtache.fro.practice.gui.fx.FXPracticeSoundExactController;
import ch.gtache.fro.practice.gui.fx.FXPracticeSoundMultichoiceController;
import ch.gtache.fro.practice.gui.fx.FXPracticeSoundMultichoicePictureController;
import dagger.Binds;
import dagger.Module;
import dagger.Provides;
import jakarta.inject.Singleton;
import javafx.fxml.FXMLLoader;
/**
* Dagger module for the FX GUI package
*/
@Module(includes = FXPracticeModule.class)
public abstract class FXModule {
private FXModule() {
//Empty constructor
}
@Provides
@Singleton
static FXMLLoader providesFXMLLoader(final FXFetchController fetchController,
final FXMainController mainController,
final FXSettingsController settingsController,
final FXPracticeController practiceController,
final FXPracticeResultController practiceResultController,
final FXPracticeSettingsController practiceSettingsController,
final FXPracticePictureExactController practicePictureExactController,
final FXPracticePictureMultichoiceController practicePictureMultichoiceController,
final FXPracticeSoundExactController practiceSoundExactController,
final FXPracticeSoundMultichoiceController practiceSoundMultichoiceController,
final FXPracticeSoundMultichoicePictureController practiceSoundMultichoicePictureController,
final CombinedResourceBundle combinedResourceBundle) {
final var loader = new FXMLLoader(FXModule.class.getResource("/ch/gtache/fro/gui/fx/mainView.fxml"));
loader.setResources(combinedResourceBundle);
loader.setControllerFactory(c -> {
if (c == FXFetchController.class) {
return fetchController;
} else if (c == FXMainController.class) {
return mainController;
} else if (c == FXSettingsController.class) {
return settingsController;
} else if (c == FXPracticeController.class) {
return practiceController;
} else if (c == FXPracticeResultController.class) {
return practiceResultController;
} else if (c == FXPracticeSettingsController.class) {
return practiceSettingsController;
} else if (c == FXPracticePictureExactController.class) {
return practicePictureExactController;
} else if (c == FXPracticePictureMultichoiceController.class) {
return practicePictureMultichoiceController;
} else if (c == FXPracticeSoundExactController.class) {
return practiceSoundExactController;
} else if (c == FXPracticeSoundMultichoiceController.class) {
return practiceSoundMultichoiceController;
} else if (c == FXPracticeSoundMultichoicePictureController.class) {
return practiceSoundMultichoicePictureController;
} else {
throw new IllegalArgumentException("Unknown controller class " + c);
}
});
return loader;
}
@Binds
abstract FetchController bindsFetchController(final FXFetchController fetchController);
@Binds
abstract FetchModel bindsFetchModel(final FXFetchModel fetchModel);
@Binds
abstract MainController bindsMainController(final FXMainController mainController);
@Binds
abstract MainModel bindsMainModel(final FXMainModel mainModel);
@Binds
abstract SettingsController bindsSettingsController(final FXSettingsController settingsController);
@Binds
abstract SettingsModel bindsSettingsModel(final FXSettingsModel settingsModel);
}

View File

@@ -0,0 +1,59 @@
package ch.gtache.fro.modules.practice.gui.fx;
import ch.gtache.fro.practice.gui.*;
import ch.gtache.fro.practice.gui.fx.*;
import dagger.Binds;
import dagger.Module;
/**
* Dagger module for the FX practice package
*/
@Module
public abstract class FXPracticeModule {
private FXPracticeModule() {
//Empty constructor
}
@Binds
abstract PracticeController bindsPracticeController(final FXPracticeController practiceController);
@Binds
abstract PracticeModel bindsPracticeModel(final FXPracticeModel practiceModel);
@Binds
abstract PracticeSettingsController bindsPracticeSettingsController(final FXPracticeSettingsController practiceSettingsController);
@Binds
abstract PracticeSettingsModel bindsPracticeSettingsModel(final FXPracticeSettingsModel practiceSettingsModel);
@Binds
abstract PracticePictureExactController bindsPracticePictureExactController(final FXPracticePictureExactController practicePictureExactController);
@Binds
abstract PracticePictureExactModel bindsPracticePictureExactModel(final FXPracticePictureExactModel practicePictureExactModel);
@Binds
abstract PracticePictureMultichoiceController bindsPracticePictureMultichoiceController(final FXPracticePictureMultichoiceController practicePictureMultichoiceController);
@Binds
abstract PracticePictureMultichoiceModel bindsPracticePictureMultichoiceModel(final FXPracticePictureMultichoiceModel practicePictureMultichoiceModel);
@Binds
abstract PracticeSoundExactController bindsPracticeSoundExactController(final FXPracticeSoundExactController practiceSoundExactController);
@Binds
abstract PracticeSoundExactModel bindsPracticeSoundExactModel(final FXPracticeSoundExactModel practiceSoundExactModel);
@Binds
abstract PracticeSoundMultichoiceController bindsPracticeSoundMultichoiceController(final FXPracticeSoundMultichoiceController practiceSoundMultichoiceController);
@Binds
abstract PracticeSoundMultichoiceModel bindsPracticeSoundMultichoiceModel(final FXPracticeSoundMultichoiceModel practiceSoundMultichoiceModel);
@Binds
abstract PracticeSoundMultichoicePictureController bindsPracticeSoundMultichoicePictureController(final FXPracticeSoundMultichoicePictureController practiceSoundMultichoicePictureController);
@Binds
abstract PracticeSoundMultichoicePictureModel bindsPracticeSoundMultichoicePictureModel(final FXPracticeSoundMultichoicePictureModel practiceSoundMultichoicePictureModel);
}

View File

@@ -0,0 +1,56 @@
package ch.gtache.fro.practice.gui.fx;
import ch.gtache.fro.practice.gui.PracticeController;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import javafx.fxml.FXML;
import javafx.scene.layout.Pane;
import java.util.Objects;
/**
* FX implementation of {@link PracticeController}
*/
@Singleton
public final class FXPracticeController implements PracticeController {
@FXML
private Pane practiceSettings;
@FXML
private Pane practiceResult;
@FXML
private Pane practicePictureExact;
@FXML
private Pane practicePictureMultichoice;
@FXML
private Pane practiceSoundExact;
@FXML
private Pane practiceSoundMultichoice;
@FXML
private Pane practiceSoundMultichoicePicture;
private final FXPracticeModel model;
@Inject
FXPracticeController(final FXPracticeModel model) {
this.model = Objects.requireNonNull(model);
}
@FXML
private void initialize() {
model.panes().addAll(practiceSettings, practiceResult, practicePictureExact, practicePictureMultichoice,
practiceSoundExact, practiceSoundMultichoice, practiceSoundMultichoicePicture);
model.selectedPaneProperty().addListener((_, _, newValue) -> {
for (final var pane : model.panes()) {
pane.setManaged(pane == newValue);
pane.setVisible(pane == newValue);
}
});
model.setSelectedPane(practiceSettings);
}
@Override
public FXPracticeModel model() {
return model;
}
}

View File

@@ -0,0 +1,42 @@
package ch.gtache.fro.practice.gui.fx;
import ch.gtache.fro.practice.gui.PracticeModel;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.layout.Pane;
/**
* FX implementation of {@link PracticeModel}
*/
@Singleton
public final class FXPracticeModel implements PracticeModel {
private final ObservableList<Pane> panes;
private final ObjectProperty<Pane> selectedPane;
@Inject
FXPracticeModel() {
this.panes = FXCollections.observableArrayList();
this.selectedPane = new SimpleObjectProperty<>();
}
ObservableList<Pane> panes() {
return panes;
}
Pane selectedPane() {
return selectedPane.get();
}
void setSelectedPane(final Pane pane) {
selectedPane.set(pane);
}
ObjectProperty<Pane> selectedPaneProperty() {
return selectedPane;
}
}

View File

@@ -0,0 +1,56 @@
package ch.gtache.fro.practice.gui.fx;
import ch.gtache.fro.PictureType;
import ch.gtache.fro.practice.gui.PracticePictureExactController;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.image.ImageView;
import org.controlsfx.control.PrefixSelectionComboBox;
import org.controlsfx.control.textfield.CustomTextField;
import java.util.Objects;
/**
* FX implementation of {@link PracticePictureExactController}
*/
@Singleton
public final class FXPracticePictureExactController implements PracticePictureExactController {
private final FXPracticePictureExactModel model;
@FXML
private ImageView pictureView;
@FXML
private CustomTextField nameField;
@FXML
private PrefixSelectionComboBox<PictureType> typeCombobox;
@FXML
private Button validateButton;
@Inject
FXPracticePictureExactController(final FXPracticePictureExactModel model) {
this.model = Objects.requireNonNull(model);
}
@Override
public void confirm() {
throw new UnsupportedOperationException();
}
@Override
public FXPracticePictureExactModel model() {
return model;
}
@FXML
private void enterPressed() {
confirm();
}
@FXML
private void validatePressed() {
confirm();
}
}

View File

@@ -0,0 +1,65 @@
package ch.gtache.fro.practice.gui.fx;
import ch.gtache.fro.Picture;
import ch.gtache.fro.practice.gui.PracticePictureExactModel;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
/**
* FX implementation of {@link PracticePictureExactModel}
*/
@Singleton
public final class FXPracticePictureExactModel implements PracticePictureExactModel {
private final StringProperty guess;
private final ObjectProperty<Picture> picture;
@Inject
FXPracticePictureExactModel() {
this.guess = new SimpleStringProperty();
this.picture = new SimpleObjectProperty<>();
}
@Override
public String guess() {
return guess.get();
}
@Override
public void guess(final String guess) {
this.guess.set(guess);
}
/**
* Returns the property for the user guess
*
* @return the property for the user guess
*/
StringProperty guessProperty() {
return guess;
}
@Override
public Picture picture() {
return picture.get();
}
@Override
public void picture(final Picture picture) {
this.picture.set(picture);
}
/**
* Returns the property for the picture
*
* @return the property for the picture
*/
ObjectProperty<Picture> pictureProperty() {
return picture;
}
}

View File

@@ -0,0 +1,45 @@
package ch.gtache.fro.practice.gui.fx;
import ch.gtache.fro.practice.gui.PracticePictureMultichoiceController;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.layout.GridPane;
import java.util.Objects;
/**
* FX implementation of {@link PracticePictureMultichoiceController}
*/
@Singleton
public final class FXPracticePictureMultichoiceController implements PracticePictureMultichoiceController {
private final FXPracticePictureMultichoiceModel model;
@FXML
private GridPane grid;
@FXML
private Button validateButton;
@Inject
FXPracticePictureMultichoiceController(final FXPracticePictureMultichoiceModel model) {
this.model = Objects.requireNonNull(model);
}
@Override
public FXPracticePictureMultichoiceModel model() {
return model;
}
@Override
public void confirm() {
throw new UnsupportedOperationException();
}
@FXML
private void validatePressed() {
confirm();
}
}

View File

@@ -0,0 +1,73 @@
package ch.gtache.fro.practice.gui.fx;
import ch.gtache.fro.Bird;
import ch.gtache.fro.Picture;
import ch.gtache.fro.practice.gui.PracticePictureMultichoiceModel;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
/**
* FX implementation of {@link PracticePictureMultichoiceModel}
*/
@Singleton
public final class FXPracticePictureMultichoiceModel implements PracticePictureMultichoiceModel {
private final ObjectProperty<Picture> picture;
private final ObservableList<Bird> suggestions;
private final ObjectProperty<Bird> selected;
@Inject
FXPracticePictureMultichoiceModel() {
this.picture = new SimpleObjectProperty<>();
this.suggestions = FXCollections.observableArrayList();
this.selected = new SimpleObjectProperty<>();
}
@Override
public ObservableList<Bird> suggestions() {
return suggestions;
}
@Override
public Bird selected() {
return selected.get();
}
@Override
public void selected(final Bird selected) {
this.selected.set(selected);
}
/**
* Returns the property for the selected bird
*
* @return the property for the selected bird
*/
ObjectProperty<Bird> selectedProperty() {
return selected;
}
@Override
public Picture picture() {
return picture.get();
}
@Override
public void picture(final Picture picture) {
this.picture.set(picture);
}
/**
* Returns the property for the picture
*
* @return the property for the picture
*/
ObjectProperty<Picture> pictureProperty() {
return picture;
}
}

View File

@@ -0,0 +1,36 @@
package ch.gtache.fro.practice.gui.fx;
import ch.gtache.fro.practice.gui.PracticeResultController;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import java.util.Objects;
/**
* FX implementation of {@link PracticeResultController}
*/
@Singleton
public final class FXPracticeResultController implements PracticeResultController {
private final FXPracticeResultModel model;
@FXML
private Label successNumberLabel;
@FXML
private Label failureNumberLabel;
@FXML
private Label successListLabel;
@FXML
private Label failureListLabel;
@Inject
FXPracticeResultController(final FXPracticeResultModel model) {
this.model = Objects.requireNonNull(model);
}
@Override
public FXPracticeResultModel model() {
return model;
}
}

View File

@@ -0,0 +1,18 @@
package ch.gtache.fro.practice.gui.fx;
import ch.gtache.fro.practice.gui.PracticeResultModel;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
/**
* FX implementation of {@link PracticeResultModel}
*/
@Singleton
public final class FXPracticeResultModel implements PracticeResultModel {
@Inject
FXPracticeResultModel() {
}
}

View File

@@ -0,0 +1,61 @@
package ch.gtache.fro.practice.gui.fx;
import ch.gtache.fro.practice.PracticeType;
import ch.gtache.fro.practice.gui.PracticeSettingsController;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.control.Spinner;
import javafx.scene.control.SpinnerValueFactory;
import org.controlsfx.control.PrefixSelectionComboBox;
import static java.util.Objects.requireNonNull;
/**
* FX implementation of {@link PracticeSettingsController}
*/
@Singleton
public final class FXPracticeSettingsController implements PracticeSettingsController {
private final FXPracticeSettingsModel model;
private final PracticeTypeConverter practiceTypeConverter;
@FXML
private PrefixSelectionComboBox<PracticeType> practiceTypeCombobox;
@FXML
private Label suggestionsNumberLabel;
@FXML
private Spinner<Integer> suggestionsNumberSpinner;
@Inject
FXPracticeSettingsController(final FXPracticeSettingsModel model, final PracticeTypeConverter practiceTypeConverter) {
this.model = requireNonNull(model);
this.practiceTypeConverter = requireNonNull(practiceTypeConverter);
}
@FXML
private void initialize() {
practiceTypeCombobox.setItems(model.practiceTypes());
practiceTypeCombobox.valueProperty().bindBidirectional(model.practiceTypeProperty());
practiceTypeCombobox.setConverter(practiceTypeConverter);
suggestionsNumberLabel.visibleProperty().bind(model.hasSuggestionsProperty());
suggestionsNumberSpinner.visibleProperty().bind(model.hasSuggestionsProperty());
suggestionsNumberSpinner.setValueFactory(new SpinnerValueFactory.IntegerSpinnerValueFactory(1, 8, model.suggestionsNumber()));
suggestionsNumberSpinner.getValueFactory().valueProperty().bindBidirectional(model.suggestionsNumberProperty().asObject());
}
@Override
public void startPractice() {
throw new UnsupportedOperationException();
}
@FXML
private void startPressed() {
startPractice();
}
@Override
public FXPracticeSettingsModel model() {
return model;
}
}

View File

@@ -0,0 +1,94 @@
package ch.gtache.fro.practice.gui.fx;
import ch.gtache.fro.practice.PracticeType;
import ch.gtache.fro.practice.gui.PracticeSettingsModel;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyBooleanProperty;
import javafx.beans.property.ReadOnlyBooleanWrapper;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
/**
* FX implementation of {@link PracticeSettingsModel}
*/
@Singleton
public final class FXPracticeSettingsModel implements PracticeSettingsModel {
private static final int DEFAULT_SUGGESTIONS_NUMBER = 4;
private final ObservableList<PracticeType> practiceTypes;
private final ObjectProperty<PracticeType> practiceType;
private final ReadOnlyBooleanWrapper hasSuggestions;
private final IntegerProperty suggestionsNumber;
@Inject
FXPracticeSettingsModel() {
this.practiceTypes = FXCollections.observableArrayList(PracticeType.values());
this.practiceType = new SimpleObjectProperty<>(PracticeType.PICTURE_EXACT);
this.hasSuggestions = new ReadOnlyBooleanWrapper(true);
hasSuggestions.bind(practiceType.isEqualTo(PracticeType.PICTURE_EXACT).or(practiceType.isEqualTo(PracticeType.SOUND_EXACT)));
this.suggestionsNumber = new SimpleIntegerProperty(DEFAULT_SUGGESTIONS_NUMBER);
}
@Override
public ObservableList<PracticeType> practiceTypes() {
return practiceTypes;
}
@Override
public PracticeType practiceType() {
return practiceType.get();
}
@Override
public void practiceType(final PracticeType practiceType) {
this.practiceType.set(practiceType);
}
/**
* Returns the practice type property
*
* @return The practice type property
*/
ObjectProperty<PracticeType> practiceTypeProperty() {
return practiceType;
}
@Override
public boolean hasSuggestions() {
return hasSuggestions.get();
}
/**
* Returns the has suggestions property
*
* @return The has suggestions property
*/
ReadOnlyBooleanProperty hasSuggestionsProperty() {
return hasSuggestions.getReadOnlyProperty();
}
@Override
public int suggestionsNumber() {
return suggestionsNumber.get();
}
@Override
public void suggestionsNumber(final int suggestionsNumber) {
this.suggestionsNumber.set(suggestionsNumber);
}
/**
* Returns the suggestions number property
*
* @return The suggestions number property
*/
IntegerProperty suggestionsNumberProperty() {
return suggestionsNumber;
}
}

View File

@@ -0,0 +1,57 @@
package ch.gtache.fro.practice.gui.fx;
import ch.gtache.fro.SoundType;
import ch.gtache.fro.practice.gui.PracticeSoundExactController;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.media.MediaView;
import org.controlsfx.control.PrefixSelectionComboBox;
import java.util.Objects;
/**
* FX implementation of {@link PracticeSoundExactController}
*/
@Singleton
public final class FXPracticeSoundExactController implements PracticeSoundExactController {
private final FXPracticeSoundExactModel model;
@FXML
private Button validateButton;
@FXML
private TextField inputField;
@FXML
private MediaView mediaView;
@FXML
private PrefixSelectionComboBox<SoundType> typeCombobox;
@Inject
FXPracticeSoundExactController(final FXPracticeSoundExactModel model) {
this.model = Objects.requireNonNull(model);
}
@Override
public FXPracticeSoundExactModel model() {
return model;
}
@Override
public void confirm() {
throw new UnsupportedOperationException();
}
@FXML
private void validatePressed() {
confirm();
}
@FXML
private void enterPressed() {
confirm();
}
}

View File

@@ -0,0 +1,65 @@
package ch.gtache.fro.practice.gui.fx;
import ch.gtache.fro.Sound;
import ch.gtache.fro.practice.gui.PracticeSoundExactModel;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
/**
* FX implementation of {@link PracticeSoundExactModel}
*/
@Singleton
public final class FXPracticeSoundExactModel implements PracticeSoundExactModel {
private final StringProperty guess;
private final ObjectProperty<Sound> sound;
@Inject
FXPracticeSoundExactModel() {
this.guess = new SimpleStringProperty();
this.sound = new SimpleObjectProperty<>();
}
@Override
public String guess() {
return guess.get();
}
@Override
public void guess(final String guess) {
this.guess.set(guess);
}
/**
* Returns the property for the user guess
*
* @return the property for the user guess
*/
StringProperty guessProperty() {
return guess;
}
@Override
public Sound sound() {
return sound.get();
}
@Override
public void sound(final Sound sound) {
this.sound.set(sound);
}
/**
* Returns the property for the sound
*
* @return the property for the sound
*/
ObjectProperty<Sound> soundProperty() {
return sound;
}
}

View File

@@ -0,0 +1,48 @@
package ch.gtache.fro.practice.gui.fx;
import ch.gtache.fro.practice.gui.PracticeSoundMultichoiceController;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.layout.GridPane;
import javafx.scene.media.MediaView;
import java.util.Objects;
/**
* FX implementation of {@link PracticeSoundMultichoiceController}
*/
@Singleton
public final class FXPracticeSoundMultichoiceController implements PracticeSoundMultichoiceController {
private final FXPracticeSoundMultichoiceModel model;
@FXML
private GridPane grid;
@FXML
private MediaView mediaView;
@FXML
private Button validateButton;
@Inject
FXPracticeSoundMultichoiceController(final FXPracticeSoundMultichoiceModel model) {
this.model = Objects.requireNonNull(model);
}
@Override
public FXPracticeSoundMultichoiceModel model() {
return model;
}
@Override
public void confirm() {
throw new UnsupportedOperationException();
}
@FXML
private void validatePressed() {
confirm();
}
}

View File

@@ -0,0 +1,73 @@
package ch.gtache.fro.practice.gui.fx;
import ch.gtache.fro.Bird;
import ch.gtache.fro.Sound;
import ch.gtache.fro.practice.gui.PracticeSoundMultichoiceModel;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
/**
* FX implementation of {@link PracticeSoundMultichoiceModel}
*/
@Singleton
public final class FXPracticeSoundMultichoiceModel implements PracticeSoundMultichoiceModel {
private final ObservableList<Bird> suggestions;
private final ObjectProperty<Bird> selected;
private final ObjectProperty<Sound> sound;
@Inject
FXPracticeSoundMultichoiceModel() {
this.suggestions = FXCollections.observableArrayList();
this.selected = new SimpleObjectProperty<>();
this.sound = new SimpleObjectProperty<>();
}
@Override
public ObservableList<Bird> suggestions() {
return suggestions;
}
@Override
public Bird selected() {
return selected.get();
}
@Override
public void selected(final Bird selected) {
this.selected.set(selected);
}
/**
* Returns the property for the selected bird
*
* @return the property for the selected bird
*/
ObjectProperty<Bird> selectedProperty() {
return selected;
}
@Override
public Sound sound() {
return sound.get();
}
@Override
public void sound(final Sound sound) {
this.sound.set(sound);
}
/**
* Returns the property for the sound
*
* @return the property for the sound
*/
ObjectProperty<Sound> soundProperty() {
return sound;
}
}

View File

@@ -0,0 +1,48 @@
package ch.gtache.fro.practice.gui.fx;
import ch.gtache.fro.practice.gui.PracticeSoundMultichoicePictureController;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.layout.GridPane;
import javafx.scene.media.MediaView;
import java.util.Objects;
/**
* FX implementation of {@link PracticeSoundMultichoicePictureController}
*/
@Singleton
public final class FXPracticeSoundMultichoicePictureController implements PracticeSoundMultichoicePictureController {
private final FXPracticeSoundMultichoicePictureModel model;
@FXML
private GridPane grid;
@FXML
private MediaView mediaView;
@FXML
private Button validateButton;
@Inject
FXPracticeSoundMultichoicePictureController(final FXPracticeSoundMultichoicePictureModel model) {
this.model = Objects.requireNonNull(model);
}
@Override
public FXPracticeSoundMultichoicePictureModel model() {
return model;
}
@Override
public void confirm() {
throw new UnsupportedOperationException();
}
@FXML
private void validatePressed() {
confirm();
}
}

View File

@@ -0,0 +1,73 @@
package ch.gtache.fro.practice.gui.fx;
import ch.gtache.fro.Picture;
import ch.gtache.fro.Sound;
import ch.gtache.fro.practice.gui.PracticeSoundMultichoicePictureModel;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
/**
* FX implementation of {@link PracticeSoundMultichoicePictureModel}
*/
@Singleton
public final class FXPracticeSoundMultichoicePictureModel implements PracticeSoundMultichoicePictureModel {
private final ObservableList<Picture> suggestions;
private final ObjectProperty<Picture> selected;
private final ObjectProperty<Sound> sound;
@Inject
FXPracticeSoundMultichoicePictureModel() {
this.suggestions = FXCollections.observableArrayList();
this.selected = new SimpleObjectProperty<>();
this.sound = new SimpleObjectProperty<>();
}
@Override
public ObservableList<Picture> suggestions() {
return suggestions;
}
@Override
public Picture selected() {
return selected.get();
}
@Override
public void selected(final Picture selected) {
this.selected.set(selected);
}
/**
* Returns the property for the selected picture
*
* @return the property for the selected picture
*/
ObjectProperty<Picture> selectedProperty() {
return selected;
}
@Override
public Sound sound() {
return sound.get();
}
@Override
public void sound(final Sound sound) {
this.sound.set(sound);
}
/**
* Returns the property for the sound
*
* @return the property for the sound
*/
ObjectProperty<Sound> soundProperty() {
return sound;
}
}

View File

@@ -0,0 +1,33 @@
package ch.gtache.fro.practice.gui.fx;
import ch.gtache.fro.TranslationException;
import ch.gtache.fro.practice.PracticeType;
import ch.gtache.fro.practice.PracticeTypeTranslator;
import jakarta.inject.Inject;
import javafx.util.StringConverter;
import java.util.Objects;
public class PracticeTypeConverter extends StringConverter<PracticeType> {
private final PracticeTypeTranslator translator;
@Inject
PracticeTypeConverter(final PracticeTypeTranslator translator) {
this.translator = Objects.requireNonNull(translator);
}
@Override
public String toString(final PracticeType object) {
try {
return translator.translate(object);
} catch (final TranslationException e) {
return object.name();
}
}
@Override
public PracticeType fromString(final String string) {
return null;
}
}

View File

@@ -0,0 +1,22 @@
/**
* GUI FX module for the FRO project
*/
module ch.gtache.fro.gui.fx {
requires transitive ch.gtache.fro.gui.api;
requires ch.gtache.fro.gui.core;
requires dagger;
requires jakarta.inject;
requires javafx.fxml;
requires javafx.graphics;
requires javafx.media;
requires org.controlsfx.controls;
exports ch.gtache.fro.gui.fx;
exports ch.gtache.fro.practice.gui.fx;
exports ch.gtache.fro.modules.gui.fx;
exports ch.gtache.fro.modules.practice.gui.fx;
opens ch.gtache.fro.gui.fx to javafx.fxml;
opens ch.gtache.fro.practice.gui.fx to javafx.fxml;
}

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.*?>
<?import org.controlsfx.control.CheckComboBox?>
<?import org.controlsfx.control.PrefixSelectionComboBox?>
<GridPane hgap="10.0" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" vgap="10.0"
xmlns="http://javafx.com/javafx/24.0.1" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="ch.gtache.fro.gui.fx.FXFetchController">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES"/>
<ColumnConstraints hgrow="SOMETIMES"/>
</columnConstraints>
<rowConstraints>
<RowConstraints vgrow="SOMETIMES"/>
<RowConstraints vgrow="SOMETIMES"/>
<RowConstraints vgrow="SOMETIMES"/>
</rowConstraints>
<children>
<PrefixSelectionComboBox fx:id="birdCombobox" GridPane.rowIndex="1"/>
<Button fx:id="fetchButton" mnemonicParsing="false" onAction="#fetchBirdPressed"
text="%fetch.button.fetch.label" GridPane.columnIndex="1" GridPane.rowIndex="1"/>
<Button fx:id="fetchAllButton" mnemonicParsing="false" onAction="#fetchAllPressed"
text="%fetch.button.all.label" GridPane.columnIndex="1" GridPane.rowIndex="2"/>
<Label text="%fetch.providers.label"/>
<CheckComboBox fx:id="providersCombobox" GridPane.columnIndex="1"/>
</children>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
</padding>
</GridPane>

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Tab?>
<?import javafx.scene.control.TabPane?>
<TabPane maxHeight="-Infinity" maxWidth="-Infinity" tabClosingPolicy="UNAVAILABLE" xmlns:fx="http://javafx.com/fxml/1"
xmlns="http://javafx.com/javafx/24.0.1" fx:controller="ch.gtache.fro.gui.fx.FXMainController">
<tabs>
<Tab closable="false" text="%main.tab.practice.label">
<fx:include source="../../practice/gui/fx/practiceView.fxml" fx:id="practice"/>
</Tab>
<Tab closable="false" text="%main.tab.settings.label">
<fx:include source="settingsView.fxml" fx:id="settings"/>
</Tab>
<Tab closable="false" text="%main.tab.fetch.label">
<fx:include source="fetchView.fxml" fx:id="fetch"/>
</Tab>
</tabs>
</TabPane>

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" xmlns="http://javafx.com/javafx/24.0.1"
xmlns:fx="http://javafx.com/fxml/1" fx:controller="ch.gtache.fro.gui.fx.FXSettingsController">
<children>
<TableView fx:id="table" layoutX="200.0" layoutY="68.0" AnchorPane.bottomAnchor="10.0"
AnchorPane.leftAnchor="10.0"
AnchorPane.rightAnchor="10.0" AnchorPane.topAnchor="10.0">
<columns>
<TableColumn maxWidth="1.7976931348623157E308" minWidth="-1.0" prefWidth="75.0"
text="%settings.table.column.enabled"/>
<TableColumn maxWidth="1.7976931348623157E308" minWidth="-1.0" prefWidth="75.0"
text="%settings.table.column.bird"/>
<TableColumn maxWidth="1.7976931348623157E308" minWidth="-1.0" prefWidth="75.0"
text="%settings.table.column.fetchers"/>
<TableColumn maxWidth="1.7976931348623157E308" minWidth="-1.0" prefWidth="75.0"
text="%settings.table.column.pictures"/>
<TableColumn maxWidth="1.7976931348623157E308" minWidth="-1.0" prefWidth="75.0"
text="%settings.table.column.sounds"/>
</columns>
<columnResizePolicy>
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY"/>
</columnResizePolicy>
</TableView>
</children>
</AnchorPane>

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.*?>
<?import org.controlsfx.control.PrefixSelectionComboBox?>
<?import org.controlsfx.control.textfield.CustomTextField?>
<GridPane hgap="10.0" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" vgap="10.0"
xmlns="http://javafx.com/javafx/24.0.1" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="ch.gtache.fro.practice.gui.fx.FXPracticePictureExactController">
<columnConstraints>
<ColumnConstraints hgrow="ALWAYS"/>
<ColumnConstraints hgrow="SOMETIMES"/>
</columnConstraints>
<rowConstraints>
<RowConstraints vgrow="ALWAYS"/>
<RowConstraints vgrow="SOMETIMES"/>
<RowConstraints vgrow="SOMETIMES"/>
</rowConstraints>
<children>
<ImageView fx:id="pictureView" fitHeight="300.0" fitWidth="300.0" pickOnBounds="true" preserveRatio="true"
GridPane.columnSpan="2147483647"/>
<CustomTextField fx:id="nameField" onAction="#enterPressed" GridPane.rowIndex="1"/>
<PrefixSelectionComboBox fx:id="typeCombobox" GridPane.columnIndex="1" GridPane.rowIndex="1"/>
<Button fx:id="validateButton" mnemonicParsing="false" onAction="#validatePressed"
text="%practice.picture.exact.validate.button.label" GridPane.columnSpan="2147483647"
GridPane.halignment="CENTER" GridPane.rowIndex="2"/>
</children>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
</padding>
</GridPane>

Some files were not shown because too many files have changed in this diff Show More