This simple trick helps preventing the system from resizing the background view when the modal appears. It keeps the standard behavior (panning view, partial view with dark veil) but leave the background view untouched.
Simply set the following flag on your UIViewController, for instance inside the viewDidLoad method:
definesPresentationContext = true
If the presenting view controller is a child of a navigation controller, then we need to apply this flag to the navigationController instead of self:
Rules are simple: – select your piece to see where you can play – one square away (including the diagonals) and your piece is cloned – two squares away and your piece jumps – capture the pieces of your enemy by cloning or jumping next their piece – you win if you own the most pieces at the end of the game
Play against a challenging AI or against a friend on your iPhone or iPad……or play online against strangers and rank up the leaderboard!
Build a complete app from scratch in a week-end? Challenge accepted! I started the project on Friday evening and submitted the app for review on the App Store on Sunday evening. It was accepted during the night and live on Monday morning.
So what was there time to do in just a weekend? Actually, a lot:
SwiftUI: I experimented a tiny bit of SwiftUI before, but nothing compares to building a real app!
GPS based location is retrieved in the background, reverse geocoded and stored in CoreData
Forms: automatically recording locations is cool, but you sometimes have to go and manually add or edit visits, SwiftUI makes it particularly easy to create dynamic forms with very little code and handles pretty much everything for you
In-App Purchase with a paywall selling a non-consumable product to unlock some features like yearly / country reports and PDF export
PDF generation from HTML templates, and export using a SwiftUI wrapped version UIActivityController
Analytics and Crashlytics integration using Firebase
App Store preparation: finding a name, writing description, creating a logo, preparing screenshots, submitting the In-App Purchase product
What kind of issues did I run into?
SwiftUI is fun, but sometimes it’s just really hard to do something really simple (like presetting two modals / sheets from the same view), and sometimes you simply can’t do something simple (like removing the disclosure indicator from list cells without generating random crashes)
Fastlane didn’t want to work on my machine, I wanted to automate the screenshots but couldn’t, but it’s ok, since there is only one language for now and the app only support the iPhone, taking screenshots manually wasn’t too long
Apple randomly disabled submission from the version of Xcode available on the Mac App Store, and obviously the error message when submitting was super obscure… had to download the next coming GM from the developer download center
Is the code clean? Hell no! But was it fun to do? Absolutely! I don’t know if this app will ever sustain itself, but I’ve to admit we live in a time where very powerful tools are available for us to experiment and iterate really quickly. I’ll definitely do this kind of challenges again 🙂
When creating a custom video player, you need to have a component halfway between a UISlider, allowing your to interactively track and seek a particular position in the video, but also show progress continuously while also eventually showing buffering.
Even though there isn’t any component like this directly available in UIKit, it appears it’s fairly easy to make something like this, interactive and fully customizable:
Creating a custom view to display progress and buffer
Let’s start with the basics, we need a subclass of UIView for which we override all possible initializers:
Finally, it’s important to override both layoutSubviews to make sure our subviews are property placed when screen size changes (final size, rotations, etc) and the intrinsicContentSize, especially because we want the height to automatically be decided based on our track height and thumb height instead of adding a constraint ourselves:
When playing a video in an AVPlayer, you sometimes want to be aware of the buffering in order to update your interface, for instance you can:
show an activity indicator when the player stalls due to buffering
create your own progress bar and show in a different color than the progression the point up to where the video is loaded
(Note that in the following examples, I consider being at the view model level and update dynamic properties that could be observed by a view controller using KVO to react and update the interface, try using reactive programming with RxSwift or Combine instead).
Detecting changes in buffer state
In order to show an activity indicator when the player stalls, we need to register 3 observers using KVO (Key-Value Observing) on the following dynamic properties of an AVPlayerItem:
When the updates are receiving, we can then react accordingly:
isPlaybackBufferEmpty = true: the player has to fill the buffer, definitely stalling, this is a good place to start the activity indicator
isPlaybackBufferFull = true: the player has filled the buffer completely, at this stage it has more than enough to play, not stalling, the activity indicator must be stopped
isPlaybackLikelyToKeepUp = true: the player has filled enough of the buffer to start playing, at this stage, it will restart playing if not paused and is not stalling, the activity indicator can be stopped
Detecting up to what point of the video is buffered
In order to know and convert the loading time ranges into a percentage of the video, we will need to retrieve and extract different pieces of information:
the video duration
the available times aka what’s been loaded already
Getting video duration
For the duration of the video, again, an observer on the duration property of the AVPlayerItem and using KVO will do the trick: