ButtonView File with AuthenticationFormProtocol: Where to Put in Code?

Hello! This is my first time posting a question on a form. So sorry ahead of time if I am not doing something right and please let me know how I can fix it!

I am new to swift and I have been following a video by AppStuff. https://youtu.be/QJHmhLGv-_0?si=OwLGXKNTc3m-UH7r&t=5914 . The link is time stamped to the part of the video I need help with.

My question is: Where do I put the AuthenticationFormProtocol var formIsValid so that way I can call on formIsValid to use the .disabled and .opacity in the ButtonView File depending on if formIsValid is true or not?

I deviated from the video by making a new file called ButtonView so that way I didn't have to copy and paste code that I would be using in two different places.

ButtonView File

import SwiftUI

struct ButtonView: View {
    let printTitle: String
    let title: String
    let systemIcon: String
    //@Binding var disabledPlaceHolder: String
    let taskAction: () -> Void
    
    var body: some View {
        Button(action: {
            taskAction()
        }) {
            HStack {
                Text(title)
                    .fontWeight(.semibold)
                Image(systemName: systemIcon)
            }
            .foregroundStyle(Color(.white))
            .frame(width: UIScreen.main.bounds.width - 32, height: 48)
        }
        .background(Color(.systemBlue))
        //.disabled(disabledPlaceHolder)
        //.opacity(disabledPlaceHolder ? 1.0 : 0.5)
        .clipShape(RoundedRectangle(cornerRadius: 10))
        .padding(.bottom, 50)
    }
}

#Preview {
    ButtonView(printTitle: "Sign user up...",
               title: "Sign Up",
               systemIcon: "arrow.right",
               //disabledPlaceHolder: .constant(""),
               taskAction: {})
}

LoginView File

import SwiftUI

struct LoginView: View {
    @State private var email = ""
    @State private var password = ""
    @EnvironmentObject var viewModel: AuthViewModel

    var body: some View {
        NavigationStack {
            VStack {
                //image
                Image("TestLogo")
                    .resizable()
                    .scaledToFill()
                    .frame(width: 100, height: 120)
                    .clipShape(RoundedRectangle(cornerRadius: 20))
                    .padding(.vertical, 32)
                
                //form fields
                VStack(spacing: 24) {
                    InputView(text: $email,
                              title: "Email",
                              placeholder: "name@example.com")
                    .textInputAutocapitalization(.none)
                    
                    InputView(text: $password,
                              title: "Password",
                              placeholder: "Enter your password",
                              isSecureField: true)
                }
                .padding(.horizontal)
                .padding(.top, 12)
                
                //sign in button
                ButtonView(printTitle: "Login In",
                           title: "SIGN IN",
                           systemIcon: "arrow.right") {
                    Task {
                        try await viewModel.signIn(withEmail: email, 
                                                   password: password)
                    }
                }
//                .disabled(formIsValid)
//                .opacity(formIsValid ? 1.0 : 0.5)
                
                Spacer()
    
                //signup button
                NavigationLink {
                    RegistrationView()
                        .navigationBarBackButtonHidden(true)
                } label: {
                    HStack(spacing: 3) {
                        Text("Don't have an account?")
                        Text("Sign Up")
                            .fontWeight(.bold)
                    }
                    .font(.system(size: 14))
                }
            }
        }
    }
}

extension LoginView: AuthenticationFormProtocol {
    var formIsValid: Bool {
        return !email.isEmpty
        && email.contains("@")
        && !password.isEmpty
        && password.count > 5
    }
}

RegistationView File

struct RegistrationView: View {
    @State private var email = ""
    @State private var fullName = ""
    @State private var password = ""
    @State private var confirmPassword = ""
    @EnvironmentObject var viewModel: AuthViewModel
    @Environment(\.dismiss) var dismiss
    
    var body: some View {
        VStack {
            //image
            Image("TestLogo")
                .resizable()
                .scaledToFill()
                .frame(width: 100, height: 120)
                .clipShape(RoundedRectangle(cornerRadius: 20))
                .padding(.vertical, 32)
            
            //form fields
            VStack(spacing: 24) {
                InputView(text: $email,
                          title: "Email",
                          placeholder: "name@example.com")
                .textInputAutocapitalization(.none)
                
                InputView(text: $fullName,
                          title: "Full name",
                          placeholder: "Enter your name")
                
                InputView(text: $password,
                          title: "Password",
                          placeholder: "Enter your password",
                          isSecureField: true)
                
                InputView(text: $confirmPassword,
                          title: "Confirm Password",
                          placeholder: "Confirm your password",
                          isSecureField: true)
            }
            .padding(.horizontal)
            .padding(.top, 12)
            
            //sign up button
            ButtonView(printTitle: "Create User", 
                       title: "CREATE USER",
                       systemIcon: "arrow.right") {
                Task {
                    try await viewModel.createUser(withEmail: email,
                                                   password: password,
                                                   fullname: fullName)
                }
            }
//            .disabled(formIsValid)
//            .opacity(formIsValid ? 1.0 : 0.5)
            
            Spacer()
            
            Button {
                dismiss()
            } label: {
                HStack(spacing: 3) {
                    Text("Already have an account?")
                    Text("Sign In")
                        .fontWeight(.bold)
                }
                .font(.system(size: 14))
            }
            
            
        }
    }
}

extension RegistrationView: AuthenticationFormProtocol {
    var formIsValid: Bool {
        return !email.isEmpty
        && email.contains("@")
        && !password.isEmpty
        && password.count > 5
        && confirmPassword == password
        && !fullName.isEmpty
    }
}

Replies

I fixed my problem. I forgot an "!" on the .disabled(formIsValid). It should be this .disabled(!formIsValid)