Because everything is cyclical, I’m back at trying to publish cringy content on YouTube again. This time: Short update videos for the apps I’m working on. The first one is not really short but it brings you up to speed with my current project: Placescore.
Tag: SwiftUI
Out now: Peat – A habit tracker app for iOS and iPadOS
Long story short: My habit tracker app Peat is out now. You can download it for free. I think it might be the best habit tracking app on the App Store but you’ll be the judge of that seriously biased opinion.

Some people don’t get why building habits is so important for a happy life. Here’s my elevator pitch for why you would want to go through the hassle of sticking to a habit:
It literally changes your identity.
You become a different person. Just by deciding to do something regularly, you’re suddenly a person that works out, that flosses daily, that reads a new book every month. It doesn’t matter who you want to become, the fact is that building a habit stands between you and your future identity.
I love challenging myself like that but the current choice of apps didn’t fit my needs. All of them are needlessly complicated or cramped full of gamification features like streaks. As you know: I hate streaks. They create needless pressure and destroy any form of motivation as soon as they break.

That’s why I build Peat. It’s basically a tally list on steroids. You do what you want to do, you check it off. Every completion gets a green square. Over time you see your progress through the amount of green squares in each month.
You won’t get punished if you miss a day. Who cares! As long as you come back to it and try again, you’re on your way.
Here’s a list of what Peat can do right now
- Reminders: Set a customizable daily reminder for each habit you don’t want to forget about.
- Statistics: Keep an eye on overall trends or dive deep into specific habits.
- iCloud Sync: No matter if you’re on your iPhone or iPad, you can check on your progress and mark new completions.
- Widgets: Slap your habits right where you can keep them in mind. See your progress right on your home screen.
- Currently available in English and German

Peat is free to download and use. Some features require a subscription though. I’m trying to become an indie dev here, so please bear with me.
Web development is a pain in the ass
I bought the limited early access to The Joy of React the other day and worked through the whole course since then. Switching to web development while still being at the very beginning of my journey of becoming a Swift developer might not be the smartest choice but I never claimed to follow a thought-through master plan in regards to my learning, so whatever.

Before we get started: These are my current thoughts on getting into web development as somebody who has only a basic understanding of HTML and CSS. These thoughts will be different in a year from now. Cool your jets and consider this as something like a user test for the question of “How accessible is becoming a web developer?”.
Web development is a pain in the ass. You need to understand what a terminal is, what it’s used for and how to use it to even get to the point of asking yourself “What the fuck is NPM?”. Then NPM needs to be installed which feels like hacking the Matrix, since it does something somewhere but you won’t see anything but lines of text in your little terminal window into the soul of your computer that you’re afraid to touch because what if you sudo your SSD or something.
Continue reading “Web development is a pain in the ass”How to bypass email verification
Turns out: When your sign up flow consists of users entering an email address and password you might want to verify that the person signing up actually owns that email address. Who would have guessed.
Since I’m using Firebase to build Goblin Mode I have a whole plethora of features and functions at my disposal that make this easily possible. In theory.
In practice I would have had to learn Firebase cloud functions to delete accounts without a verified address after a specific timeframe and that just wasn’t realistic. I’ll teach myself how cloud functions work when I start working on notifications.
Well, how to solve the issue of people being able to sign up with other people’s email addresses? You circumvent the whole thing by not offering email/password sign up at all.
Goblin Mode sign ups now use Sign in with Apple. Ethically it’s the only right choice if I want to even think about releasing the thing at some point. I’m not good enough at programming yet to say with conviction that I could build a confidence-inspiring login system any other way.
But that’s fine. This flow is surprisingly sleek and Apple even offers to hide people’s actual email addresses.
Oh and I used this opportunity to slightly tweak the whole onboarding experience. It’s not my greatest design work ever but it does the job.
Work in progress: Goblin Mode
A lot has happened since I shared these two posts about the project I’m currently working on. I figured it’s time to let you know what has happened in the meantime. Here’s the short version: I learned a lot. Like A LOT. This is my third app ever and it’s the one where a lot of previously vague concepts finally clicked. I’m injecting dependencies, juggle with types and create view models like there’s no tomorrow. It’s so much fun!

A couple of weeks ago I invited some friends to try out the app and see if the overall idea works. This was a huge moment for me. People signed up for something I programmed. They created literal user accounts saved to a database I connected to an app I coded. Crazy. It got even cooler after that: They started using the app. And somehow they didn’t stop. I’m not sure if they’re only using the App because they want to be nice but it feels like they enjoy sharing one-off status updates with a closed and private group of friends. No endless timeline, no fame, only letting people know what you’re up to.
Let me give you an overview of how the app looks like at the moment.

This is the main view. You see your own current status and how old it is. Below that you’ll see all current status of your friends.
I wrote the code for all of this like three separate times. The first two iterations didn’t care about the amount of database requests at all. They worked but they weren’t scalable. I’m now using Firestore realtime updates and it’s amazing. If a friend updates their status while you’re in the app, the status automatically gets loaded from the server and displayed on top of the stack.
But what happens when a friend hasn’t updated their status since midnight?

They become stale. I like the idea of having a predefined tabula rasa moment. Each day starts with a clean slate. If you post something one minute before midnight that status will only be fresh for one minute. Slightly weird, but I kind of like it.

Speaking of likes: I implemented a system to like status. It works well and is fun. I’ll probably replace it with a system to react with a tag, though. Liking feels wrong when a friend posts a status about them being tired, feeling empty or being sad. I want to be able to react to these with “🤡 Clown”.

There are more than 130 tags now. I built an admin area and support for admin accounts into the app and can CRUD tags and tag categories in seconds. New tags and categories show up on user’s devices without the need for an app update. It’s all in the cloud, baby!
I also build a system for tags and tag categories that are behind the paywall. My current idea for monetizing the app would be to put most of the cool tags behind a subscription of some kind. Those server bills need to be paid!

With the ever increasing amount of tags my friends asked for a tag search feature. That has been implemented as well. For those moments when you need to share your shower thought quickly.

And last but not least: I revamped the whole follow/unfollow system I talked about here. It became clear that asynchronous following isn’t the right concept for an app that’s meant for you to share semi-private status updates. Now there’s a whole screen dedicated to see who requests being friends with you. If you accept a request you become friends with the other person and you can both see the status of each other. If you cancel a friendship both ex-friends stop being able to see the respective status. Fair and easy.
I’m toying with the idea of limiting the maximum number of friends each person can have. Just to drive the point of the app home. That didn’t work out very well for Path back in the day but maybe times have changed. Who knows.
That’s it for now. I still don’t know if I’m going to release this to the public at any point. I’m still a novice coder and my implementation of everything related to Firebase has a big potential to suck. I’m generally cool with my code not being the best but in this case it could result in me racking up an enormous Firebase bill. That would not be fun at all.
As I said: Who knows. I might find a way to limit the app features enough to let people try it out without me becoming poor while allowing people to pay to cover the database costs. It sure would be an interesting problem to have.
Do you feel like there’s a Goblin Mode shaped hole in the lives of you and your friends?
Uploading, fetching and async-awaiting
I’m having the time of my life over here. Without getting too much into what my next app will be: Look at this! All the data gets fetched from Firebase. Creating a new tag uploads it to firebase. The categories are documents in Firebase as well. The view showing categories and tags together is based on an array of objects that combines both. I’m juggling with data!
I wouldn’t have been able to do any of this a couple of months ago. We’re looking at a logged in user, authenticated through email and password, that has an isAdmin
flag set to true
. Only admin users are able to see the tag management section and are able to create new ones.
Databases! Optionals! ViewModels! Aysnc/Await! Everything comes together.
This is so much fun that I have to force myself to stop working to get a good night’s sleep.
“How fucking slick is that?!”
Some of you might have guessed it: I’m a big fan of the internet. The simple fact that I could work through this amazing seven(!) hour video about SwiftUI and Firebase by Stephan Dowless for free is still mind-blowing to me. It is free knowledge. Potentially life-changing information just lying around on the internet and all you have to do is consume it.
Stephan is an incredibly enthusiastic instructor who made the time fly by. Even though he obviously doesn’t do this for the first time, he still bursts out stuff like “How fucking slick is that!?” all the time. I felt thoroughly entertained. This is easily one of the most helpful courses I’ve worked through.
I know now that Firebase is the way to go for what I’m currently looking for. The course went through the whole process of building a low-tech Twitter clone. From signing up to fetching data from Firebase to storing images and writing and liking tweets. Not only do I now understand the basics of Firebase (and how to work with databases in general), I also got a better insight into how slightly more complex apps are supposed to be structured. MVVM is easier to understand when applied to a project with a certain complexity. I didn’t get it when other people tried to explain it with simpler examples.
This was very well invested time and I feel like I’m ready to start my next project. Something with databases! On the internet! How exciting!
All your databases are belong to us
Currently I’m spending most of my programming time learning new things instead of actually building something. My next project should include technology I don’t know anything about yet. I’d love for it to be something that’s online.
Building little apps that store data on your device is cute and everything but for me the magic lies in stuff being on the internet. Unfortunately I don’t yet know anything about how databases work.

I stumbled upon Swiftful Thinking, a YouTube channel explaining Swift and SwiftUI topics in a way that resonates very well with how I learn. His videos taught me that CloudKit is exactly what I was looking for. Who would have thought that that’s a database solution from Apple that I’m already paying for? I know how to connect an app to CloudKit, how to put data in a database and how to fetch it again. I even know what CRUD stands for. Look at me, knowing my acronyms.
Continue reading “All your databases are belong to us”Lost in Localizable.strings
Update: Somebody actually solved my issue. Internet is great. Scroll down to see how this is fixed.
When I wrote about the couple of problems I don’t know how to solve in Stoins, I didn’t anticipate to quickly run into the next one. Stoins is supposed to be available in English and German. With English as the default, I set out to add German translations and watched a couple of tutorials on how to do so.
It’s relatively straight-forward.
- Create a Localizable.strings file for every language you want
- Xcode finds all translatable strings automatically and you translate them one by one
- Done
Unfortunately that’s not exactly how it went. Most strings were found, sure, but those outside of Text()
views weren’t and I don’t understand why or how to force Xcode to translate them.
An example
Take everything with a grain of salt. I don’t know what I’m doing. I’m that much of a beginner that we can just accept the fact that literally anything I do can be done in a better way. For now my main goal is for stuff to just work. I don’t want to win any prizes for great code. Yet.
This is an object in Stoins. It’s the blueprint for an achievement:
struct Achievement: Identifiable {
let id = UUID()
let name: String
let description: String
let image: String
let badge: String
var conditionAchieved: (() -> Bool)
}
I have an array of objects like this that I use to create the interface. The array looks a little like this:
@Published var achievementsStreaks = [
Achievement(name: "Fortnight", description: "Have a 14 days streak", image: "badge_fortnight", badge: "badge_fortnight.gltf") {
var result = false
// Code that defines if 'result' is true or false
}
return result
},
// Second Achievement
// Third achievement
// etc
]
(I’m a bit proud of my use of closures here, ngl. They were very brain-breaking for me and now I’m able to use them without hurting myself in confusion.)
So far, so good. All of this works surprisingly well in terms of how the app is supposed to behave. The only remaining problem is that I can’t seem to figure out how to localize the name and description. Xcode doesn’t manage to automatically find the name
and description
attributes and when I add them manually to Localizable.strings
nothing happens.
I thought I found the answer in this WWDC video about localization in SwiftUI but using LocalizedStringKey
only works for views not structs, it seems.
For now I’ll leave it as it is. Only the about screen and achievements are affected which means it’s not an app-breaking issue for those who don’t speak English. Not great. Not terrible. A solid 3.6.
Still, I’d love to publish an update to this post where I explain how somebody helped me solve this and how it was a very easy fix. If that’s you, hit me up. There’s a very cozy comments section down below.
Update: As expected the answer to this couldn’t be more easy, I just wasn’t able to find it. Thanks Philipp for pointing me to this article. And thanks Bei Li! Every user facing string needs to be wrapped in String(localized:"")
. That’s it. Everything works now. lol.