Thanks! #69

Closed
opened 2025-08-28 22:13:43 +02:00 by desbeers · 14 comments

First of all, thanks for your great effort!

I wrote a beautiful application for macOS in SwiftUI for guitar players using the Open Source ChordPro format:

Chord Provider

I’m also a contributor to that project and take care of the macOS version.

However; my heart is still at Linux and I wanted to port my application. Rewrote the core to Foundation; wrote a CLI package and now, the GUI...

It took me about two days to get a grip of your code but the result is a reasonable application:

Screenshot 2025-08-28 at 21.21.25.png

Truly enjoyable to write this!

There are issues, obviously:

  • Swift 6 concurrency (I removed a lot of async code)
  • No EmptyView()
  • Learning curve :-D

Thanks; I enjoy this!

Nick

First of all, thanks for your great effort! I wrote a beautiful application for macOS in SwiftUI for guitar players using the Open Source [ChordPro](https://www.chordpro.org) format: [Chord Provider](https://github.com/Desbeers/Chord-Provider) I’m also a contributor to that project and take care of the macOS version. However; my heart is still at Linux and I wanted to port my application. Rewrote the *core* to `Foundation`; wrote a CLI package and now, the GUI... It took me about two days to get a grip of your code but the result is a reasonable application: <img width="1728" alt="Screenshot 2025-08-28 at 21.21.25.png" src="attachments/afe33e68-3aec-4d08-bc71-8928da664d25"> Truly enjoyable to write this! There are issues, obviously: - Swift 6 concurrency (I removed a lot of async code) - No `EmptyView()` - Learning curve :-D Thanks; I enjoy this! Nick
Author

ChordProvederGnome.png

![ChordProvederGnome.png](/attachments/2132a4e2-f0f7-460c-8abc-4d0ff0d64c9e)
Owner

This is so cool! Thank you very much! I’ve fixed a problem in ForEach that affected your render view so please update to the latest package version. I‘ll take a look at your split views, this is an awesome addition!

I’m very looking forward to your further development and hope we can improve Adwaita for Swift!

This is so cool! Thank you very much! I’ve fixed a problem in `ForEach` that affected your render view so please update to the latest package version. I‘ll take a look at your split views, this is an awesome addition! I’m very looking forward to your further development and hope we can improve Adwaita for Swift!
Author

Oh wow, this ForEach fix fixed my crashes when running as flatpak!

I was breaking my head over this; when just doing swift run in the Terminal all was fine...

My to-do list (in random order):

  • Trap the quit() function somehow. When a song is edited it should show a dialog if you want to save the file.
  • Let it open song files directly from Files by double-click. I want to try the ArgumentParser package for that. I already use that in my CLI version.
  • Show chord diagrams. I have them as SwiftUI View in the macOS version and as html for the cli. I would like to have a very simple webview for the Gnome version and looking into this: https://github.com/javalikescript/webview-c WebKitGTK does not compile on macOS so that is no option.
  • Give it a nice icon :-)
  • Update the ChordPro language file for the SourceEditor. That is why I cloned your package; to add a custom language... that I want to send as PR to GtkSourceView when ready.
  • In the end; the Gnome version should have all the bells and whistles my macOS version has...

Anyway, a flatpak release is much closer than I ever thought! Your code is very well documented so it was not so hard to get a grip on it.

Oh wow, this `ForEach` fix fixed my crashes when running as flatpak! I was breaking my head over this; when just doing `swift run` in the Terminal all was fine... My to-do list (in random order): - Trap the `quit()` function somehow. When a song is edited it should show a dialog if you want to save the file. - Let it open song files directly from Files by double-click. I want to try the `ArgumentParser` package for that. I already use that in my `CLI` version. - Show chord diagrams. I have them as SwiftUI View in the macOS version and as html for the `cli`. I would like to have a very simple webview for the Gnome version and looking into this: https://github.com/javalikescript/webview-c WebKitGTK does not compile on macOS so that is no option. - Give it a nice icon :-) - Update the *ChordPro* language file for the `SourceEditor`. That is why I cloned your package; to add a custom language... that I want to send as PR to `GtkSourceView` when ready. - In the end; the Gnome version should have all the *bells and whistles* my macOS version has... Anyway, a flatpak release is much closer than I ever thought! Your code is very well documented so it was not so hard to get a grip on it.
Author

Progress!!

  • It shows chord diagrams!!!
  • It has a nice icon :-)
  • Smarter highlight in the sourceEditor
  • It remembers window size and splitter position

adwaita-swift is full with hidden treasures!

diagrams.jpg

Progress!! - It shows chord diagrams!!! - It has a nice icon :-) - Smarter highlight in the `sourceEditor` - It remembers window size and splitter position `adwaita-swift` is full with hidden treasures! ![diagrams.jpg](/attachments/3f347783-c7d1-488c-ac48-79fa90b3f947)
Owner

This is so cool! Congratulations!

I've just added HSplitView and VSplitView to the main branch (here - I rewrote it using a more declarative approach that is actually slightly more efficient) - thanks for your work!

This is so cool! Congratulations! I've just added `HSplitView` and `VSplitView` to the main branch ([here](https://git.aparoksha.dev/aparoksha/adwaita-swift/src/branch/main/Sources/Core/View/SplitView.swift) - I rewrote it using a more declarative approach that is actually slightly more efficient) - thanks for your work!
Author

Wow, that’s much different and cleaner than mine! Learning every day :-)

Now, besides making the chord diagrams more fancy (cairo, I have to learn c now as well) my next challenge is to trap the quit.

The quickest trick was adding .deletable(false) to the Window but I don’t like that... It feels cheap so I removed it.

The logic for an ‘unsaved’ state is already implemented. Open a new song or quitting from the menu shows a dialog when the song is edited.

I hacked around in your code with mixed result. I can add a signal and trap the quit but since a signal closure is a void I can never actually quit :-)

Any pointers?

Or maybe an optional .onQuit modifier? That returns true or false or something like that?

Next, let it open songs from Files...

I found a couple of bugs; they are on my list to tell you. It might be wrong implementation from my side so still investigating...

And one more question:

Why do you use SQLite as backend for storage? Since all stuff to store has to confirm to codable you might as well store it in JSON. I do that for my settings:

SettingsCache

I like that more because its in its own file. Correct me if I’m wrong, but it looks to me all stored states are in the same data.sqlite database. So if I store the width and height state of my Window, and another application does that as well; it will override each other.

But, most important, it’s great fun to write an Adwaita application in Swift! Never thought I could write a Linux version of my macOS application so easy. Thanks!

Wow, that’s much different and cleaner than mine! Learning every day :-) Now, besides making the chord diagrams more fancy (cairo, I have to learn `c` now as well) my next challenge is to trap the `quit`. The quickest trick was adding `.deletable(false)` to the Window but I don’t like that... It feels cheap so I removed it. The logic for an ‘unsaved’ state is already implemented. Open a new song or quitting from the menu shows a dialog when the song is edited. I hacked around in your code with mixed result. I can add a `signal` and trap the `quit` but since a `signal` closure is a void I can never actually quit :-) Any pointers? Or maybe an optional `.onQuit` modifier? That returns `true` or `false` or something like that? Next, let it open songs from `Files`... I found a couple of bugs; they are on my list to tell you. It might be wrong implementation from my side so still investigating... And one more question: Why do you use `SQLite` as backend for storage? Since all stuff to store has to confirm to `codable` you might as well store it in JSON. I do that for my settings: [SettingsCache](https://github.com/Desbeers/Chord-Provider/blob/main/ChordProviderCore/Sources/ChordProviderCore/Utils/SettingsCache.swift) I like that more because its in its own file. Correct me if I’m wrong, but it looks to me all stored states are in the same `data.sqlite` database. So if I store the *width* and *height* state of my Window, and another application does that as well; it will override each other. But, most important, it’s great fun to write an Adwaita application in Swift! Never thought I could write a Linux version of my macOS application so easy. Thanks!
Owner

Great work! And sorry for ignoring your comment for so long, updating the Swift Freedesktop SDK Extension for GNOME 49 was trickier than I expected :)

  • I added onClose to Window which gets executed if the user closes the window, quits using the context menu in the dash/headerbar or after window.close(). It does not get executed after app.quit, so this has to be handled separately.
  • Yeah, I want to work on the way data gets stored to make the SQLite solution to make more sense instead of simply storing the value as a json in a database. The current solution was built using Flatpak in my mind, where every app has its own data directory. It may be sensible, for whenever someone uses Adwaita for Swift outside of a Flatpak, to name the file using the app's id instead of the generic data.sqlite. Thanks for bringing this up!

Thanks for the nice feedback, it's awesome to see people using my project. I'm looking forward to working on the bugs you found!

Great work! And sorry for ignoring your comment for so long, updating the Swift Freedesktop SDK Extension for GNOME 49 was trickier than I expected :) - I added `onClose` to `Window` which gets executed if the user closes the window, quits using the context menu in the dash/headerbar or after `window.close()`. It does not get executed after `app.quit`, so this has to be handled separately. - Yeah, I want to work on the way data gets stored to make the SQLite solution to make more sense instead of simply storing the value as a json in a database. The current solution was built using Flatpak in my mind, where every app has its own data directory. It may be sensible, for whenever someone uses Adwaita for Swift outside of a Flatpak, to name the file using the app's id instead of the generic `data.sqlite`. Thanks for bringing this up! Thanks for the nice feedback, it's awesome to see people using my project. I'm looking forward to working on the bugs you found!
Author

I added onClose to Window which gets executed if the user closes the window, quits using the context menu in the dash/headerbar or after window.close(). It does not get executed after app.quit, so this has to be handled separately.

This works great! It looks like there is no app.quit in the Gnome overview. When I quit I can still trap it. Happy about that :-)

However, it feels unnatural for me to return true to avoid closing the window. Reading the GTK source, it is correct. Returning true avoids closing. In my opinion, it should be the other way around. But... better keep to their implementation.

My document implementation is a bit smelly... To make Chord Provider working with Files I give every new app an unique ID. Result is that if you click on a song in Files it opens a new instance of Chord Provider. Works fine but feels like a hack...

Found another issue (should I make a new issue for that?). I cannot select a folder with the FilePicker. In the source comment there is that option, but not in the implementation.

Screenshot 2025-10-05 at 16.32.29.png

I truly enjoy GUI design. The small details that makes you feel happy to use an application. I’m getting there. Show only relevant options. My code is still a bit messy; especially in the toolbar. Also repeating code...

I’m pretty proud about my application so far; most of the GUI is done. Couldn’t write it without your project!

STORAGE:

My idea of storing it in a JSON file has one big disadvantage... When the struct changed in code (adding a new setting), the stored settings cannot be read anymore...

> I added onClose to Window which gets executed if the user closes the window, quits using the context menu in the dash/headerbar or after window.close(). It does not get executed after app.quit, so this has to be handled separately. This works great! It looks like there is no `app.quit` in the Gnome overview. When I `quit` I can still trap it. Happy about that :-) However, it feels *unnatural* for me to return `true` to avoid closing the window. Reading the GTK source, it is correct. Returning `true` avoids closing. In my opinion, it should be the other way around. But... better keep to their implementation. My *document implementation* is a bit smelly... To make **Chord Provider** working with `Files` I give every new `app` an unique ID. Result is that if you click on a song in `Files` it opens a new instance of **Chord Provider**. Works fine but feels like a *hack*... Found another issue (should I make a new issue for that?). I cannot select a folder with the `FilePicker`. In the source comment there is that option, but not in the implementation. <img width="926" alt="Screenshot 2025-10-05 at 16.32.29.png" src="attachments/e87be871-dcf2-4c87-8f09-a594b09b7027"> I truly enjoy GUI design. The small details that makes you feel happy to use an application. I’m getting there. Show only relevant options. My code is still a bit messy; especially in the `toolbar`. Also repeating code... I’m pretty proud about my application so far; most of the GUI is done. Couldn’t write it without your project! STORAGE: My idea of storing it in a JSON file has one **big** disadvantage... When the struct changed in code (adding a new setting), the stored settings cannot be read anymore...
Owner

However, it feels unnatural for me to return true to avoid closing the window. Reading the GTK source, it is correct. Returning true avoids closing. In my opinion, it should be the other way around. But... better keep to their implementation.

You're right, this can be quite confusing. I decided to make it slightly more descriptive in 037a697c74:

.onClose {
    return .keep // or .close
}

Found another issue (should I make a new issue for that?). I cannot select a folder with the FilePicker. In the source comment there is that option, but not in the implementation.

I added support for picking folders with file dialogs with the new folderImporter (similar to the current fileImporter for files) in c8ce2cc2fe:

.folderImporter(open: signal) { url in
    print(url)
} onClose: {
    print("No selection")
}

I'll keep working on the other issues and let you know once I make progress :)

Thanks again for reporting those problems!

> However, it feels unnatural for me to return true to avoid closing the window. Reading the GTK source, it is correct. Returning true avoids closing. In my opinion, it should be the other way around. But... better keep to their implementation. You're right, this can be quite confusing. I decided to make it slightly more descriptive in 037a697c74f2c023b315d2ffb471fcf0f6333fcb: ```swift .onClose { return .keep // or .close } ``` > Found another issue (should I make a new issue for that?). I cannot select a folder with the FilePicker. In the source comment there is that option, but not in the implementation. I added support for picking folders with file dialogs with the new `folderImporter` (similar to the current `fileImporter` for files) in c8ce2cc2fe4979e9905cc4ae7d13fa7b6c3a16a1: ```swift .folderImporter(open: signal) { url in print(url) } onClose: { print("No selection") } ``` I'll keep working on the other issues and let you know once I make progress :) Thanks again for reporting those problems!
Author

Thanks, these were my biggest showstoppers :-) While there are still many small things left, I'm pretty close to release a FlatPak.

Now I just cut/paste many of my Swift(UI) code and with minor adjustments it works!

btw: I'm surprised about the great performance of GTK; even on macOS.

Thanks, these were my biggest showstoppers :-) While there are still many small things left, I'm pretty close to release a FlatPak. Now I just cut/paste many of my Swift(UI) code and with minor adjustments it works! btw: I'm surprised about the great performance of GTK; even on macOS.
Author

You're right, this can be quite confusing. I decided to make it slightly more descriptive in 037a697c74:

.onClose {
    return .keep // or .close
}

The word 'keep' sounds a bit strange to me. Maybe just 'cancel' instead? Because the closing of the window will be canceled :-)

> You're right, this can be quite confusing. I decided to make it slightly more descriptive in 037a697c74f2c023b315d2ffb471fcf0f6333fcb: > > ```swift > .onClose { > return .keep // or .close > } > ``` The word 'keep' sounds a bit strange to me. Maybe just 'cancel' instead? Because the closing of the window will be canceled :-)
Contributor

However, it feels unnatural for me to return true to avoid closing the window. Reading the GTK source, it is correct. Returning true avoids closing. In my opinion, it should be the other way around. But... better keep to their implementation.

You're right, this can be quite confusing. I decided to make it slightly more descriptive in 037a697c74:

.onClose {
    return .keep // or .close
}

Found another issue (should I make a new issue for that?). I cannot select a folder with the FilePicker. In the source comment there is that option, but not in the implementation.

I added support for picking folders with file dialogs with the new folderImporter (similar to the current fileImporter for files) in c8ce2cc2fe:

.folderImporter(open: signal) { url in
    print(url)
} onClose: {
    print("No selection")
}

I'll keep working on the other issues and let you know once I make progress :)

Thanks again for reporting those problems!

No way! I'm definitely going to have to play around with that soon. I'm building a couple document-based apps, and the file format for one of them is a package document, which is a regular directory with some extra metadata. This might be handy...

> > However, it feels unnatural for me to return true to avoid closing the window. Reading the GTK source, it is correct. Returning true avoids closing. In my opinion, it should be the other way around. But... better keep to their implementation. > > You're right, this can be quite confusing. I decided to make it slightly more descriptive in 037a697c74f2c023b315d2ffb471fcf0f6333fcb: > > ```swift > .onClose { > return .keep // or .close > } > ``` > > > Found another issue (should I make a new issue for that?). I cannot select a folder with the FilePicker. In the source comment there is that option, but not in the implementation. > > I added support for picking folders with file dialogs with the new `folderImporter` (similar to the current `fileImporter` for files) in c8ce2cc2fe4979e9905cc4ae7d13fa7b6c3a16a1: > ```swift > .folderImporter(open: signal) { url in > print(url) > } onClose: { > print("No selection") > } > ``` > > I'll keep working on the other issues and let you know once I make progress :) > > Thanks again for reporting those problems! No way! I'm definitely going to have to play around with that soon. I'm building a couple document-based apps, and the file format for one of them is a package document, which is a regular directory with some extra metadata. This might be handy...
Author

It’s time to close this issue. With pleasure. I follow the development and great so see some of my issues solved.

The pleasure will goes-on! In 3 months I ported my SwiftUI application to a true and beautiful Adwaita application.

For me, this is the best programming experience in a long, long time. Because its fun, Open Source and still familiar.

While still have a lot to learn I’m behind the stage I have to figure-out how to do to stuff in adwaita-swift.

Now its time to contribute back. While not handy with Git, my first start is to contribute my well-documented code for my Chord provider application; following best practice as much as possible. It’s a neat application! I use it every day as guitar player. I’m proud of it and can be build as flatpak.

I do have a list of issues/suggestions/etc but that is for another issue.

Thanks!

screenshot-adwaita-1.png

screenshot-adwaita-2.png

screenshot-adwaita-3.png

It’s time to close this issue. With pleasure. I follow the development and great so see some of my issues solved. The pleasure will goes-on! In 3 months I ported my SwiftUI application to a true and beautiful Adwaita application. For me, this is the best *programming experience* in a long, long time. Because its fun, Open Source and still familiar. While still have a lot to learn I’m behind the stage I have to figure-out *how* to do to stuff in *adwaita-swift*. Now its time to contribute back. While not handy with Git, my first start is to contribute my well-documented code for my **Chord provider** application; following best practice as much as possible. It’s a neat application! I use it every day as guitar player. I’m proud of it and can be build as `flatpak`. I do have a list of issues/suggestions/etc but that is for another issue. Thanks! ![screenshot-adwaita-1.png](/attachments/5f028a6b-bebd-4d24-b23b-6fb2e86258ff) ![screenshot-adwaita-2.png](/attachments/b9f97d8e-f41d-48f9-9f52-8c3ab467d5b6) ![screenshot-adwaita-3.png](/attachments/b07076dd-46a6-4421-97de-d754cabad7bc)
Owner

Congratulations! Thank you for sharing the amazing project and helping improve Adwaita for Swift! I‘m looking forward to fixing your list of issues :D

Congratulations! Thank you for sharing the amazing project and helping improve Adwaita for Swift! I‘m looking forward to fixing your list of issues :D
Sign in to join this conversation.
No Milestone
3 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: aparoksha/adwaita-swift#69
No description provided.