Hello, i want to use jewel for a standalone projec...
# jewel
j
Hello, i want to use jewel for a standalone project and have a couple questions, is there any more documentation than just the sample for component usage? And is the following artifacting only in debug or also when it is built, i cant seem to build it so i cant test this.
s
Hi! The artifacting is a Compose issue, that is mostly solved by using the swing compositing (Jewel has a convenience API for it)
As for docs, not yet. They are on the roadmap but there's no high level guide.
We're improving kdoc and sample coverage first
j
Thanks a lot for the reply, i will try that. As I'm quite new to compose multiplatform i would like to ask you if you know any guides/examples/docs for compose multiplatform on desktop as i mostly see mobile focussed guides etc. I would like to build the desktop idiomatic way.
s
At this stage it's mostly "look at existing stuff out there" including apps using Jewel, Nucleus, etc
It's not entirely clear what desktop idiomatic means in general outside of electron and native-native
IntelliJ is probably the biggest reference
j
Oh okay, thanks. I just feel like model views and stack based navigating are more mobile/single window oriented and thus looking for a more desktop like alternative. But compose multiplatform is already way better than .net stuff so im happy ๐Ÿ™‚
s
Eheh yeah Better than wpf for sure :) Maui I haven't used but seemed DOA from the outside
c
If by artifacting you mean the white background, be sure to also set the window background to match the Jewel theme since by default the AWT window drawn by Compose Desktop is not aware of the OS theme.
It doesn't solve the rendering issue, but if the backgrounds match, it'll make it less obvious.
โค๏ธ 1
โž• 1
u
https://nucleus.kdroidfilter.com/runtime/decorated-window-jewel/ I recently introduced a jewel-decorated window into Nucleus, and the JNI version fixes the rendering problem.
โค๏ธ 1
๐Ÿ”ฅ 1
20260321-1953-12.2560321.mp4
I just saw that it's not perfect under Windows yet ๐Ÿ˜…
s
Classic Windows ๐Ÿ˜„
j
Haha
u
Microsoft Edge ๐Ÿคฃ
So, I'm not going to invest any more time.
s
You're already doing better than web XD I bet most of the "new native" React based apps fare the same
๐Ÿ’ฏ 1
u
On my app which uses Jewel (with the decorated window from Nucleus) I don't have this problem ๐Ÿค”
Honestly, I don't understand at all.
s
Windows vibes
u
Yes, but still, it means that something in my app fixes this bug and I'm not aware of it ๐Ÿ˜…
๐Ÿ‘€ 1
j
Looks like macos is also kind of having it, havendt had a change to try the "fixes" yet. While im in here, does jewel provide stuff to make custom components, for the app im building i need to have a terminal for example
u
Looks like macos is also kind of having it, havendt had a change to try the "fixes" yet.
Try the nucleus decorated window
. While im in here, does jewel provide stuff to make custom components, for the app im building i need to have a terminal for example
you can use https://github.com/JetBrains/jediterm in a swing panel
s
Of course you can build custom components โ€” Jewel doesn't prevent you from doing it. And as Elie said, you can also use existing Swing components in an interop container if you don't want to build the whole thing yourself
j
Yes, thanks. But i more mean custom base ocmponents like meterials etc
Or am i thinking wrong?
s
Material and Jewel are not used together, they are different design systems and component sets
If there are components that you are missing in Jewel please open a feature request โ€” but at this stage I'd say we have most of the "big" components covered in Jewel, with only lazy tables being still WIP
j
Yes i understand its different design systems, i mean is the styling streamlined so i can for example style a box like a button or something else?
u
The API isn't as modular as Material , but it already gives you a certain degree of freedom that seems sufficient on desktop.
โค๏ธ 1
c
Though the styles are quite coupled to their components so you can't easily style a Box with any component style. Really depends what you are trying to do specifically. The styling is not as free form or as composable as say Tailwind if that is what you are looking for. At the same time, many of the components use content/slot parameters, so for example, if you need to put random stuff in a button container, you can, and still can get stuff like the focus ring, hover/pressed states, etc.
j
Probably the most complicated custom thing i want to do is makea box have a background color thats theme aware of the IntUITheme
s
That seems like a trivially easy thing to do tho? As in, the literal worst case scenario is having to manually
if (JewelTheme.isDark)
, but if you use one of the colours from the existing component stylings you don't even have to do that...
โ˜๏ธ 1
๐Ÿ‘ 1
j
The font seems quite low res, any ideas on why:
u
You are on linux ?
j
Windows
u
you use the jbr ?
j
yes
u
Strange ๐Ÿค”
j
image.png
u
it' s right
j
should i try 24?
u
It won't change anything.
๐Ÿค” 1
jbr is only lts, 21, 25
j
ooh okay
u
try with an another font maybe, from your compose res
https://github.com/kdroidFilter/Nucleus/releases can you check the jewel sample on windows ?
to know if you also experience this low res effect?
j
Yes, the same there.
u
I have 5000 Windows users with my program that uses Jewel, and nobody has reported this to me.
but I use my own fonts
j
Mmm, its reallyt weird, since im still new i got to find out how to use a different font
u
Copy code
@Composable
    fun defaultTextStyle(): TextStyle =
        TextStyle(
            fontFamily =
                FontFamily(
                    Font(resource = Res.font.notoserifhebrew),
                ),
        )
Copy code
JewelTheme.darkThemeDefinition(
                 
                            defaultTextStyle = defaultTextStyle(),
                        )
j
okay let me try it with a font in the res
bottom looks better in my opinion, but my eyes are kinda bad
pleas tell me if its just me ๐Ÿ˜†
u
I see a difference, but I think it's just the font; I don't see it as blurry in the screenshot.
j
oKAY, I TIHNK I WILL USE THE OTHER FONT NO MATTER WHAT SO ๐Ÿ™‚
oh caps
๐Ÿ˜‚ 1
๐Ÿ˜ตโ€๐Ÿ’ซ 1
u
You can try using OpenGL instead of DirectX ?
Copy code
System.setProperty("skiko.renderApi", "OPENGL")
at the very beginning of the main, before application
Copy code
when (getOperatingSystem()) {
            OperatingSystem.WINDOWS -> {
                if (isWindows10()) {
                    System.setProperty("skiko.renderApi", "OPENGL")
                } else {
                    System.setProperty("skiko.renderApi", "DIRECT3D")
                }
            }
For other reasons, I do this
j
With open gl:
u
there is a difference ?
j
im checking woth the default rn ๐Ÿ™‚
without:
I dont see any blur
on eiter
u
me too
j
maybe restarting and starting on the next day is enough?
the screenshots from yesterday do show blur. Wierd....
u
The mysteries of Windows...
j
Yep laugh cry face palm
u
You only need to check my example, or also your program ?
because my Jewel example doesn't use JBR but a Nucleus fix for HDPI under Windows
j
Nucleus jewel sample looks good too
u
it's a native image without a JVM
j
My own app using kbr looks clear as well
which uses jbr
u
I don't know what to say
j
Damn windows
i think ill use opengl no matter what since my app will only target windows
u
Yes, Microsoft loves to make developers suffer.
๐Ÿซ  1
j
Hey @ืืœื™ื”ื• ื”ื“ืก since you implemented the jewel decorated window and title bar for nucleus. Why do they look soo different?
Copy code
package ui

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.application
import arkascendedservermanager.ui.generated.resources.Res
import arkascendedservermanager.ui.generated.resources.nunito
import io.github.kdroidfilter.nucleus.darkmodedetector.isSystemInDarkMode
import io.github.kdroidfilter.nucleus.window.TitleBar
import io.github.kdroidfilter.nucleus.window.jewel.JewelDecoratedWindow
import org.jetbrains.compose.resources.Font
import org.jetbrains.jewel.foundation.theme.JewelTheme
import org.jetbrains.jewel.intui.standalone.theme.IntUiTheme
import org.jetbrains.jewel.intui.standalone.theme.darkThemeDefinition
import org.jetbrains.jewel.intui.standalone.theme.default
import org.jetbrains.jewel.intui.standalone.theme.lightThemeDefinition
import org.jetbrains.jewel.intui.window.decoratedWindow
import org.jetbrains.jewel.intui.window.styling.dark
import org.jetbrains.jewel.intui.window.styling.light
import org.jetbrains.jewel.ui.ComponentStyling
import org.jetbrains.jewel.ui.component.Icon
import org.jetbrains.jewel.ui.component.IconButton
import org.jetbrains.jewel.ui.component.Text
import org.jetbrains.jewel.ui.painter.hints.Size
import org.jetbrains.jewel.window.TitleBar
import org.jetbrains.jewel.window.newFullscreenControls
import org.jetbrains.jewel.window.styling.TitleBarStyle

@Composable
fun defaultTextStyle(): TextStyle =
    TextStyle(
        fontFamily =
            FontFamily(
                Font(resource = Res.font.nunito),
            ),
    )

fun main() = application {
    System.setProperty("skiko.renderApi", "OPENGL")
    val isDark = isSystemInDarkMode()

    val themeDefinition = if (isDark) JewelTheme.darkThemeDefinition(
        defaultTextStyle = defaultTextStyle()
    ) else JewelTheme.lightThemeDefinition(
        defaultTextStyle = defaultTextStyle()
    )

    val styling = ComponentStyling.default()
        .decoratedWindow(
            titleBarStyle = if (isDark) TitleBarStyle.dark() else TitleBarStyle.light()
        )

    IntUiTheme(theme = themeDefinition, styling = styling) {
        JewelDecoratedWindow(
            onCloseRequest = { exitApplication() },
            title = "AASM",
        ) {
            Column(Modifier.fillMaxSize().background(JewelTheme.globalColors.panelBackground)) {
                TitleBar(Modifier.newFullscreenControls(), gradientStartColor = Color(0x56fff100)) {
                    Row(Modifier.align(Alignment.Start).padding(start = 8.dp)) {
                        Row(
                            horizontalArrangement = Arrangement.spacedBy(3.dp),
                            verticalAlignment = Alignment.CenterVertically,
                        ) {
                            Row(
                                horizontalArrangement = Arrangement.spacedBy(4.dp),
                                verticalAlignment = Alignment.CenterVertically,
                            ) {
                                Text("Bob")
                            }
                        }
                    }
                    Text("Ark Ascended Server Manager")
                }
                Text("Hello World")
            }
        }
    }
}
inactive state does not change on mine
u
are you using the jbr or jni version of decorated window ?
j
JBR
u
can you try with jni ?
j
yes, i will
Same
u
What makes them different?
j
If i look at the 2 jewel samples, the nucleus one does not have inactive titlebar color difference and does not have a border below it.
image.png
u
I need to check
I know I slightly modified the code
j
Oh okay
Is your app open source by any chance or do you know any other repos that use jewel to use as example?
u
My app is open source but is entirely in Hebrew
j
Thanks, is code Hebrew too?
u
no ๐Ÿ™‚
j
Thanks, i will probably learn alot from the code alone ๐Ÿ™‚
๐Ÿ˜… 1
seems like this part is missing:
Copy code
Spacer(
    Modifier
        .height(1.dp)
        .fillMaxWidth()
        .background(JewelTheme.defaultTitleBarStyle.colors.border)
        .semantics { hideFromAccessibility() }
)
when i add it after the titlebar and drag the window i get wierd flickerting and i dont know about layouts and stuff. so idk whats wrong
u
Yes, I noticed that; it's a bug with OpenGL.
j
damn
u
but it seems to me that it only exists on JNI
j
Oh ohkay
u
jni decorated window was rewritten from scratch and, as I'm writing in the doc, it hasn't been tested nearly enough.
j
damn, i understand. Im already happy youre making all of this ๐Ÿ™‚
๐Ÿ™Œ 1
u
I'm trying to bring native images via graalvm to Compose Desktop; I think it's really necessary.
I recently implemented (and haven't documented yet) a static bytecode analyzer to try and detect reflections at compile time as much as possible.
My intuition is that this is possible on desktop because the reflection used is much lighter than in frameworks like Swing.
And for now, I'm quite satisfied with the results.
j
much of this is unkown to me. I guess ill use the jbr window for now ๐Ÿ™‚
๐Ÿ’ฏ 1
u
Here is an experimental example of my program, which is quite large and uses GraalVM on a 2014 Celeron N2840.
And it's very impressive; you can even see that my program takes less time than the terminal starts up.
j
So graalvm and all the jni stuff makes everything use more native stuff instead of donig it in java resulting in waay better performance?
u
Regarding native integration, using JNA actually makes it much more complicated; that's why Nucleus doesn't use JNA as a matter of principle.
In terms of performance, you'll get an instant cold start, but in CPU throughput, you'll experience a loss.
My program uses a very complex search system; I've noticed a 40% performance loss in the search.
j
Damn, im planning to manage game servers and want as least as possible overhead i think i should start using the aot stuff. is it hard to set up?
u
But despite everything, I prefer it because the users have modest machines; a Celeron can take 1 minute to compile the classes at startup.
j
Oh yeah
mm
u
No, no, not AOT, you have to use Leyden I think
j
My brain is exploding
u
If you need minimal latency, the JVM will perform much better; with Leyden you significantly reduce breakage.
j
mm okay
u
Leyden is the happy medium; it allows the JVM to start much faster.
You need to configure your program to create an AOT cache; the JVM will use it and reach C2 much faster.
Nucleus allows you to do this in 5 lines of code
j
Okay and this is better for general performance?
u
Once the JVM reaches C2, it's exactly the same.
j
Okay, what is C2
u
It just allows you to reach it faster.
The JVM compiles your code in real time; first your app opens, but the code isn't optimized. This is called C1.
j
Oooh okay
u
Then it performs profiling and compiles your code to maximize performance; this is called C2.
๐Ÿ‘€ 1
I'll get that to you very quickly; the JIT of JVM is the most optimized JIT in the world.
j
Okay ๐Ÿ™‚
u
When I activated Leyden, users reported a fivefold reduction in startup time.
j
Damn
ill activate it, since its free improvements, which ill take happiliy ๐Ÿ™‚
๐Ÿ’ฏ 1
u
But it's still slower than what you'd get with a full AOT build like Flutter, which is why I'm trying to implement compilation with GraalVM.
j
Yeah okay, understood
u
A Flutter app will start in approximately 0.65 seconds on my machine, and 0.85 seconds for a Compose app using GraalVM.
j
i started with flutter but it dit not even have multi window support which is a must for me
u
Flutter is not optimized for desktop, even in terms of scrolling feel.
j
Found some other wierd behaviour
i like dart, but flotter and the way of it not much
u
j
Will read ๐Ÿ™‚
u
Found some other wierd behaviour
Yes, I'm talking about this bug. I tried to reduce the case, but I stopped worrying about it because I saw a similar bug in Microsoft Edge.
j
Yeah okay haha
j
Seems like not using opengl and use jni window gives the best result.
๐Ÿ’ฏ 1
@ืืœื™ื”ื• ื”ื“ืก when i use the typography from jewel it does not apply my nunito font using the way you explained ๐Ÿ˜•
Copy code
@Composable
fun defaultTextStyle(): TextStyle =
    TextStyle(
        fontFamily =
            FontFamily(
                Font(resource = Res.font.nunito),
            ),
    )

fun main() = application {
    val isDark = isSystemInDarkMode()

    val themeDefinition = if (isDark) JewelTheme.darkThemeDefinition(
        defaultTextStyle = defaultTextStyle(),
    ) else JewelTheme.lightThemeDefinition(
        defaultTextStyle = defaultTextStyle(),
    )
j
Oooh im gonna use you islands theme too ๐Ÿ™‚
โž• 1
Still only nunito in titlebar and not in typograpghy
๐Ÿ˜•
u
Wait for the master @seb
j
okidoki
s
I've been summoned
What for? :D
j
When overriding default text style it does not apply to typography
hellow world should be same as title font
nunito
s
IIRC typography is derived from the default text style
But your override may happen too late/in the wrong place
j
It happens by passing themedefinition and styling into the intuitheme
image.png
s
I'm afk at this very moment so can't provide a precise answer
j
no problem
It seems native islands support is coming, should i not use your implementation and wait or just transfer it over @ืืœื™ื”ื• ื”ื“ืก
u
If it happens natively, I'll migrate too ๐Ÿ™‚
j
Okaay, ill keep it liek this for now. Doesnt seem it will be that difficult and when its added i hope to be better in compose and kotlin etc.
u
you start with compose ?
j
Im new if thats what you mean yes.
u
This is unusual; most of them come from Android but it's okay๐Ÿ˜…
j
Yeah i come from web development and liked the reactive state compared to other frameworks ๐Ÿ™‚
๐Ÿ’ฏ 1
And i really like kotlin since i feel it kind of represents golang
but more oop
u
Go is really a poor language compared to Kotlin.
Kotlin is surely one of the richest languages โ€‹โ€‹that exist
j
Yes but i like it for its simplicity in some cases and kotlin for its completeness
u
Yes, it's not bad language, that's not what I said, it's simple language.
โค๏ธ 1
j
When im writing performant simple microservices i tend to go for golang
u
Kotlin is truly very rich, and its ecosystem is even more so.
j
Yes
u
On one hand, there's the JVM ecosystem, the well-known backend frameworks; on the other hand, there's the entire Android world; on the other hand, you have the whole desktop basics with Swing; now you also have Kotlin Native, especially on iOS, and each is based on Kotlin but different.
j
Yep, sometimes the completeness of kotlin (+ ecosystem)c an be confusing to me ๐Ÿ˜†
u
Yes, the ecosystem is rich, and that's without even mentioning all the somewhat classic tooling you need to learn and that you find pretty much everywhere; it starts with Gradle.
j
comping form just go run or composer dev (laravel) gradle is a whole other level.
๐Ÿ˜‚ 1
u
Actually, I'd say that Kotlin is a language that works natively everywhere; it doesn't try to give you platform abstraction. Kotlin works natively like Java on a JVM; it will work natively in a JS ecosystem with Kotlin JS, and similarly, Kotlin natively allows you to interact with iOS APIs natively without abstraction. So ultimately, the secret, once you have a good grasp of the foundations, is to learn the platform.
j
Yes, indeed
u
And Kotlin, thanks to KMP, is the language that allows you to easily create your own abstractions with the current expect pattern; you decide which part of your code shares
j
Yes i like that alot too, but right now ive only used it to make desktop apps
u
And that's what I particularly love, besides compsose; those are the two things that really make me love Kotlin: that feeling of freedom, I can do what I want with this language.
๐Ÿ’ฏ 1
The desktop sector is unfortunately one of the least wealthy there is.
But it's not just in Kotlin, it's a general trend
j
Really?
I only do it for OSS atm, but also chose for CMP so i can apply it to mobile.
u
Yes, the desktop sector is lagging behind. If you look at all the libraries I've had to develop in the last three years, you'll realize how much isn't natively available.
j
Yeah okay
I see alot of open prs on github, what is the velocity on jewel, do you know?
u
Since they integrated the IntelliJ repository, I'd say it's become quite slow.
j
Damn, is saw stuff like datatable which i dont see back since the merge
u
I must say that I didn't understand the point.
j
I understand it for the integration sake for plugins. But for standalone it seems pointless
s
Our velocity depends on a number of factors. It surely has gone down since moving into IJ but not purely because of it; we are a lot more deliberate with our releases now to avoid breaking users
๐Ÿ‘ 1
There is no point in separating standalone and bridge, you can't add features on one without adding on the other, etc
j
Just got rick rolled by the standalone sample ๐Ÿ˜ญ
Is there something like a dialog? Or should i use another window for this?
u
There is a DialogWindow
and in nucleus decorateddialogwindow
j
Oh okay separate window it is ๐Ÿ™‚
u
Desktop guideline ! don't use dialog like android, only separate windows !!
j
Oh okay thanks! Thinking too much like web
๐Ÿ˜… 1
Should i lock the main window while dialog is open?
u
the dialog will do this for you
j
oh yeah nvm
u
it shoud be a children of your window
j
yes okay, thanks alot! I've just set up basic navigation with decompose and currently really happy:
u
why decompose ?
j
Most experience with that (tried it once) and i like the lifecycle management
Is using the repository pattern for shared state a good idea? And do you have better alternatives for decompose?
u
It's not very useful on desktop decompose; you don't have a back button, so you don't really have a stack to manage. Why not a simple
when
?
j
I think it will get cluttered wit halot of screens no?
u
It can be useful in an onboarding process where you have several steps, and you can move from one step to another, but in that case, I simply use Compose Navigation.
It really depends on the app you're going to make.
But if you only have 5 screens, and no previous button, use a
when
statement.
Otherwise, I'd recommend Nav3 instead.
Just disable the default animations; they make it look too mobile.
j
Its a gameserver manager, on the servers page there will be multiple servers you can click and it then routes to the server specific page which will also have multiple pages, and when i switch between lets say settings and servers i want it to save the "unsaved state"
u
I understand, I don't know enough about decompose, personally I use either nav2 or nav3
j
Okay ill look into it! What do you think about the repository pattern to keep shared state together?
u
I don't quite understand;
j
I have a separate module that loads, creates, reads server configs. To persist this in the application i need a shared object across the app. Some posts and AI said i should use a repository pattern: https://medium.com/@yeldar.nurpeissov/master-kotlin-multiplatform-navigation-with-decompose-add-di-with-kodein-and-koin-405462b2691b
u
If you're just starting out with Kotlin, I recommend a simple singleton with flows; later you can use dependency injection frameworks.
j
Okay thanks! Wouldn't this state singleton be a "State Rpeository"?
u
Yes , It's basically a Repository that also holds in-memory state.
j
Okay thanks alot. I tend to go into the deep too fast, i think you just saved me!
u
Before using a framework like Koin (or Metro, which I use), I think you first need to understand the problem they're meant to solve. But in your case, I think it's wiser to start slowly with a singleton.
j
I mean i do have experience with DI and other stuff from Laravel
u
ah ok sorry
j
NHoi problem ๐Ÿ™‚
u
That must be a shock for you, PHP -> Kotlin
It's like going from a scooter to a fighter jet.
j
I mean i really like PHP 8+, together with laravel it lets be build stuff really quick and simple. But when i want complex processing or other complex stuff i tend to grab to go ๐Ÿ™‚
There is even |> which i really love
K 1
Does kotlin have it? i mean you can chain most stuff cleanly so you dont really need it i guess.
Have you heard about deompose router? https://github.com/xxfast/Decompose-Router