Add notification subsystem

This commit is contained in:
JeremyStar™ 2024-10-15 03:30:55 +02:00
parent 1e6fa79716
commit bed5811b70
Signed by: JeremyStarTM
GPG key ID: E366BAEF67E4704D
17 changed files with 942 additions and 0 deletions

View file

@ -30,6 +30,7 @@ tasks.register("javadocAll", Javadoc) {
":base",
":ansi",
":slf4j-compat",
":notification",
":windowing",
":windowing:glfw",
]

2
notification/README.md Normal file
View file

@ -0,0 +1,2 @@
# The `slf4j-compat` subsystem
This subsystems provides an extensive notification API. The only thing missing in the sandwich is your rendering implementation.

110
notification/build.gradle Normal file
View file

@ -0,0 +1,110 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
// Plugins
plugins {
id("java")
id("io.freefair.lombok") version("${pluginLombok}")
id("maven-publish")
}
// Dependencies
dependencies {
// -> Runtime <-
// Lombok
compileOnly("org.projectlombok:lombok:${dependencyLombok}")
annotationProcessor("org.projectlombok:lombok:${dependencyLombok}")
// JetBrains Annotations
compileOnly("org.jetbrains:annotations:${dependencyJetbrainsAnnotations}")
// -> Project <-
implementation(project(":base"))
}
// Fix delombok task
delombok.doFirst {
File target = file("${project.projectDir}/src/main/module-info.java")
File source = file("${project.projectDir}/src/main/java/module-info.java")
target.delete()
source.renameTo(target)
}
delombok.doLast {
File target = file("${project.projectDir}/src/main/java/module-info.java")
File source = file("${project.projectDir}/src/main/module-info.java")
target.delete()
source.renameTo(target)
}
// Javadoc configuration
javadoc {
outputs.upToDateWhen { false } // Force task execution
dependsOn(delombok) // Make sure the source is delomboked first
javadoc {
setClasspath(files(project.sourceSets.main.compileClasspath)) // Include dependencies
options {
if (new File(projectDir, "src/main/javadoc/theme.css").exists())
stylesheetFile = new File(projectDir, "src/main/javadoc/theme.css") // Theming is cool :3
setMemberLevel(JavadocMemberLevel.PUBLIC) // Only display public stuff
setOverview("src/main/javadoc/overview.html") // We want a custom overview page to greet the visitor
setLocale("en_US") //
addStringOption("Xwerror", "-quiet") // Fail build on warning
setJFlags([
"-Duser.language=en_US" // See above
])
}
}
}
// Include javadoc and source jar during publishing
java {
withJavadocJar()
withSourcesJar()
}
// Build publishing configuration
// Note: You can safely ignore any errors or warnings thrown by your IDE here
publishing {
repositories {
maven {
name = "staropensource"
url = uri("https://mvn.staropensource.de/sosengine")
credentials(org.gradle.api.credentials.PasswordCredentials)
authentication {
//noinspection GroovyAssignabilityCheck
basic (BasicAuthentication)
}
}
}
publications {
//noinspection GroovyAssignabilityCheck
maven (MavenPublication) {
groupId = group
artifactId = project.getName()
version = version
//noinspection GroovyAssignabilityCheck
from components.java
}
}
}

1
notification/gradle Symbolic link
View file

@ -0,0 +1 @@
../gradle

1
notification/gradlew vendored Symbolic link
View file

@ -0,0 +1 @@
../gradlew

1
notification/gradlew.bat vendored Symbolic link
View file

@ -0,0 +1 @@
../gradlew.bat

View file

@ -0,0 +1,146 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.notification;
import de.staropensource.engine.base.type.immutable.ImmutableHashMap;
import de.staropensource.engine.notification.type.Notification;
import de.staropensource.engine.notification.type.NotificationState;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Map;
/**
* Manages and handles {@link Notification}s.
*
* @since v1-alpha6
*/
public final class NotificationManager {
/**
* Contains a list of all notifications and their states.
*
* @since v1-alpha6
*/
private static final @NotNull Map<@NotNull Notification, @NotNull NotificationState> notifications = new HashMap<>();
/**
* Creates and initializes an instance of this class.
*
* @since v1-alpha6
*/
private NotificationManager() {}
/**
* Returns an {@link ImmutableHashMap} containing all
* registered notifications and their current states.
*
* @return map of registered notifications
* @since v1-alpha6
*/
public static @NotNull Map<@NotNull Notification, @NotNull NotificationState> getNotifications() {
return new ImmutableHashMap<>(notifications);
}
/**
* Returns whether the specified notification
* is registered and if so, which state
* it is in.
*
* @param notification notification to check
* @return state or {@code null} if unregistered
* @since v1-alpha6
*/
public static @Nullable NotificationState getState(@NotNull Notification notification) {
if (notifications.containsKey(notification))
return notifications.get(notification);
return null;
}
/**
* Fires the specified notification.
* Will simply set it's state to
* {@link NotificationState#SHOWN}
* if it is already registered.
*
* @param notification notification to fire
* @since v1-alpha6
*/
public static void fire(@NotNull Notification notification) {
updateNotification(notification, NotificationState.SHOWN, false);
}
/**
* Hides the specified notification.
* Does nothing if it isn't shown.
*
* @param notification notification to update
* @since v1-alpha6
*/
public static void hide(@NotNull Notification notification) {
if (notifications.getOrDefault(notification, NotificationState.HIDDEN) == NotificationState.SHOWN)
updateNotification(notification, NotificationState.HIDDEN, false);
}
/**
* Dismisses the specified notification.
* Does nothing if it is already dismissed.
* <p>
* Note: Dismissing a notification does not
* necessarily mean it removes it. Depending
* on the {@link Notification#}
*
* @param notification notification to update
* @since v1-alpha6
*/
public static void dismiss(@NotNull Notification notification) {
if (notifications.getOrDefault(notification, NotificationState.HIDDEN) == NotificationState.SHOWN) {
updateNotification(notification, NotificationState.DISMISSED, false);
switch (notification.getDismissalAction()) {
case UNREGISTER -> updateNotification(notification, notifications.get(notification), true);
case EXECUTE -> notification.dismiss();
case EXECUTE_UNREGISTER -> {
notification.dismiss();
updateNotification(notification, notifications.get(notification), true);
}
}
}
}
/**
* Adds or updates the specified notification
* in the {@link #notifications} map.
*
* @param notification notification to add or update
* @param state state to set
* @since v1-alpha6
*/
private static synchronized void updateNotification(@NotNull Notification notification, @NotNull NotificationState state, boolean removeOnly) {
if (removeOnly)
notifications.remove(notification);
else
if (notifications.containsKey(notification))
notifications.replace(notification, state);
else
notifications.put(notification, state);
}
}

View file

@ -0,0 +1,83 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.notification;
import de.staropensource.engine.base.annotation.EngineSubsystem;
import de.staropensource.engine.base.implementable.SubsystemClass;
import de.staropensource.engine.base.implementation.versioning.StarOpenSourceVersioningSystem;
import de.staropensource.engine.base.type.DependencyVector;
import de.staropensource.engine.base.utility.information.EngineInformation;
import lombok.Getter;
import org.jetbrains.annotations.NotNull;
/**
* Main class of the {@code notification} subsystem.
*
* @since v1-alpha6
*/
@EngineSubsystem
@SuppressWarnings({ "JavadocDeclaration" })
public final class NotificationSubsystem extends SubsystemClass {
/**
* Contains the class instance.
*
* @since v1-alpha6
* -- GETTER --
* Returns the class instance.
*
* @return class instance unless the subsystem is uninitialized
* @since v1-alpha6
*/
@Getter
private static NotificationSubsystem instance = null;
/**
* Initializes this subsystem.
*
* @since v1-alpha6
*/
public NotificationSubsystem() {
// Check if subsystem has already initialized
if (instance == null)
instance = this;
else
logger.crash("Only one instance of this class is allowed, use getInstance() instead of creating a new instance");
}
/** {@inheritDoc} */
@Override
public @NotNull String getName() {
return "notification";
}
/** {@inheritDoc} */
@Override
public void initializeSubsystem() {}
/** {@inheritDoc} */
@Override
public @NotNull DependencyVector getDependencyVector() {
return new DependencyVector.Builder()
.setIdentifier("notification")
.setVersioningSystem(StarOpenSourceVersioningSystem.class)
.setVersion(EngineInformation.getVersioningString())
.build();
}
}

View file

@ -0,0 +1,327 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.notification.type;
import de.staropensource.engine.base.type.Color;
import de.staropensource.engine.notification.NotificationManager;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.Range;
import java.util.LinkedHashMap;
/**
* A notification!
*
* @since v1-alpha6
*/
@Getter
@Setter
@SuppressWarnings({ "JavadocDeclaration" })
public class Notification {
/**
* Contains the class from where
* this notification was emitted.
*
* @since v1-alpha6
* -- GETTER --
* Returns the class from where
* this notification was emitted.
*
* @return origin
* @since v1-alpha6
*/
@Setter(value = AccessLevel.NONE)
private final @NotNull Class<?> origin;
/**
* Contains what to do when the notification is dismissed.
*
* @since v1-alpha6
* -- GETTER --
* Returns what to do when the notification is dismissed.
*
* @return dismissal action
* @since v1-alpha6
* -- SETTER --
* Sets what to do when the notification is dismissed.
*
* @param dismissalAction new dismissal action
* @since v1-alpha6
*/
private @NotNull NotificationDismissalAction dismissalAction = NotificationDismissalAction.UNREGISTER;
/**
* Contains the priority of this notification.
*
* @since v1-alpha6
* -- GETTER --
* Returns the priority of this notification.
*
* @return priority
* @since v1-alpha6
* -- SETTER --
* Sets the priority of this notification.
*
* @param priority new priority
* @since v1-alpha6
*/
private @NotNull NotificationPriority priority = NotificationPriority.DEFAULT;
/**
* Contains the type of this notification.
*
* @since v1-alpha6
* -- GETTER --
* Returns the type of this notification.
*
* @return type
* @since v1-alpha6
* -- SETTER --
* Sets the type of this notification.
*
* @param type new type
* @since v1-alpha6
*/
private @NotNull NotificationType type = NotificationType.INFORMATIONAL;
/**
* Contains the title of this notification.
*
* @since v1-alpha6
* -- GETTER --
* Returns the title of this notification.
*
* @return title
* @since v1-alpha6
* -- SETTER --
* Sets the title of this notification.
*
* @param title new title
* @since v1-alpha6
*/
private @NotNull String title;
/**
* Contains the content of this notification.
*
* @since v1-alpha6
* -- GETTER --
* Returns the content of this notification.
*
* @return content
* @since v1-alpha6
* -- SETTER --
* Sets the content of this notification.
*
* @param message new content
* @since v1-alpha6
*/
private @Nullable String content = null;
/**
* Contains the color of this notification.
*
* @since v1-alpha6
* -- GETTER --
* Returns the theme color of this notification.
*
* @return theme color
* @since v1-alpha6
* -- SETTER --
* Sets the theme color of this notification.
*
* @param color new theme color
* @since v1-alpha6
*/
private @Nullable Color color = null;
/**
* Contains whether this notification shall be closable or not.
*
* @since v1-alpha6
* -- GETTER --
* Returns whether this notification shall be closable or not.
*
* @return closable flag state
* @since v1-alpha6
* -- SETTER --
* Sets whether this notification shall be closable or not.
*
* @param closable new closable flag state
* @since v1-alpha6
*/
private boolean closable = true;
/**
* Contains whether the notification has a progress bar attached,
* and if so, to which percentage it is filled.
* <p>
* If it contains {@code -1} then this notification does not have
* a progress bar. If it doesn't, it must contain a percentage
* between {@code 0} and {@code 100}.
*
* @since v1-alpha6
* -- GETTER --
* Returns whether the notification has a progress bar attached,
* and if so, to which percentage it is filled.
* <p>
* If it contains {@code -1} then this notification does not have
* a progress bar. If it doesn't, it must contain a percentage
* between {@code 0} and {@code 100}.
*
* @return progress bar filled in %, or {@code -1} if disabled
* @since v1-alpha6
* -- SETTER --
* Sets whether the notification has a progress bar attached,
* and if so, to which percentage it is filled.
* <p>
* If it contains {@code -1} then this notification does not have
* a progress bar. If it doesn't, it must contain a percentage
* between {@code 0} and {@code 100}.
*
* @param bar new % value to which the progress bar is filled, or {@code -1} to mark it as disabled
* @since v1-alpha6
*/
private @Range(from = -1, to = 100) int bar = -1;
/**
* Contains the {@link Runnable} which shall be executed
* when the notification is clicked/interacted with.
*
* @since v1-alpha6
* -- GETTER --
* Contains the {@link Runnable} which shall be executed
* when the notification is clicked/interacted with.
*
* @return {@link Runnable} executed if clicked
* @since v1-alpha6
* -- SETTER --
* Sets the {@link Runnable} which shall be executed
* when the notification is clicked/interacted with.
*
* @param clickCode {@link Runnable} executed if clicked
* @since v1-alpha6
*/
private @Nullable Runnable clickCode = null;
/**
* Contains all buttons and their associated
* {@link Runnable}s on this notification.
*
* @since v1-alpha6
* -- GETTER --
* Returns all buttons and their associated
* {@link Runnable}s on this notification.
*
* @return linked button map
* @since v1-alpha6
*/
private @NotNull LinkedHashMap<@NotNull String, @NotNull Runnable> buttons = new LinkedHashMap<>();
/**
* Creates and initializes an instance of this class.
*
* @since v1-alpha6
*/
public Notification(@NotNull Class<?> origin, @NotNull String title) {
this.origin = origin;
this.title = title;
}
/**
* Sets the percentage of which the progress bar is filled.
* This method calculates the percentage between two values,
* saving you the simple math.
*
* @param min minimum value
* @param max maximum value
* @param value value
* @since v1-alpha6
*/
public void setBar(int min, int max, int value) {
if (min >= value)
bar = 0;
else
bar = max / value;
if (bar < 0)
bar = 0;
else if (bar > 100)
bar = 100;
}
/**
* Sets the percentage of which the progress bar is filled.
* This method calculates the percentage between two values,
* saving you the simple math.
* <p>
* Note: This method assumes the minimum value is {@code 0}.
* If you want control over this, see {@link #setBar(int, int, int)}.
*
* @param max maximum value
* @param value value
* @since v1-alpha6
*/
public void setBar(int max, int value) {
setBar(0, max, value);
}
/**
* Returns the state of this notification.
*
* @return state or {@code null} if not registered
* @since v1-alpha6
*/
public final @Nullable NotificationState getState() {
return NotificationManager.getState(this);
}
/**
* Fires this notification.
* <p>
* If this notification has just been created,
* invoking this method will register it and
* make it work. If this method has been called
* already however, it will simply display
* the notification again, even if hidden or
* dismissed.
*
* @since v1-alpha6
*/
public final void fire() {
NotificationManager.fire(this);
}
/**
* Dismisses this notification.
* <p>
* This method will only be executed if
* {@link #dismissalAction} is either set
* to {@link NotificationDismissalAction#EXECUTE}
* or {@link NotificationDismissalAction#EXECUTE_UNREGISTER}.
*
* @since v1-alpha6
*/
public void dismiss() {}
}

View file

@ -0,0 +1,69 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.notification.type;
/**
* Used for representing how a notification
* should act if it is dismissed.
*
* @since v1-alpha6
*/
public enum NotificationDismissalAction {
/**
* Makes the notification do nothing.
* It will simply sit there in loneliness,
* waiting to be interacted with.
* <p>
* <b>Not recommended as it will cause
* memory leaks if not cleaned up manually.</b>
*
* @since v1-alpha6
*/
NOTHING,
/**
* Simply unregisters the notification,
* causing it to disappear. Most likely
* the option you want to choose.
*
* @since v1-alpha6
*/
UNREGISTER,
/**
* Executes the {@link Notification#dismiss()}
* method on the notification.
* <p>
* <b>Not recommended as it will cause
* memory leaks if not cleaned up manually.</b>
*
* @since v1-alpha6
*/
EXECUTE,
/**
* Executes the {@link Notification#dismiss()}
* method on the notification and
* unregisters it afterwards.
*
* @since v1-alpha6
*/
EXECUTE_UNREGISTER,
}

View file

@ -0,0 +1,62 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.notification.type;
/**
* Determines a notification's importance.
*
* @since v1-alpha6
*/
public enum NotificationPriority {
/**
* A very important notification.
*
* @since v1-alpha6
*/
VERY_IMPORTANT,
/**
* An important notification.
*
* @since v1-alpha6
*/
IMPORTANT,
/**
* The standard priority.
*
* @since v1-alpha6
*/
DEFAULT,
/**
* An unimportant notification.
*
* @since v1-alpha6
*/
UNIMPORTANT,
/**
* A very unimportant notification.
*
* @since v1-alpha6
*/
VERY_UNIMPORTANT,
}

View file

@ -0,0 +1,48 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.notification.type;
/**
* Used for representing the state of an notification.
*
* @since v1-alpha6
*/
public enum NotificationState {
/**
* A shown notification.
*
* @since v1-alpha6
*/
SHOWN,
/**
* A hidden notification.
*
* @since v1-alpha6
*/
HIDDEN,
/**
* A dismissed notification.
*
* @since v1-alpha6
*/
DISMISSED,
}

View file

@ -0,0 +1,48 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.notification.type;
/**
* Determines the type of a notification.
*
* @since v1-alpha6
*/
public enum NotificationType {
/**
* Marks a notification as an error notification.
*
* @since v1-alpha6
*/
ERROR,
/**
* Marks a notification as a warning notification.
*
* @since v1-alpha6
*/
WARNING,
/**
* Marks a notification as an informational notification.
*
* @since v1-alpha6
*/
INFORMATIONAL,
}

View file

@ -0,0 +1,19 @@
/**
* The {@code notification} subsystem, which
* provides an extensive notification API.
*
* @since v1-alpha6
*/
module sosengine.notification {
// Dependencies
// -> Engine
requires sosengine.base;
// API access
exports de.staropensource.engine.notification;
exports de.staropensource.engine.notification.type;
// Reflection access
opens de.staropensource.engine.notification;
opens de.staropensource.engine.notification.type;
}

View file

@ -0,0 +1,22 @@
<!--
~ STAROPENSOURCE ENGINE SOURCE FILE
~ Copyright (c) 2024 The StarOpenSource Engine Authors
~ Licensed under the GNU Affero General Public License v3
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU Affero General Public License as
~ published by the Free Software Foundation, either version 3 of the
~ License, or (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU Affero General Public License for more details.
~
~ You should have received a copy of the GNU Affero General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<body>
<p>Welcome to the sos!engine API documentation!<br/>
You are currently in the documentation for the <b>notification</b> subsystem, which provides an extensive notification API.</p>
</body>

View file

@ -0,0 +1 @@
../../../../src/main/javadoc/theme.css

View file

@ -23,6 +23,7 @@ include("base")
include("testing")
include("ansi")
include("slf4j-compat")
include("notification")
include("windowing")
include("windowing:glfw")
include("testapp")