Swiftmas – Day 10 – Christmas Cracker

Posted by

·

Welcome to Day 10 of #The12DaysOfSwiftmas

Today’s prompt…

Swiftmas 2023 GitHub repo: https://github.com/thecodingsprite/Swiftmas-2023/tree/main

Now if you’re not British you may not fully get this prompt as I have been made aware that Christmas Crackers are not a worldwide thing! (I cannot believe this, they are the highlight of the Christmas meal!!!) Anyhow let me explain, they are tubes that 2 people have a tug of war over until a loud snap & the winner ends up with the tube half that contains a paper hat, a joke & sometimes a gift. Cracker jokes are some of my most favourite kinds of jokes, so a Cracker Joke App here I come!

In my head, at the initial stage I knew I wanted a good amount of jokes for people to peruse through. I knew I wanted a previous & next button & ideally a randomise button for fun. But seeing all that code line up in my head, the jokes would have to be stored separately in a different file to begin with otherwise it would just be a mess. But for now we will style out our ContentView file.

We will use placeholder text for now & add some todo comments.

 var body: some View {
        ZStack {
            // Background
            Image("bg")
                .resizable()
                .aspectRatio(contentMode: .fill)
                .ignoresSafeArea()
                .opacity(0.8)
            
            VStack {
                Spacer()
                
                // Joke
                ZStack {
                    RoundedRectangle(cornerRadius: 15)
                        .padding()
                        .frame(height: 300)
                        .foregroundStyle(Color("joke-box"))
                        .opacity(0.8)
            
                    // TODO: Dynamically show jokes
                    Text(" Joke goes here, probably on multiple lines, testing text, testing text, testing text.")
                        .foregroundStyle(.white)
                        .clipShape(RoundedRectangle(cornerRadius: 15))
                        .padding(.horizontal, 30)
                }
                
                Spacer()
                
                HStack {
                    // Previous
                    Button {
                        // TODO: Previous joke
                    } label: {
                        ZStack {
                            RoundedRectangle(cornerRadius: 10)
                                .frame(height: 50)
                                .foregroundStyle(Color("button-box"))
                            
                            Text("Previous")
                                .foregroundStyle(.white)
                        }
                    }
                    
                    // Next
                    Button {
                        // TODO: Next joke
                    } label: {
                        ZStack {
                            RoundedRectangle(cornerRadius: 10)
                                .frame(height: 50)
                                .foregroundStyle(Color("button-box"))
                            
                            Text("Next")
                                .foregroundStyle(.white)
                        }
                    }
                }.frame(width: 350)
                
                Button {
                    // TODO: Randomise joke
                } label: {
                    ZStack {
                        RoundedRectangle(cornerRadius: 10)
                            .frame(height: 50)
                            .foregroundStyle(Color("button-box"))
                        
                        Text("Random")
                            .foregroundStyle(.white)
                    }
                    .padding(.bottom, 50)
                }
                
                
            }
            .frame(width: 350)
        
        }
    }
}

So after creating your UI layout right click in the file navigator > New File > Swift File

Now we can store our jokes in this new struct we are going to create. But we need to think about access to these jokes. I personally thought the best way would be one array containing the jokes but the strings needed to be multi-line strings so we use """ instead of "". I also for the sake of this app went with using the static keyword as jokes aren’t a big deal for privacy in this application.

import Foundation

struct Jokes {
    
    static var jokes = [
        """
        Q: Why didn't Santa put the tree lights up?
        
        A: Because of Elf & Safety!
        
        """,
        
        """
        Q: Why can't the Christmas tree stand up?
                
        A: It doesn't have legs!
                
        """,
        
        """
        Q: Who is Santa's favourite actor?
        
        A: William Dafoe-ho-ho!
        
        """,
        
        """
        Q: What's ever elf's favourite type of music?
        
        A: Wrap!
        
        """,
        
        """
        Q: Who tells the best Christmas jokes?
        
        A: Reindeer. They sleigh every time!
        
        """,
        
        """
        Q: What do you call Santa when he takes a break?
        
        A: Santa Pause!
        
        """,
        
        """
        Q: Who is a Christmas tree's favourite singer?
        
        A: Spruce Springsteen!
        
        """,
        
        """
        Q: What do you get if Santa goes down the chimney when a fire is lit?
        
        A: Crisp Kringle!
        
        """,
        
        """
        Q: Why is the turkey never hungry at Christmas?
        
        A: Because it's stuffed!
        
        """,
        
        """
        Q: What does Santa use to bake cakes?
        
        A: Elf-raising flour of course!
        
        """,
        
        """
        Q: Why did the choir have to cancel their carol concert?
        
        A: They caught tinsel-itis!
        
        """,
        
        """
        Q: What do call a penguin in the Sahara desert?
        
        A: Lost!
        
        """,
        
        """
        Q: What do Santa's little helpers learn at school?
        
        A: The elf-abet!
        
        """,
        
        """
        Q: What do you get if you put a bell on a skunk?
        
        A: Jingle smells!
        
        """,
        
        """
        Q: How did Darth Vader know what Luke Skywalker got for Christmas?
        
        A: He felt his presents!
        
        """,
        
        """
        Q: What is white & minty?
        
        A: A Polo Bear!
        
        """,
        
        """
        Q: What do you call an old snowman?
        
        A: Water!
        
        """,
        
        """
        Q: What do sheep say to each other at Christmas time?
        
        A: Merry Christmas to ewe!
        
        """,
        
        """
        Q: What comes at the end of Christmas Day?
        
        A: The letter "Y"!
        
        """,
        
        """
        Q: What did the farner get for Christmas?
        
        A: A cowculator!
        
        """,
        
        """
        Q: What can you call a polar bear which wears ear muffs?
        
        A: Anything you like, they can't hear you!
        
        """,
        
        """
        Q: What do you get if Santa forgets to wear his undercrackers?
        
        A: St Nickerless!
        
        """,
        
        """
        Q: Why is it getting harder to buy advent calendars?
        
        A: Because their days are numbered!
        
        """,
        
        """
        Q: What do you get if you cross Santa with a duck?
        
        A: A Christmas Quacker!
        
        """,
        
        """
        Q: Who's Rudolphs favourite pop star?
        
        A: Beyon-sleigh!
        
        """,
        
        """
        Q: Why did  no one bid for Rudolph & Dasher on eBay?
        
        A: Because they were two deer!
        
        """,
        
        """
        Q: What do snowmen wear on their heads?
        
        A: Ice caps!
        
        """,
        
        """
        Q: Why couldn't the skeleton go to the Christmas party?
        
        A: Because he had no body to go with!
        
        """,
        
        """
        Q: What do you call an obnoxious reindeer?
        
        A: Rude-olph!
        
        """,
        
        """
        Q: Why was the snowman looking through the carrots?
        
        A: He was picking his nose!
        
        """
    ]
}

I went with a total of 30 jokes. Some my own from memory & some I went googling for. This was probably the hardest part as it was just so mundane. But 30 jokes later & we can go back to ContentView & begin fixing our UI to dynamically show these jokes. First off we are going to need a @State property that can update with the UI so we can keep track of where we are in the list of jokes.

 @State var jokeTracker = 0

Now to add the jokes to the UI using this state property to set the index within that array to show.

// Dynamically show jokes
Text(Jokes.jokes[jokeTracker])

Now to update those todo comments in the buttons. For previous we can -1 of our @State property & next we can +1 but first we need to check we are not already at 0. For the randomise button we can use the Int.random(in: 0...29) to select our place within the array (remember arrays start at 0 not 1 so we only count up to 29).

Button {
                        // Previous joke
                        if jokeTracker != 0 {
                            jokeTracker -= 1
                        } else {
                            // Do nothing as we can't go any further back
                        }
                    } label: {
                        ZStack {
                            RoundedRectangle(cornerRadius: 10)
                                .frame(height: 50)
                                .foregroundStyle(Color("button-box"))
                            
                            Text("Previous")
                                .foregroundStyle(.white)
                        }
                    }
                    
                    
                    // Next
                    Button {
                        // Reset jokes back to start if at the end
                        if jokeTracker >= 29 {
                            jokeTracker = 0
                        } else {
                            // Next joke
                            jokeTracker += 1
                        }
                    } label: {
                        ZStack {
                            RoundedRectangle(cornerRadius: 10)
                                .frame(height: 50)
                                .foregroundStyle(Color("button-box"))
                            
                            Text("Next")
                                .foregroundStyle(.white)
                        }
                    }
                }
                .frame(width: 350)
                
                
                // Randomise joke
                Button {
                    jokeTracker = Int.random(in: 0...29)
                } label: {
                    ZStack {
                        RoundedRectangle(cornerRadius: 10)
                            .frame(height: 50)
                            .foregroundStyle(Color("button-box"))
                        
                        Text("Random")
                            .foregroundStyle(.white)
                    }
                    .padding(.bottom, 50)
                }
            }
            .frame(width: 350)
        }
    }

Now you should have a fully functional app that can make you laugh out loud whenever you want it to!

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


Our Completed Application

See you tomorrow for Day 11


Complete Code

ContentView

import SwiftUI

struct ContentView: View {
    
    @State var jokeTracker = 0
    
    var body: some View {
        
        
        ZStack {
            // Background
            Image("bg")
                .resizable()
                .aspectRatio(contentMode: .fill)
                .ignoresSafeArea()
                .opacity(0.8)
            
            VStack {
                Spacer()
                
                // Joke
                ZStack {
                    RoundedRectangle(cornerRadius: 15)
                        .padding()
                        .frame(height: 300)
                        .foregroundStyle(Color("joke-box"))
                        .opacity(0.8)
            
                    // Dynamically show jokes
                    Text(Jokes.jokes[jokeTracker])
                        .foregroundStyle(.white)
                        .clipShape(RoundedRectangle(cornerRadius: 15))
                        .padding(.horizontal, 30)
                }
                
                Spacer()
                
                HStack {
                    
                    // Previous
                    Button {
                        // Previous joke
                        if jokeTracker != 0 {
                            jokeTracker -= 1
                        } else {
                            // Do nothing as we can't go any further back
                        }
                    } label: {
                        ZStack {
                            RoundedRectangle(cornerRadius: 10)
                                .frame(height: 50)
                                .foregroundStyle(Color("button-box"))
                            
                            Text("Previous")
                                .foregroundStyle(.white)
                        }
                    }
                    
                    
                    // Next
                    Button {
                        // Reset jokes back to start if at the end
                        if jokeTracker >= 29 {
                            jokeTracker = 0
                        } else {
                            // Next joke
                            jokeTracker += 1
                        }
                    } label: {
                        ZStack {
                            RoundedRectangle(cornerRadius: 10)
                                .frame(height: 50)
                                .foregroundStyle(Color("button-box"))
                            
                            Text("Next")
                                .foregroundStyle(.white)
                        }
                    }
                }
                .frame(width: 350)
                
                
                // Randomise joke
                Button {
                    jokeTracker = Int.random(in: 0...29)
                } label: {
                    ZStack {
                        RoundedRectangle(cornerRadius: 10)
                            .frame(height: 50)
                            .foregroundStyle(Color("button-box"))
                        
                        Text("Random")
                            .foregroundStyle(.white)
                    }
                    .padding(.bottom, 50)
                }
            }
            .frame(width: 350)
        }
    }
}

Jokes Struct

import SwiftUI

struct ContentView: View {
    
    @State var jokeTracker = 0
    
    var body: some View {
        
        
        ZStack {
            // Background
            Image("bg")
                .resizable()
                .aspectRatio(contentMode: .fill)
                .ignoresSafeArea()
                .opacity(0.8)
            
            VStack {
                Spacer()
                
                // Joke
                ZStack {
                    RoundedRectangle(cornerRadius: 15)
                        .padding()
                        .frame(height: 300)
                        .foregroundStyle(Color("joke-box"))
                        .opacity(0.8)
            
                    // Dynamically show jokes
                    Text(Jokes.jokes[jokeTracker])
                        .foregroundStyle(.white)
                        .clipShape(RoundedRectangle(cornerRadius: 15))
                        .padding(.horizontal, 30)
                }
                
                Spacer()
                
                HStack {
                    
                    // Previous
                    Button {
                        // Previous joke
                        if jokeTracker != 0 {
                            jokeTracker -= 1
                        } else {
                            // Do nothing as we can't go any further back
                        }
                    } label: {
                        ZStack {
                            RoundedRectangle(cornerRadius: 10)
                                .frame(height: 50)
                                .foregroundStyle(Color("button-box"))
                            
                            Text("Previous")
                                .foregroundStyle(.white)
                        }
                    }
                    
                    
                    // Next
                    Button {
                        // Reset jokes back to start if at the end
                        if jokeTracker >= 29 {
                            jokeTracker = 0
                        } else {
                            // Next joke
                            jokeTracker += 1
                        }
                    } label: {
                        ZStack {
                            RoundedRectangle(cornerRadius: 10)
                                .frame(height: 50)
                                .foregroundStyle(Color("button-box"))
                            
                            Text("Next")
                                .foregroundStyle(.white)
                        }
                    }
                }
                .frame(width: 350)
                
                
                // Randomise joke
                Button {
                    jokeTracker = Int.random(in: 0...29)
                } label: {
                    ZStack {
                        RoundedRectangle(cornerRadius: 10)
                            .frame(height: 50)
                            .foregroundStyle(Color("button-box"))
                        
                        Text("Random")
                            .foregroundStyle(.white)
                    }
                    .padding(.bottom, 50)
                }
            }
            .frame(width: 350)
        }
    }
}

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.