Frosty is a third-party Twitch client for Android and iOS. One of the main features added by Frosty is support for custom emotes (which are not available in the first-party Twitch client). Beyond that, Frosty also adds a lot of quality-of-life improvements. This has made Frosty the most popular Twitch third-party client on iOS and Android.
It currently has 705 stars, 98 active issues and 172 closed issues, as well as 1 open PRs, and 138 closed PRs (2 PRs were closed right after I opened mine). There are 5 contributors (including me). The repository owner and maintainer, Tommy Chow, wrote on their profile that they are currently busy and might respond slowly, which probably explains the relatively large number of open issues. That being said, they still look at PRs and merge them quite quickly.
The project doesn't have any discussion forum or mailing list. As far as I can see, the only interactions between users and/or contributors happen in issues or pull requests.
The project is licensed under **AGPL** (Affero General Public License), a copyleft license based on the GPL but modified for network-based software.
This isn't my first *try* at contributing to Frosty. In January 2023, I submitted a pull request to add swipe controls to the video player. However, I couldn't find enough time to improve the code to meet the standards wanted by the maintainer. So the maintainer decided not to merge my PR.
The time I spent learning about the state management solution and the overall codebase was not wasted at all. I actually liked the state management library used (MobX) a lot, and I've been using it ever since.
## Contribution
The project has a small "Development setup" section in the README, which consists of instructions on how to build the app and work on it, but the project doesn't have a `CONTRIBUTING.md` file.
After setting everything up, I started looking for an issue that I wanted to work on. It didn't take much time to find an interesting request, someone wanted the ability to filter out messages in the chat. This can be either because they do not like certain emotes, or maybe because they don't want to read messages on a certain topic. I figured that this was a great feature to have while also being relatively easy to work on, so I commented on the issue that I would try to implement it and got to work.
After about 30 minutes, I figured out exactly where to filter out messages and tested with a preset list of things to filter out. It worked! Now I had to make the settings interface.
This part took a bit longer simply because I started working on it and then got busy with other projects. I also took a bit longer than expected because I wasn't really sure what the maintainer would like and how the code should be organized. After looking at a lot of the other settings files, I implemented a stateless widget and put all the logic in the `settingsStore` (sort of like a controller in MVC or a model in MVVM). I then committed my changes to my branch, recorded a demo video, and made my PR.
After only 10 hours, the maintainer had reviewed my PR and requested some changes. All of the requested changes were points I wasn't sure of; the main one was the decision to put the logic in the settingsStore and use a StatelessWidget. The maintainer wanted to keep the settingsStore clean, and I agreed with them. So I made the changes and also improved the code further to remove a hack that I had to use.
The same day, the maintainer replied that they liked my solution in general but they wanted me to add back the hack (it was a pretty neat solution to a tricky issue), but they preferred the ‘hack’ because only my widget would use it. I made the changes, re-tested the app on IOS and Android and then pushed.
The following day, the maintainer accepted my PR and merged the changes.
## Journal
When the project was announced, I first wanted to work on an app called Ente Auth. It is an alternative to Google Authenticator that supports more platforms. I forked the repo and started looking at issues when I realized that there weren't many issues that had clear solutions (there were a few issues linked to the framework). I still built the app locally but ended up looking for a different project.
My second idea was LocalSend, an open-source alternative to AirDrop that I often use. Again, I forked the repo and started looking at issues. I found a couple of interesting ones, including a request for a "select all" button when choosing images. I thought this feature was quite important, so I began looking the code. After about 30 minutes, I found the relevant section and realized that the gallery view was from a library. I then looked at the library and how they implemented it to see if I could perhaps add the feature there, and then update LocalSend with the new version. However, the LocalSend maintainer was already planning to change image picker plugins anyway.
My third and final idea was to add a feature to frosty. The process was described in sections above.
## Conclusion
Contributing to an open-source project has been a great experience. I learned more about how larger projects work, as well as how Git (more specifically GitHub) works when making a pull request. It felt rewarding when the PR was accepted and merged because I had contributed a feature that, while not really useful for all users, will be important for some. Knowing that someone out there will find the app even a bit better thanks to this feature is great.