Today, I have been doing multiple things:
Today, I added a button to start a new game after the game is over.
Additionally, I changed the calulcation of whether someone reached a new record. The previous implementation was irritating even to myself. Beforehand, I counted a level as new record when the level was done, i.e. you reached level 3 and entered the correct sequence. Now, I consider a level as a new record when it was reached even if the user enters the wrong sequence.
Regarding new records, I added an animation when a new record was reached to make it more noticeable to the user.
Today, I implemented displaying a cross when the entered user sequence differs from the generated one and playing a sound. Looking for a nice sound took some time. And my Android emulator didn't want to play sounds. When I started it from Android Studio it did but after that it didn't work anymore. I remember having this issue beforehand but I don't remember what the solution was. Next time I solve this issue I need to write it down.
Today, I tried to generate images for my spot the difference app. The first image was awesome whereas the following were completely different and didn't look as good as the first one. In the evening, I was able to generate some other good looking images. There is still a lot to do for me here.
Today, I finished working on the screen for the in-app purchases and the result looks somewhat okay, I would say.
Additionally, I noticed that I did not set up react-native-vector-icons for Android properly and fixed that such that the icons are displayed now on Android as well.
Today, I was reflecting a bit about the progress I made this year. My plan was to release 4 apps this year. As of now, none is released. This dragged me down a bit because 4 months are already over and I have no visible progress. But then I thought a bit more:
Taking this into account, my first 4 months don't look that bad. I made some progress, had some learnings and am on my way of releasing my next app π
Today, I started working on the screen for the in-app purchases. I explained what the additional modes contain and tried to arrange the content properly.
Today, I have been working on the localization of the app, mainly. Luckily, I wrote down the exact steps when doing the localization for Math Experts and therefore, doing it again was a breeze π
Today, I added a green checkmark which pops up when the sequence entered by the user is correct.
Today, I have been working on better app store titles, subtitles, and descriptions of my app Math Experts in all 5 supported languages. By doing so, I hope to increase traffic and sales of my app.
Today, I have released version 2.4 of Math Experts. The release includes the new times tables mode as well as localized names of the app. I localized the app name because I assume that users search for apps in their mother tongue. Therefore, localized app names could increase traffic and maybe sales as well.
Creating the release took a lot of time today, because I got an email from apple stating that my release contains issues ("ITMS-91053: Missing API declaration"). I needed to do some investigation to figure out what this means and which options I have. I started by googling for my issues and from that investigating the sources of the libraries I use to figure out where the issues come from. I doubted everything: I doubted to be a good software developer, I doubted that I could solve these issues, and I doubted that I could release any new app. In the end, I added the necessary PrivacyInfo and gave reasons for using the specified APIs. As the reasons were pre-defined, I just had to understand the possible reasons and chose the most appropriate ones.
Today, I have prepared the next release of Math Experts. I have enhanced the app store description texts for all languages I support (English, German, French, Spanish, and Portuguese). It was a lot of work. I needed to come up with texts describing the new times tables feature and finding proper translations which hopefully make sense. Additionally, I re-arranged the texts in the app store descriptions to make clear why the user should choose Math Experts. To emphasize why Math Experts is a good choice, I added texts stating that Math Experts is a safe learning environment because it does not show adds and that I take privacy into account by storing the data on the user's phone only.
While I was on that I decided I could try giving the app a localized name. I hope that this increases the visibility of my app in the app stores assuming users search for apps in their mother tongue.
Today, I did several things:
I aligned the menu buttons of my Simon Says game and improved the overall look
I fixed a bug with the user input sequence. Somehow, the input user sequence always had a max length of 1 which made it impossible to go beyond level 1. It was already working at some point but somehow I broke it π
I replaced the usage of TouchableOpacity with TouchableWithoutFeedback and when the user clicks on a TouchableWithoutFeedback, the clicked monster is scaled like it is scaled when the generated sequence is played. By doing so, I learned that TouchableWithoutFeedback does not accept styling or layout props and I had to wrap the content of the TouchableWithoutFeedback into a View.
Before:
<TouchableOpacity
disabled={!isUserTurn}
onPress={() => addToUserSequence(3)}
onPressIn={() => setCurrentlyPressedMonster(3)}
onPressOut={() => setCurrentlyPressedMonster(undefined)}
style={{
width: iconWidth,
height: iconWidth,
}}
>
<Image
style={{ width: "80%", height: "80%" }}
source={require("../assets/monsters/monster003.png")}
resizeMode="contain"
/>
</TouchableOpacity>
After:
<TouchableWithoutFeedback
disabled={!isUserTurn}
onPress={() => addToUserSequence(3)}
onPressIn={() => setCurrentlyPressedMonster(3)}
onPressOut={() => setCurrentlyPressedMonster(undefined)}
>
<View
style={{
width: iconWidth,
height: iconWidth,
}}
>
<Image
style={{ width: "80%", height: "80%" }}
source={require("../assets/monsters/monster003.png")}
resizeMode="contain"
/>
</View>
</TouchableWithoutFeedback>
Today, I introduced colors assigned to each monster and when a monster is played within the generated sequence, the app displays the color of the current monster as well making it easier to remember sequences. Additionally, I decided to check for a new record after each round because the user might click on the 'Back' button and I want to ensure storing the current record properly. Now that I think about it, I might do so when clicking "Back" as well. Might be that I change it again because it might be inefficient to check for a new record after each round π¬
Today, I added a nice radial gradient to the circle around which the monsters are positioned.
Today, I implemented changing the background color of the circle around which the monsters are positioned to the color of the monster currently being played within the generated sequence.
Today, I played around with fonts for my app. That's a task I really don't like that much but it needs to be done anyways. To have some fun after that, I implemented storing and retrieving records per difficulty level.
Today, I disabled the monster buttons after successfully checking for the sequence match. This means that while a sequence is played, ddthe mosnter buttons cannot be clicked. For playing the initial sequence that was already the case but I forgot to disable the monster buttons after each round.
Today, I have been working on playing the generated sequence, visualizing it, and recognizing user input. I am proud of some of my implementation decisions. The flow is as follows: a level is defined (1 when starting the game), a sequnece is being generated, and the sequence is being played. Instead of calling a playSequence
function right after generating it, I implemented two useEffect hooks:
// generate sequence
useEffect(() => {
setSequence(generateSequence(level, difficulty));
}, [level]); // intentionally leaving out difficulty
// play sequence
useEffect(() => {
//
}, [sequence]);
Earlier, I would have tried to execute playSequence
right after setSequence(generateSequence(level, difficulty));
:
// generate and play sequence
useEffect(() => {
setSequence(generateSequence(level, difficulty));
playSequence(sequence);
}, [level]); // intentionally leaving out difficulty
but as state variables ar set asynchronously (i.e. not updated directly) in react native, this might have caused problems. So I think my solution is pretty good and from that I see some improvements in understanding react native π
Today, I started working on my brand new project "Monsty: Simon Says". I created a basic main menu and a game view featuring 3 difficulty levels. Most of the time I spent aligning the monsters around a circle. I think the app still looks shitty. Let's see where it goes.
Wow, I didn't write in the recent past. What happened since I stopped posting? I paused working on Monster Friends Forever since I figured out that it's a very large project. As I am currently not earning any money with my apps, I decided to work on smaller apps which can prove to me that I am capable of earning money with my apps. During the past 3 months, I have been working on two apps. One has been paused for now because the assets would be a huge investment ($300) which I am not willing to spend at the moment. Before spending $300, I want to see that I can earn money with other apps. Then I started working on a sudoku app. My idea involves more thinking and therefore I postponed this app as well. So here I am, sitting in front of a clean project. It's a nice Simon Says app for kids featuring the Monster Friends. Let's see where this goes π
Today, I finally managed to center the view containing the present the user gets once a day per monster. In react native it's not possible to center using top: 50%, left: 50%, transform: translate(50%, -50%)
because you cannot specify percentage values for the transform properties. I managed to get the view centered after learning about the onLayout prop which allows you to dynamically calculate the view's dimensions and adjust the transform values accordingly. I used the following code:
const [layout, setLayout] = useState({ width: 0, height: 0 });
const onLayout = (event) => {
const { width, height } = event.nativeEvent.layout;
setLayout({ width: width / 2, height: height / 2 });
};
<View onLayout={onLayout} style={{ position: 'absolute', top: '50%', left: '50%', transform: [{ translateX: -layout.width },{ translateY: -layout.height }] }}
...
</View>
I am still working on giving the user a present once a day per monster. Today, I have been adding the library react-native-sound
to play a sound when a present has been received. This library is easy to integrate and works pretty well.
Additionally, I wasted a lot of time on an assumed "app starts with black screen" error. It took me a while to figure out that the background on my phone was just black whereas it was white on the simulator. As it was working on the simulator, I have been assuming that it would be the same on my phone. The reason was: My phone was in dark mode whereas my simulator wasn't π
While my daughter and my husband were playing Math Experts in two-player mode, they noticed that multiplication equations were generated seldomly. The reason was that if you set the "Calculate up to" property to e.g. 20, the generated factors could be between 1 and 20. Of course, it's very likely to have a result above 20 when multiplying and allowing factors up to 20. In such a case, a new equation would be generated because the "Calculate up to" constraints could not be met. But: I did not ensure that an equation of the same type would be generated. This resulted in multiplication equations not meeting the constraints often and generating other equations in this case, i.e. addition, subtraction and division equations being genrated more often than multiplication equations.
I needed to change two code parts to solve this issue. For multiplications, I don't allow factors up to "Calculate up to" anymore but instead I calculate the square root and round down, i.e. Math.floor(Math.sqrt(maxNumber))
. Additionally, I remember what the chosen equation type was and generate another equation of the same type if the constraints are not met.
Since I persisted the item state after feeding yesterday, I implemented persisting the monster state after feeding today.
To be honest, I thought this would be a quick one. Unfortunately, it wasn't. There are several reasons for this.
Firstly, I did not know that the spread operator creates a shallow copy instead of a deep copy. When changing a deep copy of an object, the underlying object won't be changed. In contrast, when changing nested objects in a shallow copy, the source object is changed as well. This took me a while to figure out. But, I learned something which is great.
Creating a shallow copy of an object in JavaScript:
const copy = { ...sourceObject }
Creating a deep copy of an object in JavaScript:
const copy = JSON.parse(JSON.stringify(sourceObject))
Secondly, I forgot to change the monster param of the component after feeding which led to the monster state not changing. This took some time to figure out as well.
Today, I implemented retrieving the user's items, display the amount of foods, and started implementing the feeding mechanism.
Retrieving the user's items and displaying the amount of foods were straight forward and done within a few minutes.
Implementing the feeding mechanism was not that easy. In short: I needed to figure out how to reduce the used food by one. Just using food.quantity--
was not working because this would modify the state of the component directly which lead to an error (You attempted to set the key "quantity" with the value "999" on an object that is meant to be immutable and has been frozen.
). The error meant that I was changing an object which is a parameter of the component, the list of items, which is not allowed. Instead, I needed to use food.quantity - 1
. It took me a while to figure that out.
As the items were changing their order with the working implementation, I wanted to sort them. The foods will be sorted by aggregated state improvements in descending order. For that, I copied code from the existing project. I did not understand my old implementation in the first place and made some mistakes here and there until I got it working.
In the previous session, I implemented authentication. This time, I focused on retrieving the user's actual monsters, replacing the previously mocked ones. While working on this, I noticed a bug in the monster, platform, and background mappings which I fixed directly. In short: the wrong monster, platform and background have been displayed.
Today, I have been adding Firebase Authentication to Monster Friends Forever. I implemented the logic for signing in and out plus a very ugly login screen. Of course, I will improve it in one of my next sessions.
Today, I have been changing the equation generation algorithm of Math Experts such that the same equation is not generated consecutively. Additionally, I removed the 'lost' modal to avoid demotivating the presumably young players.
Today, I have been changing the equation generation algorithm of Math Experts such that divisions by 1 and multiplications by 1 are not generated when the 'Calculating up to' setting is set to greater than 10. 'Calculating up to' is a setting which defines what the largest result of equations should be. For smaller numbers these equations need to be allowed because e.g. for 'Calculating up to' being set to 3 there isn't a division which gives an integer as a result. For numbers larger than 3, the equation generation would work but we would have a very limited amount of possible equations, e.g. for the value 5 we would only have the following possible divisions which would result in an integer: 2:1, 3:1, 4:1, 2:2, 4:2, 4:4 (if I'm not mistaken).
Today, I have been working on opening the feed and play menu in Monster Friends Forever. The feed menu contains the user's items and in which way each food will affect the monster's state.
Today, I have been adapting the borders between happiness, repletion, and love levels. Additionally, I have been doing some cleanup on the project. I mean, come on, it's December 31st π¬
Today, I have been adding navigation to the project. The user now can navigate from the monster overview to a specific monster to interact with it. The monster view contains the monster and its state of happiness, repletion, and love.
I have been setting up a new project: Monster Friends Forever. It's not completely new. I created this project last year using VueJS. It is available via https://monster-pets.com/. I want to convert it to a mobile app now.
Today, I have been creating the monster overview and the header containing the menu items.
Yesterday evening, I opened the YouTube Studio app since a long time. It felt good to see that I have 20 subscribers. I checked out some videos I created about vim. They are really bad but I still felt proud about them. I think I want to continue YouTube on the side. On the side of my side project of becoming a successful app developer while working a full-time job as a software developer π It's some additional work but I think it's worth it. I benefit from it by learning new things and going beyond my comfort zone and others can benefit by getting some knowledge from my blog posts and videos.
Today, I finished taking all screenshots for all languages for Android devices. Version 2.0 of Math Experts has been released now π€©
Today, I started taking screenshots of the Android version of Math Experts. I said "I started"... I figured out that the new settings screen did not look good on the 7'' device, I used to take screenshots on. I fixed the issue but could not finish taking all necessary screenshots.
Today, I finally managed to make the Math Expert screenshots for iOS. I added them to App Store Connect, added the release notes, and release Math Experts version 2.0 π₯³
Today, I sat down again with some music and went through the tidious task of taking screenshots for 5 device sizes and 5 languages. When I was done, I was pretty happy with the results. I wanted to add the screenshots to the app description but then App Store Connect told me that the screenshots do not fit the expected size. Noooooooo π±
What did I do wrong? I just looked at the little icons which are displayed in App Store Connect and started one simulator with a screen like this but did not have in mind that the device I chose might have another display size.
I tried some solutions to resize the screenshots to the needed size but was not successful.
Now I figured out which devices I need to use to get the necessary screen size:
I guess I need to continue with this tomorrow again. Yay! π¬
Today, I planned to create screenshots of version 2.0 of Math Experts. Since the UI changed and improved a lot, I thought the screenshots should be updated. So I sat down with some music and started creating the screenshots. When I came to the French version, I noticed that the translation for "practice mode" is longer than for the other languages. The text of this button is wrapped and was not centered anymore and so I fixed this. Then, I noticed that I forgot to add the translation for "back" for Portuguese and added this as well. After that, I noticed that the translations for high score for French, Spanish, and Portuguese were not that good and I changed them as well. Noticing all these little details took some time and slowed down taking screenshots a lot. So I just took a few and have to do a lot tomorrow (all languages for 3 iPhone and 2 iPad sizes).
Today, I have been aligning some styling in the settings view. This was a quite tidious task because I had to take a close look that everything is aligned properly and that it looks good. It took some time and I am happy with the result.
After that I still felt like doing something and had a look at an issue which bothered me for a while. I was not able to localize the back button label in iOS. When displaying a back button label on iOS, the title of the previos screen is shown. I disabled the header of the main screen because it is not needed for my app. This lead to the situation that I was not able to set a custom header title which could be used when being in the settings view for example. The screen always dispalyed "back". As my app is localized, I wanted it to display "back" in the language of the user. So I googled the issue again and this time found an issue in the react-native-screens GitHub repository. The issue was just slightly related but in the thread the version with a fix for the reported issue was mentioned. I decided to give it a try and to upgrade my react-native-screens and @react-navigation/native-stack. And it worked!!! I am so happy to have a localized back label now π€©
Recently, I was pretty sure I identified a memory leak which has been introduced with adding some numbers to the menu screen. Today I investigated the issue. It turned out that I have an array of numbers and animations which get bigger and bigger because numbers and animations which are not needed anymore are not removed. I thought I would remove unused elements from the array but the code didn't work as expected, so I changed the code such that numbers and animations are removed from the arrays when animations are done. From what I can see now, the memory leak seems to be fixed.
Today, I have been working on adding a setting to (de)activate sound. Besides that, I changed the styling of the headings in the settings view.
Today, I worked on simplifying the settings of Math Experts. Until now, Math Experts had 2 settings for numbers: The max number allowed in equations and the max result allowed. I don't know what I had in mind when programming this but I thought, I could reduce this to one setting being the max number allowed. So today I removed the max result allowed setting, adapted the code accordingly and removed unnecessary tests. I think this improves the app's usability a lot π
Today, I extracted some duplicate stylings into an own file and changed some minor stylings like spacing. Not much to say today π¬
Today, I continued working on the new game menu. I styled the game menu buttons and placed them at the bottom because this is best reachable on a phone. The upper half of the screen looked somewhat empty. Therefore, I decided to add some numbers which are moving from top to bottom. This is the resulting new game menu screen:
Until now, the game menu was displayed along with the single player game view. While making Math Experts more responsive, I figured that when I leave the game menu below the single player game view, the single player game menu increases in height when the game menu is closed. To avoid this, I decided to extract the game menu into an own view. That's what I did today.
In general, Math Experts works pretty well. My daughter loves using it after school, too. That makes me very happy π
I noticed that for the iPhone 7/8 my daughter uses, the UI is not as it should be. There are components overlapping. I tested my app on multiple simulators and I don't know exactly, how I messed it up. Anyways, when I started creating my app, I did not make it really responsive. I used fixed widths and heights, for example. Over time, I reduced them and I think now it's time to make the app really responsive πͺ
Today, I started this process by using flexbox wherever needed to make the buttons and their containers grow/shrink depending on the device size and the available space.
From this | To this |
---|---|
Today, I learned that there is a command to upgrade React Native easily: npx react-native upgrade
so I upgraded to the latest React Native version.
Since the last upgrade I have issues that logs are not shown and fast refresh is also not working anymore. I could not figure out the change that caused this issue but today I was able to figure out what I need to do to have logs and fast refresh being enabled again: In project.pbxproj
I need to set buildConfiguration
to "Debug". Then I can start Metro using npx react-native start
and start the app in iOS using: npm run ios
. Unfortunately, the version which is deployed to my iPhone is not working in this case. For this, I need to set the buildConfiguration
back to "Release". In the iOS simulator it is not working in the beginning as well but after a refresh of the app. It's still not perfect but better und usable.
Since my app works like this:
and not like this:
I needed to find a way to show the user that the result is correct. If the user had to confirm the result by pressing a button, I could let the numbers shake if the result is wrong. I decided to display a checkmark after the result if the result is correct.
Currently, I am thinking about adding a button the user has to press to confirm the result. I think in this case, the checkmark could stay but as mentioned earlier, I could let the numbers shake when the result is wrong.
My daughter is in 3rd grade now. They are calculating until 1000 at the moment. She told me that she wants to calculate until 1000 using Math Experts but it takes so long to increase the numbers. She had to hit the button for each increase. There is room for improvement, obviously.
I used the onPressIn and onPressOut events. When the user presses a button, I start an interval increasing/decreasing the corresponding number.
const setMaxNumberHold = (val: number) => {
let tempMaxNumber = settings.maxNumber
timerMaxNumber = setInterval(() => {
maxNumberLongPress = true
let newMaxNumber = tempMaxNumber + val
if (newMaxNumber < 3) {
newMaxNumber = 3
}
if (newMaxNumber > 1000) {
newMaxNumber = 1000
}
tempMaxNumber = newMaxNumber
setSettings({ ...settings, maxNumber: tempMaxNumber })
}, 200)
}
When the button is released, the onPressOut event is triggered. In this case, I clear the interval and store the new value in the settings such that this change is preserved for future use of the app.
const stopTimerMaxNumber = () => {
clearInterval(timerMaxNumber)
updateSettings(settings)
}
Of course, there is still the possibility to increase/decrease numbers by 1 by pressing the button once.
function setMaxNumber(val: number) {
if (maxNumberLongPress) {
maxNumberLongPress = false
return // don't increase if button was pressed long
}
let newMaxNumber = settings.maxNumber + val
if (newMaxNumber < 3) {
newMaxNumber = 3
}
if (newMaxNumber > 1000) {
newMaxNumber = 1000
}
const updatedSettings = { ...settings, maxNumber: newMaxNumber }
updateSettings(updatedSettings)
}
Here is an example usage of this functionality:
<TouchableOpacity
onPressIn={() => setMaxNumberHold(-10)}
onPressOut={stopTimerMaxNumber}
onPress={() => setMaxNumber(-1)}
>
<Text>-</Text>
</TouchableOpacity>
Today, I told my daughter to practice some subtraction problems using Math Experts because she really needs some practice here.
So she sat down and started practicing but at some point, some early point to be honest, she had equations like "23 - 23" and she typed "0" which is correct, obviously, but Math Experts did not accept this as the correct answer. We sat down and gave it some more tries and really often we got equations which should lead to zero as the result but zero was not accepted. Obviously, there was a bug in the subtraction equation generation.
Of course, I sat down because I really wanted her to practice some subtraction problems. I had the following code:
expectedResult = Math.max(num1, num2) - Math.min(num1, num2);
num1 = Math.max(num1, num2)
num2 = Math.min(num1, num2)
...
equation = `${num1Formatted} ${subtractionSign} ${num2Formatted} = `
After some close looks, it was clear to me that this cannot work as expected. The expected result is calculated correctly by subtracting the minimum from the maximum of the two numbers (line 1). But after that, I assign num1
to be the maximum of num1
and num2
(line 2) and in line 3, I want to assign the minimum of num1
and num2
to num2
. This might work in some cases but not in every case. Let's say num1 = 3
and num2 = 5
. By executing num1 = Math.max(num1, num2)
, num1
will get assigned 5. In line 3, I want to assign the minimum of num1
and num2
to num2
BUT now num1
is 5 and num2
is 5 as well. So the maximum and the minimum are the same now leading to the generated equation being 5 - 5 and the expected result being 2 in this case because it was calculated before this mess.
The corrected version looks like this:
[num1, num2] = [num2, num1] // swap numbers using array destructuring
expectedResult = num1 - num2;
...
equation = `${num1Formatted} ${subtractionSign} ${num2Formatted} = `
Of course, I implemented proper tests to ensure that for all operations everything works as expected now and in the future. You can do a mistake once but shouldn't do it twice βοΈ
Fun fact: For addition, I did everything correctly π¬
I really need to keep in mind to have an iPhone and an Android emulator running at the same time. Yesterday, I just did the react native upgrade changes for iOS. I remember thinking "let's do it for iOS first and see if it works and then do the changes for Android" but I totally forgot about the Android changes after everything was working. Shame on me π
Now, everything is working for Android and iOS π
Today, XCode was updated automatically. And of course, nothing was working anymore. I got an error message like "The iOS Simulator deployment target 'IPHONEOS_DEPLOYMENT_TARGET' is set to 11.0, but the range of supported deployment target versions is 12.0 to 17.0.9". At some point I had the idea to try to upgrade react native. I didn't do this for a while because I think this is annoying and I try to avoid such updates as long as I can. Now I couldn't avoid it any longer and needed to face my fear π
Updating react native using the React Native Upgrade Helper did the trick and now everything is working again π
Today, I continued with searching for a library which can play a sound for me. I tried out react-native-track-player and react-native-audio-toolkit.
The react-native-track-player library is a bit too much for my use case of playing a sound. I think I figured out that this library uses the audio player of the phone. In my case, the song I listened to on Spotify before trying out my app with sound was kind of "removed" aka I could not continue listening to it.
With react-native-audio-toolkit I was not able to play a sound at all. The callback of the play function said that it was playing but I could not hear something.
I decided that I could give react-native-sound another try. And I am so happy I did π
Regarding the issues I had last time:
I think it would be great if the user got some sort of feedback when a result is entered. It happened multiple times to me that I entered a result and was wondering why no new equation is generated. Until I realized that my result was wrong π
The app does not require the user to confirm the result by pressing a button but instead is checking the result time-based, currently. This robs me of the possibility to add a shake animation when the result is wrong because sometimes you have to insert multiple numbers. Obviously, I wouldn't want to let the result shake when the user is still typing. This would be similar to these forms which are marked red when you start typing. As you can see: I love them π
When thinking about a possible feedback for the user, I came up with the idea of playing a sound when the result is correct. So I checked out the available React Native libraries to play sounds. Today, I started trying out react-native-sound. The setup was well described in the README. But: I figured out that
My conclusion is that I will try another sound library next time. If I cannot find a sound library which fits my needs, I need to find another way to give feedback that the result is correct.
My daughter came up with a feature request π
She said that she feels under pressure when she is playing against the time. So she asked for an endless mode without time. I thought that this was a great idea and I wouldn't be super mom if I wouldn't implement this feature right away π¦ΈββοΈ
So I sat down this evening and implemented the practice mode. Most of the functionality was already there (generating equations, checking for the correct result, ...) so the devil was in the detail here. I needed to disable the timer, introduce a button to stop practice mode, re-arrange the menu because it got longer, and needed to find a way to display the "record" of practice mode in the records view. But I got it working within 2 to 3 hours. And the result is really nice π
Today, I was fixing bugs in switching to dark mode. The app headers did not change for the "Records" and "Settings" sections when switching from light to dark mode. Additionally, I added my icons in a dark color scheme to fit the overall appearance when the app is in dark mode.
Header beforehand | Header afterwards |
---|---|
Much better π
Ok, enough with procrastinating what needs to be done! Today, I continued working on my app Math Experts. I introduced a dark mode color scheme. Finally! :)
As I figured out last time, working on my website is fake work for me. So, what did I do? Of course, I continued working on my website! π
Today, I implemented the un-collapsing of the latest month as a default when opening the page. The other months are collapsed by default. I made the transition between collapsing and un-collapsing smooth.
Today, I read Ali Abdaal's newsletter where he wrote about "Real Work vs. Fake Work". He wrote that real work is the work that takes you towards the things that actually matter to you whereas fake work is everything else you spend your time βworkingβ on. I have been thinking about what real work and what fake work is for me. My goal is to earn money with my mobile apps so working on apps and ideas for apps is real work for me. Fake work is working on my website, thinking about YouTube videos I (could) create. I don't plan to earn money with my blog and my YouTube channel. As a result, I think I should really focus more on my apps and don't invest that much time in my website or YouTube channel.
Today, I added a buymeacoffee button to the end of each of my posts. I mean, you know how it works: Coffee is essential for a software developer to function properly. Without coffee, we cannot produce code, blog articles, or YouTube videos. If you like my content and would like to show your support, then feel free to buy me a coffee or two. Your support is greatly appreciated!
When working on my website during the last days, I had a lot of fun and decided to further improve my website. Today, I added a 'published' attribute to my posts to make it easier to filter for published posts. All posts which have the 'published' attribute set to 'true' are published and can be displayed on my website. This is just an internal feature but it makes it easier for me to set an article to 'published' state. While updating my posts, I discovered that for some posts I forgot to set the 'alt' attribute of images and updated this as well.
Today, I converted this page to use markdown files for the content. The first two posts have been written in HTML but I figured that it would be better to have them separated into their own markdown files to have the possibility to add tags and later on the possibility to filter for a specific tag to have only the posts displayed which belong to a certain topic.
Today, I read about SEO and as a result worked on the SEO of my website:
My husband and my daughter played Math Experts on my mobile phone. It was obvious that their hands were interfering, making it hard for them to hit the intended buttons.
To address this, I decided to introduce some spacing between the player areas. The resulting layout looked nice on iOS but when running the app on Android it looked awful. Additionally, some elements were not visible.
I need to dig deeper into how to create layouts which are really responsive. My assumption is that I should not use fixed widths and heights. Although I tried to make these values dynamic by converting them depending on the screen size, it still seems not to be working.
During my research I read that just using flexbox and no width and height values (fixed or dynamic) at all might be sufficient. I want to give this a try but can imagine that on tablets, icons might get really big. I am not really convinced by this approach. Let's see how it turns out.