Frederik Handberg's avatar
Frederik Handberg
npub1nj0c...2gqz
23 🇩🇰 I'm studying for a degree in Software Engineering while building fun projects and experimenting with drone technology. I'm also learning to sew garments as a hobby 🪡 Sometimes I work as a freelance photographer for different news outlets 📷 I mostly share progress updates as I'm working on my software and drone projects, and as I learn to sew. Basically, I just write about my hobbies...
Trying to build your own Markdown parser is a horrible experience 😂 I tried once and quickly learned that there are just way too many edge cases to solve…
I am mostly done implementing support for all the canvas objects in the Electron app. So I’m moving on to note documents now because the last object I need to support in the canvas is the note docs. I have just gotten Lexical to work in the editor. The experience is very different than my native Swift app. This is because the native Swift app uses a separate text view for each block whereas all blocks are just one continuous text view in Lexical which is much better for performance. I have not yet implemented support for images and videos. Only text with formatting is working like paragraphs and headings. #dev
I'm trying Electron for the first time. For the past many months, I have been working on a notes app for macOS. I decided to build this app using native tools for macOS, which is the Swift programming language with SwiftUI and AppKit. In the future, I want the app to be made for multiple platforms as I personally use different devices running different operating systems. Building a native app makes this problematic as I then need to build a completely new app for each platform. That's going to take a massive amount of time as a single developer, even with AI to help... For example, for iOS I would need UIKit, for Android it would be Kotlin with JetPack, for Windows it would probably be a C# framework, and for Linux it would most likely be some C or C++ framework. Electron would immediately work for Windows, Linux, and macOS. My reason for choosing the native route was just to experiment and learn, and I'm happy I made that decision. I have learned a lot. Regarding SwiftUI and AppKit, I have found the developer experience to be somewhat disappointing. The documentation has not always been the best and online resources are quite limited. Performance has also been a problem with SwiftUI and same with customizability. When implementing a new feature, I usually started out in SwiftUI and then I learned that what I wanted to build wasn't possible in SwiftUI, so I ended up having to use AppKit anyways. And don't even get me started on AppKit. It's old. Very old. And you can easily feel that. I find that features take a long time to get perfect with AppKit. I usually have some bugs that I end up spending way too much time trying to solve. It also was not uncommon for me that I had to use some "low-level" APIs from AppKit. This is where it got really difficult, because as already stated, the official documentation isn't always very informative. **Let me explain my native macOS dev experience with a bug that I experienced:** Try to insert an `NSTextView` and then place a SwiftUI view above it. Then try to change the `NSCursor` to arrow when hovering the SwiftUI view. You will notice that the cursor is NOT the arrow, but instead `iBeam`. This is because `NSTextView` is super aggressive with overriding the cursor no matter whatever you do. You wouldn't believe the amount of time I have spent trying to solve this bug and others alike... This has been my experience with AppKit and SwiftUI. I feel like I have spent more time solving bugs than implementing features - that's an exaggeration, but still, you get the point :) This sort of stuff just works by default in Chromium. Instead of solving stupid bugs, you get to actually implement features.
It's now possible to search in canvas files 🎉 I added a new search feature to my notes app for macOS. When I click `Enter` it will select the next result in the list and `Shift+Enter` will select the previous result. The problem is that the list does not scroll up and down to always keep the selected result visible. That's the last thing to fix and then canvas search should be working fully as expected. #dev #Swift #SwiftUI #AppKit #macOS
In my notes app, I have overused notifications to pass data around my application. More specifically I used `NotificationCenter`. Using a notification-based system is certainly a very fast and easy way to pass data around, but it’s quite difficult to debug. This is the reason why I’m refactoring parts of the code to be using a state-driven approach in my ViewModels.
I’m building the app that I haven’t been able to find: a beautiful and native notes app for macOS that is perfect for writing note documents and creating mood boards in an infinite canvas. image As a software developer, I need the functionality to create and edit Markdown files to write the features my applications need. I include implementation details for the features I’m building that I can then use to prompt LLMs with. I also do a lot of frontend work, so I’m often looking for inspiration. I think that an infinite canvas would be perfect for this, where I’m able to import images and videos of interesting UI designs that I find on socials. I also started a new hobby: fashion design. In the screenshot of the app, I imported some images and videos into the canvas of some garments that I find cool. #dev #Swift #SwiftUI #AppKit #macOS
I will begin #sewing the next t-shirt. The latest one I made was almost perfect. The shoulder seams should’ve been a bit longer, so I increased that by 2 cm on both sides. When I have made the perfect t-shirt that fit me, I can move on to the next project. This will most likely be a sweatshirt. I’m already working on the pattern in #CLO3D. image
Been working on copy-paste functionality for my notes app. It may sound a bit strange as you might expect this to just work by default, but because of the way I handle text editing in the app, it does not work out of the box. My notes app is block-based and because of this, each text block is its own text view. This means, a note document includes multiple `NSTextView`s (one for each text block). This makes copy-pasting from multiple blocks quite complicated as these text blocks are completely separate - they have no connection to each other. This is where my ‘sequential text view’ hack comes into play. I figured out a way to connect separate `NSTextView`s to allow performing text selections across multiple text views, and then I override the default `copy()` function with custom logic to stitch these text blocks together while keeping the text styling/formatting. So far, copy-pasting works for text, heading, and list blocks. Tomorrow, I will make it work for table, quote, and code blocks.
I hear a lot of developers complain about AI having sucked all the fun out of programming. I can understand that if what they enjoy is writing the code. But personally I feel the complete opposite. I have never enjoyed programming more than now. I’m so happy that I no longer need to be spending a ton of time on writing the code. Instead, I can use that time on figuring out the best architecture for the system I’m building. When I work with an LLM, I write Markdown documents that I use to prompt it with detailed descriptions of the features I want the LLM to implement. This could include which APIs I expect it to use. If it’s a rather unknown API, then I copy-paste the definition of it so it knows exactly which parameters it expects and which methods can be called. I find that if I don’t give the LLM some clear directions, then it will start using deprecated methods and start writing new helper methods even though it could just use existing ones. In general, I think LLMs can be a bit lazy at times… But they can do excellent work if given a good prompt. #AI #LLM #coding
Here's a look at V1 of the grid view mode in fullscreen search: Most of my time has been working on a snapshot feature where the app takes a snapshot of the canvas. This will then be used in the fullscreen search to show a preview of the canvas file. I will most likely use the same approach for note documents instead of rendering the actual note document. It's less resource intensive to load an image compared to a note document with multiple blocks. Later, I will also use the snapshot feature in preview overlays that appear when hovering a note or canvas file. But before this, I think I should fix the UI for fullscreen search first. Just simple things like the list of search result should extend as much height as possible meaning all the way to the bottom of window. In the video, you can see the canvas being a bit laggy in the beginning when it's first loading. I do have some debouncing, but I think it might be a good idea to have a more sophisticated approach where only certain objects are loading at the same time. Perhaps only the ones inside the viewport, but if too many are showing, then have a maximum of how many can load at the same time. #dev #AppKit #Swift #SwiftUI #macOS View quoted note →
I have been working on improving the fullscreen search functionality by implementing a preview mode. So now, there are two modes: _Grid_ and _Preview_. The preview mode is simply the grid but with a preview of the file’s contents. There will also by a third mode called _List_. I experienced some serious performance issues after implementing this new preview mode. This is really what most of my time was spent trying to fix. Before I was showing a real representation of the canvas where I rendered all the objects and scaled them to an appropriate size. Doing a full render of a canvas that could potentially contain 20 different objects (images, videos, note documents, etc.) is a bad idea. And it becomes an even worse idea if the search results include more than one canvas. I decided to figure out a different solution that would solve the performance issues. So I started experimenting… I figured that I could actually just show an image of the canvas, so I implemented functionality to take a snapshot of the canvas whenever closing a canvas file or switching to a different tab. This works really well and I think I will choose the same approach for the minimap inside canvas files. Because currently, I am doing a full render of the objects inside a minimap and there is just no reason to do that… Instead I will just use the snapshot approach. This means, I should also save a snapshot after making a change in the canvas, but of course with a debounce timer. For example, if moving an object, then take a new snapshot after a timer has expired. Will share a video demonstrating of the fullscreen search later…
The pictures are from 2 days ago 💚 #nature #photography 📷
Now that I have improved the media popup by implementing support for zoom-in and out with pinch gestures and an easier way to dismiss the media popup by either clicking the background or by swiping up and down, I think it's time to work on an easier to way switch between the different media attachments in a note document. I found this on Threads that I think looks quite good: Video credit: Initially, I just wanted to show chevron buttons to switch to next or previous attachment, but I think showing the actual thumbnails looks much nicer. I'll see if I can get that working 💻 #dev #inspiration View quoted note →
Been working on a different way to dismiss the image popup in the notes app. Before the only option was to either click Escape key or click in the background behind the image which will also close the popup. Now the user can simply swipe up or down, or "zoom out" by making the pinch gesture. I really want the image in the popup to animate back to its original position in the note document. I do have a semi-working solution, but it's still experimental. I'm having trouble with the opening animation being laggy, but the closing animation looks fine for some reason. #dev #macOS #Swift #SwiftUI #AppKit
I think it would be beneficial to have an easy way for the user to manage and clean/delete the assets (images and videos) in their vault. *The vault is the folder that contains all the files and folders in their Space.* It should show a list/grid of all the assets. Maybe have an import button. Be able to rename assets. Allow user to select and delete. Stuff like that. Then have filtering buttons. For example, filter by unused. This should display a list of all unused assets - meaning an asset that is not attached to any note or canvas. In case an asset is being used, the user should be able to see which notes and canvases are using it. I already have much of the backend for this, because once the user tries to delete an asset, the app will check to see if the asset is attached to any note or canvas, and if so, it’ll display a warning message that the user must confirm before the deletion will proceed. I just think it would be great to have a dedicated page to manage assets rather than doing this in the ‘Files’ sidebar. View quoted note →