100 Days of SwiftUI Day 56

100 Days of SwiftUI – Day 56

We’ve arrived at day 56 of the 100 Days of SwiftUI! Yesterday, we finished the implementation of the Bookworm app. Today, we wrap up this project by completing a few challenges. Let’s dive in!

Bookworm SwiftUI challenge #1

Let’s take a look at the first challenge!

Right now it’s possible to select no title, author, or genre for books, which causes a problem for the detail view. Please fix this, either by forcing defaults, validating the form, or showing a default picture for unknown genres – you can choose.

Hacking with Swift, Paul Hudson (@twostraws)
//
//  StringIsEmpty.swift
//  Bookworm
//


import Foundation
extension String {
    var isReallyEmpty: Bool {
        self.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
    }
}
Section {
                    Button("Save") {
                        let newBook = Book(context: moc) // create a new book in our managed object context
                        
                        // Set the properties for the new book
                        newBook.id = UUID()
                        newBook.title = title
                        newBook.author = author
                        newBook.rating = Int16(rating)
                        newBook.genre = genre
                        newBook.review = review
                        
                        try? moc.save() // save the book to the managed object context
                        dismiss() // closes the view
                    }
                }
                `.disabled(title.isReallyEmpty || author.isReallyEmpty || genre.isReallyEmpty)

Bookworm SwiftUI challenge #2

The second challenge is to modify ContentView so that books rated as 1 star are highlighted somehow, such as having their name shown in red.

 VStack(alignment: .leading) {
           Text(book.title ?? "Unknown Title")
               .font(.headline)
               .foregroundColor(book.rating == 1 ? .red : .primary)

Bookworm SwiftUI challenge #3

The third and final challenge of the day is to add a new “date” attribute to the Book entity, assigning Date.now to it so it gets the current date and time, then format that nicely somewhere in DetailView.

To do this, we first needed to add a date to our data model. Then, it was just a matter of putting it somewhere in our code, after setting it in the AddBookView.

 Section {
                    Button("Save") {
                        let newBook = Book(context: moc) // create a new book in our managed object context
                        
                        // Set the properties for the new book
                        newBook.id = UUID()
                        newBook.title = title
                        newBook.author = author
                        newBook.rating = Int16(rating)
                        newBook.genre = genre
                        newBook.review = review
                        newBook.date = Date.now
                        
                        try? moc.save() // save the book to the managed object context
                        dismiss() // closes the viewe
                    }
                }
                .disabled(title.isReallyEmpty || author.isReallyEmpty || genre.isReallyEmpty)
//
//  DetailView.swift
//  Bookworm

import SwiftUI

struct DetailView: View {
    let book: Book
    
    @Environment(\.managedObjectContext) var moc
    @Environment(\.dismiss) var dismiss
    @State private var showingDeleteAlert = false
    
    var body: some View {
        ScrollView {
            ZStack(alignment: .bottomTrailing) {
                Image(book.genre ?? "Fantasy")
                    .resizable()
                    .scaledToFit()
                
                Text(book.genre?.uppercased() ?? "FANTASY")
                    .font(.caption)
                    .fontWeight(.black)
                    .padding(8)
                    .foregroundColor(.white)
                    .background(.black.opacity(0.75))
                    .clipShape(Capsule())
                    .offset(x: -5, y: -5)
            }
            
            Text(book.author ?? "Unknown Author")
                .font(.title)
                .foregroundColor(.secondary)
            
            if let date = book.date {
                Text(date.formatted(date: .abbreviated, time: .omitted))
            }
            
            Text(book.review ?? "No review")
                .padding()
            
            RatingView(rating: .constant(Int(book.rating)))
                .font(.largeTitle)
            
        }
        
        .navigationTitle(book.title ?? "Unknown Book")
        .navigationBarTitleDisplayMode(.inline)
        
        .alert("Delete Book", isPresented: $showingDeleteAlert) {
            Button("Delete", role: .destructive, action: deleteBook)
            Button("Cancel", role: .cancel) {}
        } message: {
            Text("Are you sure?")
        }
        .toolbar {
            Button {
                showingDeleteAlert = true
            } label: {
                Label("Delete this book", systemImage: "trash")
            }
        }
    }
    
    func deleteBook() {
        moc.delete(book)
        
        // try? moc.save()
        dismiss()
    }
}

Screenshots

Wrap up

And that’s it for day 56! Tomorrow, we’ll jump right into the next project, which is a technique project where we’ll further explore Core Data. That should be very interesting, so stay tuned for that. For now, it’s time to recharge!

Darryl

Hi! My name is Darryl and this is my personal blog where I write about my journey as I learn programming! You'll also find articles about other things that interest me including games, tech and anime.

Post navigation

Leave a Comment

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

100 Days of SwiftUI – Day 68

100 Days of SwiftUI – Day 46

100 Days of SwiftUI – Day 96

100 Days of SwiftUI – Day 87