{"id":16175686,"url":"https://github.com/osiris-team/desku","last_synced_at":"2025-03-16T10:31:33.987Z","repository":{"id":65628773,"uuid":"594401353","full_name":"Osiris-Team/Desku","owner":"Osiris-Team","description":"Java Framework for Web, Desktop and Mobile Apps. Supports Android, iOS, Windows, Linux, MacOS.","archived":false,"fork":false,"pushed_at":"2024-09-02T16:25:05.000Z","size":3298,"stargazers_count":18,"open_issues_count":8,"forks_count":1,"subscribers_count":3,"default_branch":"main","last_synced_at":"2024-10-11T04:45:23.913Z","etag":null,"topics":["chromium","desktop-app","framework","java-desktop"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Osiris-Team.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-01-28T12:48:06.000Z","updated_at":"2024-09-27T15:42:32.000Z","dependencies_parsed_at":"2024-08-24T12:31:25.725Z","dependency_job_id":"206c0bef-689c-45ee-8b4f-7d0ba9529830","html_url":"https://github.com/Osiris-Team/Desku","commit_stats":null,"previous_names":[],"tags_count":88,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Osiris-Team%2FDesku","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Osiris-Team%2FDesku/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Osiris-Team%2FDesku/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Osiris-Team%2FDesku/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Osiris-Team","download_url":"https://codeload.github.com/Osiris-Team/Desku/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":221662729,"owners_count":16859736,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["chromium","desktop-app","framework","java-desktop"],"created_at":"2024-10-10T04:45:31.536Z","updated_at":"2025-03-16T10:31:33.977Z","avatar_url":"https://github.com/Osiris-Team.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Desku [![](https://jitpack.io/v/Osiris-Team/Desku.svg)](https://jitpack.io/#Osiris-Team/Desku)\nJava UI Framework for developing low-code, data centric Web, Desktop and Mobile Applications in one codebase. Using Web-Tech (JS/HTML/CSS) under the hood.\n[Click here for Maven/Gradle/Sbt/Leinigen instructions](https://jitpack.io/#Osiris-Team/Desku/LATEST) (Java 11 or higher required).\n\n## Who is it for?\nMainly backend developers that want to code their frontend/GUI directly in Java in a low-code, data centric, compile safe, fast and pain-less way.\nIn addition, it is also highly beginner-friendly, making it accessible to everyone that is new to coding due to its simplicity.\n\n## What does it look like?\n```java\nvertical().add(text(\"Hello World!\"))\n```\n\u003cdetails\u003e\n\u003csummary\u003eMinimal example\u003c/summary\u003e\n\n```java\nimport com.osiris.desku.App;\nimport static com.osiris.desku.Statics;\npublic class Main {\n    public static void main(String[] args) throws Exception {\n        App.uis = new DesktopUIManager(); // Not needed when using the Desku-Starter-App\n        App.name = \"My-App\";\n        App.init();\n        App.uis.create(() -\u003e {\n            return vertical().add(text(\"Hello World!\")); \n        });\n    }\n}\n```\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003eCommented minimal example\u003c/summary\u003e\n\n```java\nimport com.osiris.desku.App;\nimport static com.osiris.desku.Statics; // Low-code Java UI via static methods\n\npublic class Main {\n    public static void main(String[] args) throws Exception {\n        \n        // Setup app details and init.\n        App.uis = new DesktopUIManager(); // Not needed when using the Desku-Starter-App\n        App.name = \"My-App\";\n        App.init(); \n\n        // Create routes.\n        // This is only for demonstration. \n        // Normally you'd create a new class and extend Route instead.\n        // In the \"3 lines example\" a new random Route is created in App.uis.create().\n        // All routes names/paths must start with a \"/\".\n        Route home = new MRoute(\"/\", () -\u003e { \n            return vertical().add(text(\"Hello World!\")); // Low-code Java UI via static methods\n        });\n\n        // Create and show the window, with the content\n        // loaded by the provided route, in this case \"home\".\n        // The content is a tree of components which gets \"translated\" into HTML\n        // and then displayed by the users default webview.\n        App.uis.create(home);\n    }\n}\n```\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003eScreenshots\u003c/summary\u003e\n\nAppTest home page (24.08.2023), which includes all default components:\n![img.png](/docs/AppTestPage.png)\n\u003c/details\u003e\n\n## How to get started?\n#### Use the [Desku-Starter-App](https://github.com/Osiris-Team/Desku-Starter-App) as starting point since it also supports Android and iOS, everything is setup correctly and scripts for generating binaries + installers are included.\n#### Usage examples for all default components can be found [here](https://github.com/Osiris-Team/Desku/blob/main/src/test/java/com/osiris/desku/simple_app/home/Home.java) (CTRL + F to search by name).\n#### Install the [Desku-Intellij-Plugin](https://github.com/Osiris-Team/Desku-Intellij-Plugin) to make development even more hassle-free and generate the little boilerplate there is.\n\n## License\nDesku is released under a modified MIT license (see full license for details):\n\u003e If your project generates more than 1000€ a month in revenue and uses this software, you are required to pay a royalty fee to Osiris Team.\n\u003e The royalty fee is 5% of gross revenue (i.e., the total revenue generated by your project).\n\u003e You must make a monthly payment to osiris_support@pm.me over PayPal.\n\u003e Other ways of payment are possible, contact the above email for further information.\n\n## Features\n- Easily develop desktop and mobile apps in one codebase!\n- Full Java [FlexBox](https://css-tricks.com/snippets/css/a-guide-to-flexbox/) \nbindings, thus making simple/complex layout creation faster and easier than ever.\n- You decide! Code your UI in Java or directly in HTML/CSS, or both!\n- Focus on method-chaining and low-code (check out the Statics class).\n- Update the UI asynchronously hassle-free.\n- Contains cross-platform desktop WebView implementation already. \nAndroid and iOS implementations are provided in the starter repo.\n- Uses [Bootstrap v5.3.0](https://getbootstrap.com/docs/5.3/components) for styling and [Jsoup](https://jsoup.org/) for handling the HTML of components.\n- Core philosophy: Developer convenience comes first, performance (CPU/RAM usage) comes second.\n- The Component class is the heart of Desku and represents a reusable data-centric UI component.\n  Meaning a Component has always a value which is tries to represent in the UI\n\n## Extensions\nA list of all available extensions can be found [here](https://github.com/topics/desku-extension?o=desc\u0026s=updated).\nIt can be a single component or a complete suite of multiple components, either\nway, its pretty easy to create a Desku-Extension:\n1. **Start with the [Desku-Starter-Extension](https://github.com/Osiris-Team/Desku-Starter-Extension) template.**\n2. Publish your repo on GitHub with the #desku-extension tag/topic (also mention the Desku version your extension supports / was built with).\n3. Create a release and use JitPack or Maven to host the files.\n\n## State\n\n💥 Do NOT use in production projects! We have a ton of features implemented but with very little testing.\n\nAt this early state if you find something missing contribute directly instead of creating an extension.\n\nTodo:\n- Native notifications and in-app overlay notifications.\n- Default components suit similar to https://vaadin.com/docs/latest/components.\n- Serializable UI, to restore state (on ice right now, since it seems\nto be more complicated than expected)\n\n## Contributing\nContributions are welcome! Especially HTML5 component integrations, aka\nporting an HTML5 component to a Java Desku component.\n\nWhen building remember to include this specific test, to also update\nthe `Statics` class.\n```\n./gradlew build :test --tests \"com.osiris.desku.GenerateStatics\"\n```\n\n- Try to code in the existing style.\n- 99% of the variables should be public, avoid getters/setters.\n- Keep it low-code/simple for the developers using your new feature.\n\n\n## Documentation\n\nCopy and send [this](https://raw.githubusercontent.com/Osiris-Team/Desku/main/README.md) \nto [ChatGPT](https://chat.openai.com/) and ask it questions to get quick support.\n\n#### User interface\n\n\u003cdiv\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eHow to change the theme?\u003c/summary\u003e\n\nThe theme can be changed quite easily by setting\nthe `App.theme` variable. \u003cbr\u003e\nCreate your own themes by extending the `Theme` class\nwhere you modify existing attributes or add new ones\nand update the `App.theme` variable.\n\u003c/details\u003e\n\n\n\n\u003cdetails\u003e\n\u003csummary\u003eHow do I add my own JavaScript event listener?\u003c/summary\u003e\n\nProbably the best and easiest way to show is with an example.\nThe code below shows the JavaScript click event being implemented:\n\n```java\npublic class ClickEvent extends JavaScriptEvent {\n    public final boolean isTrusted;\n    public final int screenX, screenY;\n\n    public ClickEvent(String rawJSMessage, Component\u003c?\u003e comp) {\n        super(rawJSMessage, comp);\n        this.isTrusted = jsMessage.get(\"isTrusted\").getAsBoolean();\n        this.screenX = jsMessage.get(\"screenX\").getAsInt();\n        this.screenY = jsMessage.get(\"screenY\").getAsInt();\n    }\n}\n\npublic class MyComp extends Component\u003cMyComp\u003e {\n    /**\n     * Do not add actions via this variable, use {@link #onClick(Consumer)} instead.\n     */\n    public final Event\u003cClickEvent\u003e _onClick = new Event\u003c\u003e();\n\n    public MyComp() {\n        super(\"my-comp\");\n    }\n\n    /**\n     * Adds a listener that gets executed when this component was clicked.\n     */\n    public MyComp onClick(Consumer\u003cClickEvent\u003e code) {\n        _onClick.addAction((event) -\u003e code.accept(event));\n        Component\u003c?\u003e _this = this;\n        UI.current().registerJSListener(\"click\", _this, (msg) -\u003e {\n            _onClick.execute(new ClickEvent(msg, _this)); // Executes all listeners\n        });\n        return target;\n    }\n}\n```\nYou can register listeners on any JavaScript event \nyou'd like: https://developer.mozilla.org/en-US/docs/Web/Events\n\u003c/details\u003e\n\n\n\n\u003cdetails\u003e\n\u003csummary\u003eHow to get the HTML of a component?\u003c/summary\u003e\n\nGet the components' HTML string via \n`component.element.outerHTML()`. \u003cbr\u003e\nNote that this also includes all its children.\nTo make sure it equals the actual in memory representation\ncall `component.updateAll()` before retrieving the HTML.\n\u003c/details\u003e\n\n\n\n\n\u003cdetails\u003e\n\u003csummary\u003eWhat about performance?\u003c/summary\u003e\n\n- Minimal memory and cpu usage since no additional JavaScript engine (Node.js) is being used.\n- Each UIs content is provided by a tiny HTTP server and\nJava \u003c=\u003e JavaScript interactions are handled by an even tinier WebSocket server.\n\u003c/details\u003e\n\n\n\u003c/div\u003e\n\n#### Extensions\n\n\u003cdiv\u003e\n\u003cdetails\u003e\n\u003csummary\u003eExtending another component? Method chaining not possible / fallback to super class. What to do?\u003c/summary\u003e\n\nThe problem in more detail:\n```java\npublic class A extends Component\u003cA\u003e{\n    // ...\n    public A methodInA(){\n        return this;\n    }\n}\n\npublic class B extends A{\n    // ...\n    public B methodInB(){\n        return this;\n    }\n}\n\npublic class Main{\n  public void main(){\n    new B().methodInA(); // If we want to do method chaining, aka access\n    // another method of class B, its not possible anymore\n    // due to Java language limits, since now the returned value is of type A.\n  }\n}\n```\nInstead of extending classes we are forced (if we want to provide method chaining)\nto add the super class as field of our current class and wrap around important methods, like so:\n\n```java\npublic class B extends Component\u003cB\u003e{ // Instead of extending A\n    public final A a = new A(); \n    public B(){\n        super(\"b\");\n        add(a); // Add as child\n    }\n    // ...\n    public B methodInA(){\n        a.methodInA();\n        return this;\n    }\n}\n```\n\n\u003c/details\u003e\n\n\u003c/div\u003e\n\n#### Other\n\n\u003cdiv\u003e\n\n\n\u003cdetails\u003e\n\u003csummary\u003ePersistent storage/data? Databases/SQL?\u003c/summary\u003e\n\nI find it easiest to use [jSQL-Gen](https://github.com/Osiris-Team/jSQL-Gen)\n(also developed by me),\nwhich generates the Java source code that is needed to interact\nwith your database and solve this issue in a low-code fashion.\nNote that your database can be integrated in your app / exist on the client directly\n(via [mariaBD4J](https://github.com/MariaDB4j/MariaDB4j) for example)\nor hosted by yourself on your server.\n\n(TODO) If you want to store data in the local storage of the clients' browser/webview,\nyou can use ui.localStorage which \nis the Java implementation of [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage).\nNote that the data here is specific to a window/UI/Route, which means that its not shared\nacross them.\n\n\u003c/details\u003e\n\n\n\n\n\u003cdetails\u003e\n\u003csummary\u003eLogging? Log cleanup?\u003c/summary\u003e\n\nFor logging, you can use the `AL` class and its static methods info/debug, warn and error.\nThese are pre-formatted with ANSI colors, info is white, debug dark gray,\nwarn yellow and error red. Colors are stripped when writing to files and the formatting is slightly different.\n\nYou can pass Exceptions to warn and error. The stacktrace (plus all the causes) will then\nbe displayed. Note that warn only shows the Exceptions' message in the console.\nThe full stacktrace can only be seen in the log file, by default.\n\nWhen using error your app will exit in the next 10 seconds, thus you should\nuse it only if the occurred Exception is critical and hinders your app from\nrunning.\n\nNote that debug will only be shown in the log file by default, not the console.\n\nThis is part of the [jlib](https://github.com/Osiris-Team/jlib) library,\nwhich contains some more useful things you might want to check out.\n\nTODO: Remove older logs to save space on the users' device.\n\u003c/details\u003e\n\n\n\u003c/div\u003e\n\n\n\n\n\u003cdetails\u003e\n\u003csummary\u003eApp.getCSS/getJS methods return null? Resources cannot be found?\u003c/summary\u003e\n\nBy default, build tools will remove anything that is not a .java source file,\nthus your .css/.js or any other files will not be included in the final binary.\nHere is how you can fix this in Gradle, simply append the below to your `build.gradle` file:\n```groovy\n// Ensure that everything other than classes/.java files are also included in the final jar\n// This should also be included in your project if you want to easily load resources.\nsourceSets {\n    main {\n        resources {\n            srcDirs = [\"src/main/java\", \"src/main/resources\"]\n            include '**/*' // Include everything (no .java by default)\n        }\n\n    }\n}\n// This must also be included if you want to generate the sources jar without issues\ntasks.withType(Jar).configureEach { duplicatesStrategy = DuplicatesStrategy.EXCLUDE }\n```\n\u003c/details\u003e\n\n\n\n\n\u003cdetails\u003e\n\u003csummary\u003eHow to support even more platforms? Custom UI and UIManager?\u003c/summary\u003e\n\nUI and UIManager are both abstract classes that can be extended.\nDesku already provides implementations (DesktopUI and DesktopUIManager)\nvia WebView to be able to run on Desktop platforms like Windows, Linux and Mac.\n\nThe Desku-Starter-App contains implementations for Android and iOS. If you\nwant to support even more platforms make a pull-request with your implementation!\n\n\u003c/details\u003e\n\n\n\n\u003cdetails\u003e\n\u003csummary\u003eHow are null values handled?\u003c/summary\u003e\n\ncomp.getValue() should NEVER return null, even if comp.setValue(null)\nwas called before. In that case the default value is returned.\n\ncomp.setValue(null) is allowed to ensure compatibility with similar frameworks\nlike JavaFX, and allow some sort of \"clearing\"/\"resetting\" of the value, without\nneeding to rely on the error-prone null!\n\nThis also means that all components should have a sensible\ndefault value (except very basic containers, these use the NoValue.class).\n\n\u003c/details\u003e\n\n  \n  \n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://github.com/Osiris-Team/Desku/blob/main/docs/desku_banner.png?raw=true\" alt=\"\"/\u003e\n\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fosiris-team%2Fdesku","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fosiris-team%2Fdesku","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fosiris-team%2Fdesku/lists"}