Frederik Handberg's avatar
Frederik Handberg
npub1nj0c...2gqz
23 🇩🇰 Studying for a degree in Software Engineering while building fun projects and working freelance as a News Photographer 📷 I share my software projects, photos and videos from my work as a news photographer, and progress updates as I learn to sew garments. Basically, I just write about my hobbies. frederikhandberg.com
I FINALLY have `NSTextAttachmentViewProvider` working in my native #macOS notes app! 🎉 This means I can now display interactive #SwiftUI views inside an `NSTextView`. Notice how I’m embedding an image directly into the textview, which the user can click to show the image in a popup. It sure did take a lot of trial and error before I could get it working. I did try to use LLMs to help out, but they were hallucinating like crazy - this makes sense though. They learn from gathering data, but there really isn’t much data available online about `NSTextAttachmentViewProvider`. This is unfortunately the case with many of the #AppKit APIs… There just aren't that many resources to be found, which makes learning AppKit much harder compared to, for example, web development (at least I personally found web dev much easier to learn). **The problem I experienced:** The whole point of me trying to use the API, was because I needed to display a SwiftUI view containing an image directly inside an `NSTextView`. This is unsupported by the `NSTextAttachment` API. _Just to be very clear: Yes, I know that you can show an NSImage using `NSTextAttachment`, but you **CANNOT** show a SwiftUI image._ I tried to write some hacks to get it working, but then I learned about the newer API called `NSTextAttachmentViewProvider` which would allow me to do exactly what I wanted - to embed a SwiftUI image inside a textview. However, by using this new API, I had to migrate from `TextKit1` to the newer version `TextKit2`. The migration to the new `TextKit2` went fairly smooth, but getting the images to show correctly inside the `NSTextView` was quite the challenge 😅 My biggest problem was getting the size of the images to work. They seemed to be limited to the line height, which meant, the images couldn’t grow more in height than 32pts. **Re-rendering bug**: You'll notice in the video, that the images are showing the loading indicator very briefly whenever I hover over the heading blocks. This will be my next task to fix. **Hover effect bug:** There's also a problem with the text selection cursor showing even when I'm hovering over an image - it should change to the pointer cursor. It does actually change very briefly, but then changes back to text selection cursor again. #Swift #dev
View quoted note → View quoted note → It’s hard to get normies on #Nostr. As soon as they learn that their NSEC can’t be recovered or reset, or that discoverability on Nostr is mostly non-existent (except for reposts), they’ll be heading for the exit… The problem with Nostr identities not being recoverable if compromised is a massive problem. It’s my biggest problem with the Nostr protocol. It only takes one mistake where the user pastes their NSEC into a malicious client. As Nostr grows (if it ever does), we will see an increase in malicious clients popping up. Think about building up a following on Nostr just to lose it all because you made one mistake pasting your NSEC into the wrong client. It’s discouraging to creators…
Apparently, `NSTextAttachment` is very limited in what it can do. Simple things like opacity and scale hover effects aren't possible by default. That's a bummer... 😔 Luckily, I just learned about `NSTextAttachmentViewProvider`, and this one seems to support embedding interactive views in text. This means, I should be able to have a SwiftUI view embedded directly in the `NSTextView`. This SwiftUI view will contain an image with some beautiful animations such as: ```swift .opacity(isHovering ? 0.85 : 1.0) .scaleEffect(isPressed ? 0.97 : 1.0) .animation(.easeInOut(duration: 0.15), value: isHovering) .animation(.spring(response: 0.2, dampingFraction: 0.6), value: isPressed) ``` #dev #Swift #SwiftUI #AppKit View quoted note →
I finally figured out a solution to fix the many issues I had with my approach for the editor 😅 Basically, I was using an independent and separate `NSTextView` inside of each block. For example, if I had two text blocks, it would be two separate `NSTextView`s. This was causing issues with caret navigation using the arrow up and down keys. The reason was that the textviews weren’t connected in any way, so I had to implement a custom solution. It mostly worked, but the x-position was sometimes off by a few characters. Another problem was selecting text across multiple blocks. This isn’t possible by default either. I didn’t try to implement a custom solution for this, because I could already see that my approach of using separate textviews was flawed. I would’ve ended up spending a lot of time fixing basic things like text selection not working. I then thought, _what if I could just use a single textview?_ I realized that using `NSMutableAttributedString` could be useful. I spent all of Sunday working on this, but I finally have a solution that seems pretty solid. Now all blocks are displayed in the same textview, so selecting text across multiple blocks finally works 🚀 **Next tasks:** - Get images and videos working using `NSTextAttachment`. - I also need to get the animation working when collapsing a heading, so that the text moves up and its opacity decreases. - The pointer cursor does not show correctly when hovering the ellipsis button. It still shows the text selection cursor. #dev #Swift #AppKit #SwiftUI View quoted note →
In the current approach, I use an `NSTextView` in each block. This means, if you have two text blocks, there are going to be two separate `NSTextView`s. This is problematic, as it’s really difficult to make keyboard navigation feel natural when navigating the caret between the two text blocks. You know how when you use arrow up and down keys to navigate in some text, the x-position is remembered to ensure the caret stays in the same position on the horizontal axis. I do have a solution that mostly work, but I have a bug where _(I think)_ it resets the x-position on each up and down click. Shouldn’t be too difficult to fix. **However, there is another problematic issue:** Another problem is text selection. Selecting text across two different `NSTextView`s must be faked, as it does not work by default, so I need to implement a custom solution. **I see two options:** - I can continue with the current approach of using separate `NSTextView`s for each block, but this requires much debugging and custom solutions. Maybe I will never be able to get it perfect 🤷‍♂️ - Or, I can pivot and use one single NSTextView which is apparently what Apple Notes is doing. I’m not super familiar with `NSMutableAttributedString` and `NSAttributedString`, but apparently these allow for custom styling inside the same text string. For example, you can have a line with a bigger font size and then a line below with a smaller font size inside the same text paragraph. You can even add attachments inside the text with `NSTextAttachment`. I think this should also work for checkboxes. I will experiment with this new approach over the weekend. Hopefully, I can get something working. #dev #macOS #Swift #AppKit View quoted note →
I added a new image popup to my #macOS notes app 🚀 Simply click on an image, and it will open the image in a popup with a blurry and slightly dark background. I think it looks beautiful 🤩 Also added a subtle fade-out effect to the note content right below the tabs at the top. Can't wait to begin working on the iPhone and iPad app, but there's still more to be done on the macOS version 💻 I still need to implemented the visual canvas functionality, which will be a major part of the app. I think it will be perfect for brainstorming and organizing notes. The home tab also needs to be implemented. Right now, there’s just placeholder text. Still figuring out exactly what I want with it 🤔 #dev #Swift #AppKit
Funny how in autumn I get way more productive. I just code all the time 😂 And besides coding, I walk the dog 🐕‍🦺 The weather outside is cold and it’s raining 🌧️ Not very fun to be outside this time of the year…
Importing images and videos is now working in my notes app 🚀 But it's not quite perfect yet! There's still more work to do 💻 When importing media for the first time, an `/assets` folder is created in the root directory where all media is saved. Media files are reference by relative paths in the note documents. Need to work more on videos (notice the black bars on top and bottom - they should be removed). When placing cursor on video and then swiping up and down, the video starts scrubbing which is annoying. Need to figure out how to disable that. Resizing images and videos doesn't work. I also need to get fullscreen working. Basically, when double-clicking on an image, it should go into "fullscreen" - well, more like a popup with a blurry and dark background. I should probably add an option in the context menu when right-clicking an image to make it a fullscreen image that fills the entire screen. Two more options I should add could be "Open image in new tab" and "Reveal in Finder". This is unrelated to media and is more of a general issue: There's a problem with the 'Files' sidebar not updating/re-rendering when new files are imported. It just does not render the new files, so they are never displayed in the sidebar, unless the user quits and reopens the app. I think this should be fairly easy to fix. I probably just forgot to observe an `NSNotification`... #dev #Swift #AppKit #macOS View quoted note →
Today, I'm going to be working on the functionality to insert media like images and videos into documents for my notes app. I'll concentrate on getting images working, but maybe I can even get support for videos implemented as well before the end of today. **I have some decisions I need to make:** - Where should media be saved? I'm thinking of creating an `/assets` folder automatically when the user imports some media. - How should notes reference media? Should probably be the same way as Obsidian - just use a relative path. However, it's important that the path updates automatically if the user moves the media file elsewhere. - What to do if there's a naming conflict? Either, the app can check if the imported media is identical - in that case, there's no reason to import a duplicate so just cancel the import and let the user know, that the media has already been imported. Otherwise, I could just add "(1)", "(2)" and so on after the file name. The last option is certainly easier, so I think I'll start with that, then I can improve it later... Hopefully I can get it working before the end of today 🤞
Exactly! Algorithms aren’t necessarily bad. However, the user **MUST** always be in control. This is the problem with centralized platforms. They give no control to the user. All users on a platform like TikTok are forced to use their addictive algorithm designed to steal their attention for as much time as possible. View quoted note →
I changed the UI a bit for my native #macOS notes app 🚀 Now the note documents are displayed inside what looks like a page. I personally really like the design, but it’s just an option the user can toggle. If disabled, the note shows without the page outline. **What I have fixed:** - Indentation now works in lists. Using tab to indent and Shift+Tab to unindent. - Deleting list items is now possible with backspace. If the item has text, it’s transformed into a normal text block. If empty, the list item is removed. - Collapsible headings. - Added a translucent background color when hovering blocks. - Improved caret navigation between blocks. It feels much more natural now because the app remembers the x-position, so the caret stays in the same place on the x-axis when moving between text blocks with the arrow keys up and down (not implemented for lists yet). **Next task:** Implement functionality to delete blocks. I also need to figure out how to show the text formatting options. I see two options: 1. Either show a toolbar 2. Or show all the formatting options in a sidebar #Swift #AppKit #dev
Also, I’m not sure how many so-called “content creators” or influencers actually want to build a following on #Nostr, knowing that if they lose their private key or if it gets compromised, they’re just shit out of luck. There’s nothing they can do. Of course that turns people away. View quoted note →
Agreed with everything except the part about keys. I do think it’s a big problem, but there’s no viable solution. Keys definitely scare people away unless they’re already from the blockchain/crypto space. And the fact that you can’t recover them if lost isn’t exactly appealing either. But it is what it is... 🤷‍♂️ View quoted note →
The worst part about building a native #macOS app is having to relaunch it every single time you make a change just to see if it works. Would be nice to have a hot-reload feature like in #Flutter.
My notes #app is slowly starting to be in a functional state. image But there's still much work to be done 😅 Tasks I need to work on for my notes app: - The 'Files' sidebar needs to update in real time when the user is creaing folders and files outside the app. So, if the user creates a new folder inside the directory through Finder, the app should immediately update to show the new folder in the UI. - UI of the formatting toolbar needs to be fixed. It's the toolbar with all the options like toggling bold, italic, underline, and other formatting options. I need to figure out how I want it to look and where it should be located. - When deleting a note or folder, a confirmation popup should appear. Currently, notes or folders just get deleted immediately when clicking 'Delete' in context menu. Also, they don't get deleted to the trash where they can still be recovered. No, instead they get permanently deleted 😬 - Folders can already be renamed, but the 'Rename' option in the context menu for notes is not working. The user can currently only rename a note by opening it and then using the textfield containing the note's name (this field can be edited to change the name of the note). - Only paragraphs and headings can be edited. The rest of the blocks can't be edited yet. I need to implement independent rich text editors for each of the block-types. - Navigation. The back- and forward buttons don't work. They should be like in Chrome, where you can go back to the previous page. I will need a way to keep track of which pages the user has viewed and in the correct order. - I need a local SQLite database. This will allow me to have super fast and efficient search functionality. #dev #Swift #AppKit #macOS
I have now implemented support for note documents based on a JSON-structure. The rendering is looking nicely and shortcuts are working - such as `CMD + B` for applying bold styling. Still work to do with the UI. For example, I'm not really sure where the toolbar should be with all the formatting options. Maybe it should only appear when selecting some text. Then the toolbar could show above the selected text. But that approach is also a bit annoying, because the toolbar will then cover part of the text... The Craft app is using that approach and I'm not particularly a fan of it. The word and character counters are totally incorrect. They are based on some old logic that I haven't updated yet. Saving the note is working with shortcut `CMD + S`. I need to show a popup when trying to close a note with unsaved changes. This was actually working before, but the logic was based on an older ViewModel called `NotesViewModel`. I'm still in the process of switching from having one massive ViewModel to multiple independent ViewModels each with their own responsibilities (some examples of my new VMs are `TabsViewModel`, `FilesViewModel`, `SearchViewModel`, etc.). Obviuosly, it's bad practice to centralize all code in one ViewModel because it grows so massive that it becomes difficult to maintain (it breaks SRP from SOLID). The reason for me having just one ViewModel for so long, was that I really just wanted to move fast so I could quickly get something working. But when I later wanted to introduce new ViewModels, it then became much harder, because there was so much code that had to be restructured and moved into new ViewModels. So many things broke and it almost took a full day to get everything working again. Some small parts still isn't working, but that's because I just haven't prioritized those things. There are much more important things than getting character counters working again... #dev #Swift #AppKit #macOS image
The big #AI companies told everyone that they could build a whole app using an #LLM. The real software developers like myself quickly found out that it was absolutely not true, unless it’s a simple little app/website. AI is definitely useful, but it still requires you to know programming if you want to build something awesome. Because of this, much of the hype has died off. There’s still hype, but people are getting much more realistic about what current LLMs are capable of. I think a lot people has gotten an app idea at some point - not only developers, but also completely normal people. The normal people were told that they could use LLMs to build their app ideas. Then they tried, and quickly figured out that it’s actually way harder and the AI still requires a lot of guidance. You can’t just write a prompt and expect the AI to give you a perfectly usable and functional app. If you don’t know how to program, you can’t read and understand the code that the AI writes, which makes it impossible to guide it in a precise way. I suppose this is the reason for why tools like Lovable are getting less Google searches. A lot of these LLM tools were made for people who couldn’t code and now those people seem to be using AI a lot less for trying to build their app ideas. Basically, they gave up, which means many AI tools are experiencing less growth and perhaps even a decline.