Swiftmas – Day 01 – Countdown

Posted by

·

Happy Swiftmas! Today is the very first day of our #The12DaysOfSwiftmas coding challenge.

If you have no idea what swiftmas is, then check out this post to learn more.

Today’s prompt:

So if you have no idea where to start with this challenge, have no fear! I will be sharing my version here & available on GitHub for you to download/clone & play around with. This way you can learn as you go with a tutorial & use the project as a guide if things go awry.

You can find the swiftmas GitHub here, updated each day with the next project: https://github.com/thecodingsprite/Swiftmas-2023

So where did I start with this one, I knew I wanted a countdown but what kind of countdown? A days, hours & minutes one, a visual one with graphics… I mean the ideas are endless with a prompt arent’ they!

I figured Id start slow, I was looking for festive background images to stash away for any time I may need them during this challenge. Upon this search came my inspiration…an advent calendar printable (Vector File) that I knew I could re-purpose as a really cute looking UI.

So this had set the stage for a simple countdown using just days, as graphically I wanted it to display a cute looking view. So I set to work. Edited the images all ready, imported these into my Xcode project & to slowly get my brain into the mood I purely worked on the visuals of the app. Just setting up the UI. I figured I can implement the logic a bit later on. This is how my code began & the design of the UI was staged.

import SwiftUI

struct ContentView: View {
    var body: some View {

         ZStack {
            Image("bg")
                .resizable()
                .aspectRatio(contentMode: .fill)
                .ignoresSafeArea()
                .opacity(0.7)
            
            // Darken bg
            Color(.black)
                .ignoresSafeArea()
                .opacity(0.2)
            
            // Countdown Days
            HStack(spacing: 20) {
                
                // TODO: Implement logic dynamic on days left
                Image("12")
                    .resizable()
                    .aspectRatio(contentMode: .fill)
                    .frame(width: 150, height: 150)
                
                // Text design
                ZStack {
                    RoundedRectangle(cornerRadius: 25.0)
                        .foregroundStyle(Color(red: 69/255, green: 87/255, blue: 42/255))
                        .opacity(0.9)
                        .frame(width: 400, height: 80)
                    
                    Text("Day's Till Christmas")
                        .font(Font.system(size: 40))
                        .bold()
                        .foregroundStyle(.white)
                }
            }
        }
    }
}

I hardcoded an image in place so I could get the design just right. Knowing I would make this dynamic based on the countdown logic a little later on.

The next thing to note is I set the app to horizontal mode only. If you have never done this before it can be daunting but is super easy. There are a few ways, but the most simple way is to simply click on your project in the file navigator > then uncheck the other orientations for both iPhone & iPad.

This should work as long as you do both the iPad & the iPhone. But if this doesn’t work then you will need to add a section to your info.plist as below.

So now we work on the logic. We will need a variable that can refresh the state as it’s updated for the image selection.

  @State var daysLeftTillChristmas = 0

Now we change the image call…

// Change Image("12) to:

Image("\(daysLeftTillChristmas)")

Now the countdown logic… I put this in a function so it was easy to call within .onAppear{}

  func countdown() -> Int {
        
        // create date components of 12/24
        let christmasComponents = DateComponents(month: 12, day: 25)
        
        // get next christmas date
        let nextChristmas = Calendar.current.nextDate(after: Date(), matching: christmasComponents, matchingPolicy: .strict)!
        
        // calculate number of days left
        let daysLeft = Calendar.current.dateComponents([.day], from: Date() , to: nextChristmas).day!
        
        return daysLeft
    }

// Add this onAppear to the very 1st ZStack

.onAppear {
            daysLeftTillChristmas = self.countdown()
        }

The fully functioning app code should now look like this:

struct ContentView: View {
    
    @State var daysLeftTillChristmas = 0
    
    var body: some View {
        ZStack {
            Image("bg")
                .resizable()
                .aspectRatio(contentMode: .fill)
                .ignoresSafeArea()
                .opacity(0.7)
            
            // Darken bg
            Color(.black)
                .ignoresSafeArea()
                .opacity(0.2)
            
            // Countdown Days
            HStack(spacing: 20) {
                
                // Implement logic dynamic on days left
                Image("\(daysLeftTillChristmas)")
                    .resizable()
                    .aspectRatio(contentMode: .fill)
                    .frame(width: 150, height: 150)
                
              
                
                // Text design
                ZStack {
                    RoundedRectangle(cornerRadius: 25.0)
                        .foregroundStyle(Color(red: 69/255, green: 87/255, blue: 42/255))
                        .opacity(0.9)
                        .frame(width: 400, height: 80)
                        
                    Text("Day's Till Christmas")
                        .font(Font.system(size: 40))
                        .bold()
                        .foregroundStyle(.white)
                }
            }
        }
        .onAppear {
            daysLeftTillChristmas = self.countdown()
        }
       
    }
    
    
    func countdown() -> Int {
        
        // create date components of 12/24
        let christmasComponents = DateComponents(month: 12, day: 25)
        
        // get next christmas date
        let nextChristmas = Calendar.current.nextDate(after: Date(), matching: christmasComponents, matchingPolicy: .strict)!
        
        // calculate number of days left
        let daysLeft = Calendar.current.dateComponents([.day], from: Date() , to: nextChristmas).day!
        
        return daysLeft
    }
    
}

Fancy taking things a step harder?

Well why don’t we add a share button…I must admit this is new to me & I am grateful for other bloggers posting about this. The syntax has been updated for the latest iOS versions but I can’t seem to get it quite right so for the sake of time & a speedy challenge I have stuck with the deprecated syntax. (it still works on devices running iOS 17, I have checked)

So going back over the code I also wanted to tidy things up…so I added a color set to assets for the color we have been using, it just looks way less messy. The hex version is: #45572a if you wanted to do the same. Then after naming that colour: “buttons” I could tidy the foregroundStyle:

// Change from: .foregroundStyle(Color(red: 69/255, green: 87/255, blue: 42/255)) to

.foregroundStyle(Color("buttons"))

Next I added a button in the top right corner. Don’t worry about the action we will be making this next.

// Share button
            VStack {
                HStack() {
                    
                    Spacer()
                    
                    Button(action: shareButton) {
                        Image(systemName: "square.and.arrow.up")
                            .foregroundStyle(Color("buttons"))
                            .scaleEffect(1.5)
                    }
                }
                
                Spacer()
            }
            .padding(.top, 50)

Now the function for that button:

 /// Credit: /www.boltuix.com taught me this
    func shareButton() {
            let url = URL(string: "https://www.thecodingsprite.com/")
            let activityController = UIActivityViewController(activityItems: [url!], applicationActivities: nil)

            UIApplication.shared.windows.first?.rootViewController!.present(activityController, animated: true, completion: nil)
    }

The complete functional code is at the bottom of this post.


Now we have a fully working app squeeee

See you tomorrow for Day 2!


Complete Code

import SwiftUI

struct ContentView: View {
    
    @State var daysLeftTillChristmas = 0
    
    var body: some View {
        ZStack {
            Image("bg")
                .resizable()
                .aspectRatio(contentMode: .fill)
                .ignoresSafeArea()
                .opacity(0.7)
            
            // Darken bg
            Color(.black)
                .ignoresSafeArea()
                .opacity(0.2)
            
            // Countdown Days
            HStack(spacing: 20) {
                
                // TODO: Implement logic dynamic on days left
                Image("\(daysLeftTillChristmas)")
                    .resizable()
                    .aspectRatio(contentMode: .fill)
                    .frame(width: 150, height: 150)
                
              
                
                // Text design
                ZStack {
                    RoundedRectangle(cornerRadius: 25.0)
                        .foregroundStyle(Color("buttons"))
                        .opacity(0.9)
                        .frame(width: 400, height: 80)
                        
                    Text("Day's Till Christmas")
                        .font(Font.system(size: 40))
                        .bold()
                        .foregroundStyle(.white)
                }
            }
            
            // Share button
            VStack {
                HStack() {
                    
                    Spacer()
                    
                    Button(action: shareButton) {
                        Image(systemName: "square.and.arrow.up")
                            .foregroundStyle(Color("buttons"))
                            .scaleEffect(1.5)
                    }
                }
                
                Spacer()
            }
            .padding(.top, 50)
        }
        .onAppear {
            daysLeftTillChristmas = self.countdown()
        }
       
    }
    
    
    func countdown() -> Int {
        
        // create date components of 12/24
        let christmasComponents = DateComponents(month: 12, day: 25)
        
        // get next christmas date
        let nextChristmas = Calendar.current.nextDate(after: Date(), matching: christmasComponents, matchingPolicy: .strict)!
        
        // calculate number of days left
        let daysLeft = Calendar.current.dateComponents([.day], from: Date() , to: nextChristmas).day!
        
        return daysLeft
    }
    
    /// Credit: /www.boltuix.com taught me this
    func shareButton() {
            let url = URL(string: "https://www.thecodingsprite.com/")
            let activityController = UIActivityViewController(activityItems: [url!], applicationActivities: nil)

            UIApplication.shared.windows.first?.rootViewController!.present(activityController, animated: true, completion: nil)
    }
    
}

Discover more from

Subscribe to get the latest posts sent to your email.

thecodingsprite avatar

About the author

Hi! My name is Billie, my friends call me Billie Boo. I am a self taught iOS developer with a background in computer science, animation, graphic design & web design. I love sharing my knowledge & projects with the world & that is my mission for this blog. It’s never too late or too hard to follow your dreams.