Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 88 additions & 0 deletions apps/supernaut-avaje-hello/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
plugins {
id 'application'
}

apply plugin: "org.openjfx.javafxplugin"
apply plugin: "org.beryx.jlink"

def appName = 'SFX Avaje Hello'
version = helloAppVersion

application {
mainModule = 'app.supernaut.sample.avaje.hello'
mainClass = 'app.supernaut.sample.avaje.hello.HelloApp'
}

dependencies {
implementation project (':modules:app.supernaut.fx')
implementation project (':modules:app.supernaut.fx.avaje')
implementation "io.avaje:avaje-inject:${avajeInjectVersion}"
implementation "jakarta.inject:jakarta.inject-api:${jakartaInjectVersion}"
implementation "org.slf4j:slf4j-api:${slf4jVersion}"

annotationProcessor "io.avaje:avaje-inject-generator:${avajeInjectVersion}"

runtimeOnly "org.slf4j:slf4j-jdk14:${slf4jVersion}"
}

tasks.withType(Javadoc).configureEach { javadoc ->
dependsOn tasks.withType(JavaCompile) // ensure annotation processing / compilation happens first

// Include generated sources in Javadoc
source += fileTree("$buildDir/generated/sources/annotationProcessor/java/main")

// Add generated sources to classpath (important for symbols)
classpath += files("$buildDir/generated/sources/annotationProcessor/java/main")
}

javafx {
version = javaFxVersion
modules = ['javafx.graphics', 'javafx.controls', 'javafx.fxml']
}

run {
}

test {
}

def os = org.gradle.internal.os.OperatingSystem.current()

jlink {
addExtraDependencies("javafx")
options = ['--strip-debug', '--compress', '2', '--no-header-files', '--no-man-pages', '--add-modules', 'org.slf4j.jul']
launcher {
name = appName
jvmArgs = []
}
jpackage {
// See https://badass-jlink-plugin.beryx.org/releases/latest/#_jpackage for
// where the plugin's jpackage task finds the path to the jpackage tool by default
skipInstaller = false

// Which installers to make
if (os.linux) {
installerType = null // default is ['rpm', 'deb']
} else if (os.macOsX) {
installerType = 'dmg' // default is ['pkg', 'dmg']
} else if (os.windows) {
installerType = 'exe' // default is ['exe', 'msi']
}

// Massage version string to be compatible with jpackage installers
// for the current OS platform
def appVersionForJpackage = normalizeAppVersion(version)

imageOptions = ["--verbose", "--app-version", appVersionForJpackage]
installerOptions = ["--app-version", appVersionForJpackage]
if (os.macOsX) {
imageOptions += [ '--resource-dir', "${projectDir}/src/macos/resource-dir" ]
if (rootProject.ext.signJPackageImages) {
logger.warn "Setting --mac-sign in jpackage imageOptions"
imageOptions += [ '--mac-sign' ]
}
} else if (os.windows) {
installerOptions += ['--win-dir-chooser', '--win-menu', '--win-shortcut']
}
}
}
36 changes: 36 additions & 0 deletions apps/supernaut-avaje-hello/src/macos/resource-dir/Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>LSMinimumSystemVersion</key>
<string>10.14</string>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleAllowMixedLocalizations</key>
<true/>
<key>CFBundleExecutable</key>
<string>DEPLOY_LAUNCHER_NAME</string>
<key>CFBundleIconFile</key>
<string>DEPLOY_ICON_FILE</string>
<key>CFBundleIdentifier</key>
<string>DEPLOY_BUNDLE_IDENTIFIER</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>DEPLOY_BUNDLE_NAME</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>DEPLOY_BUNDLE_SHORT_VERSION</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>LSApplicationCategoryType</key>
<string>DEPLOY_BUNDLE_CATEGORY</string>
<key>CFBundleVersion</key>
<string>DEPLOY_BUNDLE_CFBUNDLE_VERSION</string>
<key>NSHumanReadableCopyright</key>
<string>DEPLOY_BUNDLE_COPYRIGHT</string>
<key>NSHighResolutionCapable</key>
<string>true</string>
</dict>
</plist>
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright 2019-2022 M. Sean Gilligan.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package app.supernaut.sample.avaje.hello;

import jakarta.inject.Named;
import jakarta.inject.Singleton;

import java.time.format.DateTimeFormatter;

/**
* A simple dependency-injected service
*/
@Singleton
public class GreetingService {
private final String planetName;

/**
* Constructor
* @param planetName Name of the planet to greet. Injected.
*/
public GreetingService(@Named("PLANETNAME") String planetName) {
this.planetName = planetName;
}

/**
* Return the name of the planet being greeted
*
* @return The name of the planet being greeted
*/
public String getPlanetName() {
return this.planetName;
}

/**
* Return a greeting
*
* @return The greeting
*/
public String greeting() {
String time = java.time.ZonedDateTime.now().format(DateTimeFormatter.ISO_LOCAL_TIME);
return "Hello " + planetName + "! The time is: " + time;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/*
* Copyright 2019-2022 M. Sean Gilligan.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package app.supernaut.sample.avaje.hello;

import app.supernaut.fx.ApplicationDelegate;
import app.supernaut.fx.FxLauncherProvider;
import app.supernaut.fx.avaje.AvajeBeanFactory;
import app.supernaut.fx.avaje.fxml.AvajeFxmlLoaderFactory;
import app.supernaut.fx.fxml.FxmlLoaderFactory;
import app.supernaut.logging.JavaLoggingSupport;
import io.avaje.inject.Bean;
import io.avaje.inject.Component;
import io.avaje.inject.Factory;
import jakarta.inject.Named;
import jakarta.inject.Singleton;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.URL;

/**
* A simple Supernaut.FX App implementing {@link ApplicationDelegate}.
*
* If is also annotated to be Avaje {@link Factory}. This allows it to
* create the {@link Named} {@code String} instance and to specify inclusion
* of a {@code Bean} that is defined in a library, which will enable the Avaje
* annotation processor to include the generated code for that {@code Bean}.
*
* (It might be nice to abstract this "factory" capability somehow so apps don't need to
* be directly dependent on Avaje for something so simple, but at this point using the @Factory
* annotation seems to be the simplest way to do things.)
*/


@Singleton
@Factory
@Component.Import({AvajeFxmlLoaderFactory.class, AvajeBeanFactory.class})
public class HelloApp implements ApplicationDelegate {
private static final Logger log = LoggerFactory.getLogger(HelloApp.class);
private final FxmlLoaderFactory loaderFactory;


/**
* Main method that calls launcher
* @param args command-line args
*/
static void main(String[] args) {
JavaLoggingSupport.configure(HelloApp.class, "app.supernaut.sample.avaje.hello");
FxLauncherProvider.find().launcher().launch(args);
}

/**
* Constructor
* @param loaderFactory injected FXMLLoaderFactory
*/
public HelloApp(FxmlLoaderFactory loaderFactory) {
log.info("Constructing Hello");
this.loaderFactory = loaderFactory;
}

/**
* {@inheritDoc}
*/
@Override
public void init() {
log.info("Initializing Hello");
}

/**
* {@inheritDoc}
*/
@Override
public void start(Stage primaryStage) throws IOException {
log.info("Starting Hello");
FXMLLoader loader = loaderFactory.get(getFXMLUrl("MainWindow.fxml"));
log.debug("primaryStage root FXML: {}", loader.getLocation());
Parent root = loader.load();

primaryStage.setScene(new Scene(root, 300, 250));
primaryStage.setTitle("SFX Avaje Hello");
primaryStage.show();
}

/**
* @return the planet name to great
*/
@Bean
@Named("PLANETNAME")
public String getPlanetName() {
return "Mars";
}

private URL getFXMLUrl(String fileName) {
return HelloApp.class.getResource(fileName);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
* Copyright 2019-2022 M. Sean Gilligan.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package app.supernaut.sample.avaje.hello;

import app.supernaut.services.BrowserService;
import jakarta.inject.Provider;
import jakarta.inject.Singleton;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.Hyperlink;
import javafx.scene.control.Label;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.URI;

/**
* Main Window Controller
* Uses JSR 330 dependency injection annotations to tell Supernaut.FX/Avaje
* what to inject in its constructor. @FXML annotations tell the FXMLLoader where
* to inject objects from the FXML file.
*/
@Singleton
public class MainWindowController {
private static final Logger log = LoggerFactory.getLogger(MainWindowController.class);
private static final URI githubRepoUri = URI.create("https://github.com/SupernautApp/SupernautFX");
private final Provider<BrowserService> browserService;
private final GreetingService greetingService;

@FXML
private Hyperlink githubLink;

@FXML
private Label message;

@FXML
private Button btn;

/**
* Constructor
* @param browserService injected browser service for launching browser windows
* @param greetingService injected greeting service for getting the planet name
*/
public MainWindowController(Provider<BrowserService> browserService, GreetingService greetingService) {
this.greetingService = greetingService;
this.browserService = browserService;
}

/**
* Called by FXMLLoader to initialize the controller.
*/
@FXML
public void initialize() {
var planet = greetingService.getPlanetName();
btn.setText("Say Hello to " + planet);

}

/**
* Button action
* @param event the event
*/
@FXML
public void buttonAction(ActionEvent event) {
var greeting = greetingService.greeting();
log.info("buttonAction: greeting: {}", greeting);
message.setText(greetingService.greeting());
}

/**
* Link action
* @param actionEvent the event
*/
@FXML
public void linkAction(ActionEvent actionEvent) {
browserService.get().showDocument(githubRepoUri);
}
}
Loading
Loading