Stack Overflow Keycap Reward

My tiny reward from Stackoverflow arrived yesterday, a small single keycap. I won it when I answered their Saved the Day story. I did not remember when, it was a long time ago.

Initially, I told them to not even bother shipping a small item overseas, the Philippines' Customs are not worth the trouble.

But they insisted. Thanks!

r/BusinessPH will be going dark

The sub r/BusinessPH will join the Reddit blackout on June 12 - 14, 2023, this is in solidarity with developers of third-party clients who will have to pay a hefty price for access to Reddit’s APIs.

For more details, you can read it here.

As a mobile developer myself and an Apollo app user, I feel and understand very well their current plight. If you have any questions, or comments don’t hesitate to contact the mods.

dSYM workaround in Xcode 14

Starting with Xcode 14, Bitcode has been deprecated. So, in our team’s case, it is impossible to download dSYM files for debugging crash logs. If you are using Crashlytics or Bugsnag, this is a requirement to make sense of the received crash logs from iOS.

But there is a workaround. Previously, all you have to do was go to App Store Connect and download the dSYMs directly from there. But that option is not available anymore.

But there is a workaround.

Workaround

Open the Window organizer in your Xcode and go to the Archive option and right-click on a particular build. Then, select Show in Finder option.

You will see files with .xcarchive extensions. Right-click on one of those and select Show Package Contents. There you will see a dSYMs folder. It should contain the dSYMs file needed for your debugging.

Underwhelming Google I/O 2023

After watching half of the Google I/O Keynote, I had to close the video because it was starting to bore me. There was no excitement for me, AI/ML is a topic I am not interested in. I took notes of the keynote while watching, and I just wanted to publish it here for keepsake purposes.

Google IO 2023 Notes

Keynote

  • So many AI/ML keynotes and features. Not interested. Bard? Does not interest me.
  • Bard is available now in 180 countries. Philippines?
  • Why would I like to edit photos? It seems fake.
  • Help me write. Nice, now spams will feel more real.
  • There is gonna be AI also in Google Search. Does this means I don’t have to concatenate “Reddit” in every search query?
  • AI on Google Cloud. Of course. Google AI.
  • AI on Android.

Stuffs to check out

  • Android design hub: UI Design  |  Android Developers
  • Download Android Studio beta**

SwiftUI Tap Anywhere

Today I learned how to implement tap anywhere to dismiss the keyboard on SwiftUI.

In your parent stack, either VStack or HStack, add the following code.

1
2
3
4
.contentShape(Rectangle())
.onTapGesture {
     UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
}

The most important thing to take note here is the contentShape modifier or tap gesture will not work.

YouTube Coding

3 days ago I uploaded on YouTube my coding in SwiftUI, working on a couple of simple bug fixes for my hobby project.

My wife gave me this idea and also I remember I have some coding sessions in Loom from 2 years ago, where I did a coding demo for a client. And, looking back at those videos is really cool and nostalgic.

So, I decided why not upload it on YouTube.

Chess Milestone

I achieved a very rare milestone last night. I had a 10-game winning streak in a “Champions” Division. I am not entirely privy to the division but I am pretty sure this is not a beginner’s division.

My new routine for the past several months is to play a couple of chess games before going to sleep or after putting our son to sleep at night.

And I am also currently no. 1 as of last night.

Xylophone App

In roughly an hour or two, I created an iOS app for our son who loves playing his Xylophone. I came upon this old repo for inspiration and reference. This was still developed using Storyboard and UIKit. So, I set out to write my own using SwiftUI.

I also borrowed their sound files. The owner of these files belongs to them.

The code looks like this initially.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
//
//  PlayerView.swift
//  Xylo
//
//  Created by Lawrence Gimenez on 4/23/23.
//

import SwiftUI
import AVFoundation

var audioPlayer: AVAudioPlayer!

struct PlayerView: View {
    
    var body: some View {
        VStack {
            Button(action: {
                play(sound: "C")
            }) {
                Text("C")
                    .foregroundColor(.white)
                    .frame(maxWidth: .infinity, minHeight: 90)
            }
            .background(Color.red)
            Button(action: {
                play(sound: "D")
            }) {
                Text("D")
                    .foregroundColor(.white)
                    .frame(maxWidth: .infinity, minHeight: 90)
            }
            .background(Color.orange)
            Button(action: {
                play(sound: "E")
            }) {
                Text("E")
                    .foregroundColor(.white)
                    .frame(maxWidth: .infinity, minHeight: 90)
            }
            .background(Color.yellow)
            Button(action: {
                play(sound: "F")
            }) {
                Text("F")
                    .foregroundColor(.white)
                    .frame(maxWidth: .infinity, minHeight: 90)
            }
            .background(Color.green)
            Button(action: {
                play(sound: "G")
            }) {
                Text("G")
                    .foregroundColor(.white)
                    .frame(maxWidth: .infinity, minHeight: 90)
            }
            .background(Color.teal)
            Button(action: {
                play(sound: "A")
            }) {
                Text("A")
                    .foregroundColor(.white)
                    .frame(maxWidth: .infinity, minHeight: 90)
            }
            .background(Color.indigo)
            Button(action: {
                play(sound: "B")
            }) {
                Text("B")
                    .foregroundColor(.white)
                    .frame(maxWidth: .infinity, minHeight: 90)
            }
            .background(Color.purple)
            Button(action: {
                play(sound: "C")
            }) {
                Text("C")
                    .foregroundColor(.white)
                    .frame(maxWidth: .infinity, minHeight: 90)
            }
            .background(Color.red)
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
    }
    
    private func play(sound: String) {
        let _ = print("Play \(sound)")
        let url = Bundle.main.url(forResource: sound, withExtension: ".wav")
        audioPlayer = try! AVAudioPlayer(contentsOf: url!)
        audioPlayer.prepareToPlay()
        audioPlayer.play()
    }
}

struct PlayerView_Previews: PreviewProvider {
    static var previews: some View {
        PlayerView()
    }
}

And here’s what it looks like on the device.

If you notice, the code is so long and redundant. We can do better. Let’s refactor our code by creating a model class so we can use it inside a loop.

Refactor Time

Let’s create a Key model. I imported SwiftUI since I need the Color class.

1
2
3
4
5
6
7
8
import SwiftUI

struct Key: Identifiable {
    
    var id: Int
    var note: String
    var color: Color
}

Go back to our PlayerView class and let’s create an array based on the Key model.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
private var arrayKeys = [
        Key(id: 0, note: "C", color: Color.red),
        Key(id: 1, note: "D", color: Color.orange),
        Key(id: 2, note: "E", color: Color.yellow),
        Key(id: 3, note: "F", color: Color.green),
        Key(id: 4, note: "G", color: Color.teal),
        Key(id: 5, note: "A", color: Color.indigo),
        Key(id: 6, note: "B", color: Color.purple),
        Key(id: 7, note: "C", color: Color.red)
]

Let’s update our body based on our newly created array.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
var body: some View {
        VStack {
            ForEach(arrayKeys) { key in
                Button(action: {
                    play(sound: key.note)
                }) {
                    Text(key.note)
                        .foregroundColor(.white)
                        .frame(maxWidth: .infinity, minHeight: 90)
                }
                .background(key.color)
            }
        }
       .frame(maxWidth: .infinity, maxHeight: .infinity)
}

Much better. Code is now shorter, if I want to add another key, I would just add another Key object to our array.

You can check the whole source code here. The project is compiled using the latest Xcode 14.3.

Fedora 38 Released

Just installed Fedora 38. So far, no issues found.

The default wallpaper sucks though.

Sound of Metal Movie

Just finished watching the movie Sound of Metal. It was a great film and just found out that it was nominated for best picture back in 2021.

If you watch the film, Ruben the main character was wearing a Youth of Today hoodie several times throughout the movie. It was revealed that he was recovering addict. 4 years drug-free he said.

For the uninitiated, Youth of Today is a hardline vegan straight-edge (refrain from drugs and alcohol movement) band. I am not much of a fan of the band but their frontman Ray Cappo is one of the huge influences that made me quit drinking and smoking.

No more.

New MacBook Air M2

My new Macbook came in today, from my sister in Houston. Thank you!

Coming from Macbook Pro 2015 (won’t run the latest Ventura or Xcode 14.3 anymore), this is a huge leap for me.

I just want to take note of the software and applications I initially installed for future reference.

Applications Installed in order

Early Birthday Gift

My wife gifted me an early present, a Fitbit. Thank you so much! I love you!

I used to have a Huawei smartwatch but lost it and hopefully, I can find them. This is my first Fitbit device. I always enjoy tracking my health data, especially my sleep pattern and steps.

And as someone who’s getting older by the day, tracking my health is something I am planning to take seriously.

Jetpack Compose Journey Part 1

This will be my first time delving into Jetpack Compose for a rewrite of our existing app. I believe I have no time to study or do a full Google code lab for this one, due to the constraints of the timeline and deadline. So I will have to go head first and rely on my > 11 years of experience.

Setup

So with every new Android project, I created one. Every new project from Android has been plagued by inconsistency. For example, some Groovy formats are in double quotes and single quotes.

Build Issues

When upgrading kotlinCompilerExtensionVersion, I encountered build issues as expected. It turns out I need to sync it with the latest Kotlin version too, based on this compatibility map. Leaving out `compose_version" seems to not affect the build issues. So,

1
id 'org.jetbrains.kotlin.android' version "1.8.10" apply false

and

1
2
3
composeOptions {
     kotlinCompilerExtensionVersion "1.4.4"
}

needs to sync together based on the compatibility map. After fixing the sync, I haven’t experienced any build issues when upgrading core components for the Compose.

The Android version I’m using is

1
2
Android Studio Electric Eel | 2022.1.1 Patch 2
Build #AI-221.6008.13.2211.9619390, built on February 17, 2023

Belated Happy Birthday To My Wife

After a very busy day yesterday, there was not enough time to post a greeting here.

Happy birthday to the best person I have ever known and my lovely wife! I love you so much!

Google I/O 2023

It’s that time of the year. I’m surprised that Google announced the event this early.

New Home

My wife and I are proud homeowners today. After 3 years in the making, we finally got the keys to our new house.

Diablo Immortal on Linux

I was able to run Diablo Immortal on Linux, despite only being available on iOS, Android, and Windows. I know for a fact that I needed Wine to be able to run a Windows environment or application in Linux. But, I just found out you need to install Lutris too.

For future reference, the steps are below. I am on Fedora.

  1. Install Wine
1
sudo dnf install wine
  1. Install Lutris
1
sudo dnf install lutris

If Lutris won’t start, try installing it via Flatpak.

  1. Install Winetricks
1
sudo dnf install winetricks
  1. Visit this Lutris Battle.net link and click on Install. It should display a dialog and click on continue. And just proceed and follow instructions.
  2. It took some time to figure out the perfect settings to run Battle.net, I was able to get a reference from this Reddit post. The settings that worked for me were, check the image below. Take note of the Wine version and the settings below it.
  • Latest Lutris Proton runner
  • DXVK Version 1.10L
  • VKD3D Version 2.6
  • D3D Extras Version 2
  • DXVK NVAPI Version 0.5.3

And after all that, Battle.net should run after signing in.

My first contribution to Google/Android

I just had my first GitHub contribution to Android/Google merged into their codebase. I have never thought of taking my free time to contribute to open source in my over > 11 YOE.

1
lawgimenez/agp-v7.4.1

It’s not much of a contribution though, it’s just an update to the latest Android Gradle plugin. But nevertheless, I contributed and I’m proud of myself.

Bought ThinkPad T480

Yesterday I bought a ThinkPad T480 for 17,000 PHP or ~315 USD. It has 512 SSD storage and 16GB RAM which is a very good specification-to-price ratio.

The screen resolution is underwhelming though with only 1366x768, compared to my Macbook Pro with Retina.

But the machine is decent enough to work on Android Studio and some light programming.

Leftover Android Studios

Thanks to this Reddit post, I just found out that you could remove unused Android Studio cache or leftover versions.

I saved around ~4GB of storage.