- Menu-List - App Lifecycle.
- Menu-List - Model.
- Menu-List - List View.
- Menu-List - Network Manager.
- Menu-List - Connecting the UI.
- Menu-List - Errors & Alerts.
- Menu-List - Loading View.
- Menu-List - Download Image.
- Menu-List - Remote Image.
- Menu-List - Project cleanup & organization.
- Menu-List - Detail View UI Setup.
- Menu-List - Detail View UI Connections.
- Menu-List - Detail View Refactor.
- Menu-List - Account View UI Setup.
- Menu-List - View Model & Text Validation.
- Menu-List - @AppStorage.
- Menu-List - Order Screen UI.
- Menu-List - Empty State.
- Menu-List - @EnvironmentObject - Order.
- Menu-List - iOS 15 - Initial Run.
- Menu-List - iOS 15 - Tabbar Badge & List Separator.
- Menu-List - iOS 15 - @FocusState Keyboard.
- Menu-List - iOS 15 - Async/Await Network Calls.
- Menu-List - iOS 15 - AsyncImage.
- Menu-List - iOS 16 - Regex, guard let.
- Menu-List - App Optimizations.
- Menu-List - Data Flow Review.
- Menu-List - iOS 17 @Observable.
![](https://private-user-images.githubusercontent.com/64445918/306377337-b3b98761-0bc6-4447-b576-3a3fe293ab39.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mzg5ODY1OTUsIm5iZiI6MTczODk4NjI5NSwicGF0aCI6Ii82NDQ0NTkxOC8zMDYzNzczMzctYjNiOTg3NjEtMGJjNi00NDQ3LWI1NzYtM2EzZmUyOTNhYjM5LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTAyMDglMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwMjA4VDAzNDQ1NVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTIyZDk3NDkyMGY4MjU3ZmFiYmM0YTVjZDc3YjJkNTFlNmIwNGIyODNjMDcwM2VjNjAyMzI1ZDk0MzY5NWQ0NjImWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.YOMiNGmzWuNP2OQ2AiMuOqvViIVGBeUCWdPgQpa5TM4)
![](https://private-user-images.githubusercontent.com/64445918/306377376-8173ecb9-03ce-4077-9e72-118c2fda9d1e.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mzg5ODY1OTUsIm5iZiI6MTczODk4NjI5NSwicGF0aCI6Ii82NDQ0NTkxOC8zMDYzNzczNzYtODE3M2VjYjktMDNjZS00MDc3LTllNzItMTE4YzJmZGE5ZDFlLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTAyMDglMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwMjA4VDAzNDQ1NVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPThkZDg5OWEwZmE4YmFlM2E1MDkxNmMzMDE2ZWEwODQxZWQ3MjgyYmJlYTBkYjBjODIwMjdlYTYxMzdiMWYxZjImWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.UYRz58b_HEHpV-7z9WZrlpPKJeQttZumt9BkTZ9SryQ)
![](https://private-user-images.githubusercontent.com/64445918/306377395-615dd51b-2436-467b-87b0-f5ad3797cbd6.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mzg5ODY1OTUsIm5iZiI6MTczODk4NjI5NSwicGF0aCI6Ii82NDQ0NTkxOC8zMDYzNzczOTUtNjE1ZGQ1MWItMjQzNi00NjdiLTg3YjAtZjVhZDM3OTdjYmQ2LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTAyMDglMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwMjA4VDAzNDQ1NVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTM0YjdhNWI0ZDU3MWIwODlmNWFkZDFjOTcyZTI3NmVhNGViNTVhODIyZjA0ZmZiZGRlMGE0YmJhMDI5M2Y4OGQmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.QAfZmdqlr5AYmvRDgbwBzenNMgdg3pNkAqW3jbN_PvY)
![](https://private-user-images.githubusercontent.com/64445918/306377416-84cd9412-f720-4561-a86c-ad8302129fc5.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mzg5ODY1OTUsIm5iZiI6MTczODk4NjI5NSwicGF0aCI6Ii82NDQ0NTkxOC8zMDYzNzc0MTYtODRjZDk0MTItZjcyMC00NTYxLWE4NmMtYWQ4MzAyMTI5ZmM1LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTAyMDglMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwMjA4VDAzNDQ1NVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTdjM2NlYmU4MWNkMTA5NjRkMDcxM2UwNzJlOWNkMzZjMWY1NmFmYzUzMzc4NTZlYmI1ZDgyMjRhODg2ODE0ZjYmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.UXytRbmYjhXZyWMhTsBcBny2T_o954Lhukdacd3GNIU)
![](https://private-user-images.githubusercontent.com/64445918/306377461-61e1528f-6a97-458f-b2c1-d3158fe469a4.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mzg5ODY1OTUsIm5iZiI6MTczODk4NjI5NSwicGF0aCI6Ii82NDQ0NTkxOC8zMDYzNzc0NjEtNjFlMTUyOGYtNmE5Ny00NThmLWIyYzEtZDMxNThmZTQ2OWE0LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTAyMDglMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwMjA4VDAzNDQ1NVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTU3YTRmNmNhYWJjYmVmZjBhOTY4OWYxZGZmMjRjNmZmYzdhZjdiYjAzMDBmOTVhYjY3MDViMjQ1YWIyZGM5NzMmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.Z-4JXnPh8of-SEH19Cbc0dgHFX7tlsDTZhEPOPyurgY)
![](https://private-user-images.githubusercontent.com/64445918/306377479-244ec164-bc41-4945-98c8-5db4233db166.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mzg5ODY1OTUsIm5iZiI6MTczODk4NjI5NSwicGF0aCI6Ii82NDQ0NTkxOC8zMDYzNzc0NzktMjQ0ZWMxNjQtYmM0MS00OTQ1LTk4YzgtNWRiNDIzM2RiMTY2LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTAyMDglMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwMjA4VDAzNDQ1NVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTBmZGU3MDQzZjg5NWY1NDM3YTNjNWMwZTQ4YzExN2ExZjJkODIxOWM5MThjNDYwZmEwN2U0M2M3MjY4YmNiNmImWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.0PJBuCs4ok7QoGbkmxP5Jqks9-Ize3VY71NCBVErR_k)
![](https://private-user-images.githubusercontent.com/64445918/306377488-26c64df8-61a7-48c7-9991-1b3e4479934a.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mzg5ODY1OTUsIm5iZiI6MTczODk4NjI5NSwicGF0aCI6Ii82NDQ0NTkxOC8zMDYzNzc0ODgtMjZjNjRkZjgtNjFhNy00OGM3LTk5OTEtMWIzZTQ0Nzk5MzRhLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTAyMDglMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwMjA4VDAzNDQ1NVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWZhNTk1YzkzM2JkZThkOWE4YzU5MTU4MmY0YTYwNjcxYWU1M2YzYjBlMWFlYzhlZTY4MjNiYTllODEzMzY4ZmQmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.oSTkHJFSa3GfmLQuMpBuHSocl20NS1D2kuUuK_3s1qU)
![](https://private-user-images.githubusercontent.com/64445918/306377501-ec8ba921-701b-4aee-b86a-ed01b62fe4c6.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mzg5ODY1OTUsIm5iZiI6MTczODk4NjI5NSwicGF0aCI6Ii82NDQ0NTkxOC8zMDYzNzc1MDEtZWM4YmE5MjEtNzAxYi00YWVlLWI4NmEtZWQwMWI2MmZlNGM2LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTAyMDglMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwMjA4VDAzNDQ1NVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWVlMzRmNTZhOGY3ZGMzNmIwNGI4ZWMzOWU5ODdhY2Y2NzllZDc5MGM0ZjQ5YmI5ZmFhZmI0ZjJiMTRiOGY5MWImWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.j5nr1yeEh9JI4xKz8WEqVjkr0pfG58JSG0VSnkeG9Cc)
![](https://private-user-images.githubusercontent.com/64445918/306377509-a4e56d7f-d721-4aec-8647-f12015b31995.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mzg5ODY1OTUsIm5iZiI6MTczODk4NjI5NSwicGF0aCI6Ii82NDQ0NTkxOC8zMDYzNzc1MDktYTRlNTZkN2YtZDcyMS00YWVjLTg2NDctZjEyMDE1YjMxOTk1LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTAyMDglMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwMjA4VDAzNDQ1NVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTBiZmY4YWYxNGQ4ZWFlM2M4YjZiMGU4ZTQyNTNlOTdjMDYwNDc4NTI5NmFlYzQ2YjRlOTg4ZGQ5ODkxMTkyM2MmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.xW2-zcaFLK5zr4T678FhQJPJ63kvcbeEqvG_FKnLH3w)
![](https://private-user-images.githubusercontent.com/64445918/306377515-009818bb-c071-4340-a8a7-c248456f96a3.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mzg5ODY1OTUsIm5iZiI6MTczODk4NjI5NSwicGF0aCI6Ii82NDQ0NTkxOC8zMDYzNzc1MTUtMDA5ODE4YmItYzA3MS00MzQwLWE4YTctYzI0ODQ1NmY5NmEzLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTAyMDglMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwMjA4VDAzNDQ1NVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWQ0Zjk1ZWRlNGJiMzM4NTA1Y2JhYTllNWUwM2ZlOTc3OTg0ZjFmZTc3NTUzMGMwMjBjODNiNjJiMWI3OGM4YTUmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.iFtjh1RfyZi658Nd5jjna-KG25o8opS_5Gn-cGFncZk)
extension String {
var isValidEmail: Bool {
let emailFormat = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
let emailPredicate = NSPredicate(format: "SELF MATCHES %@", emailFormat)
return emailPredicate.evaluate(with: self)
}
}
import SwiftUI
import RegexBuilder
extension String {
var isValidEmail: Bool {
let emailRegex = Regex {
OneOrMore {
CharacterClass(
.anyOf("._%+-"),
("A"..."Z"),
("0"..."9"),
("a"..."z")
)
}
"@"
OneOrMore {
CharacterClass(
.anyOf("-"),
("A"..."Z"),
("a"..."z"),
("0"..."9")
)
}
"."
Repeat(2...64) {
CharacterClass(
("A"..."Z"),
("a"..."z")
)
}
}
return self.wholeMatch(of: emailRegex) != nil
}
}
struct StandardButton: ViewModifier {
func body(content: Content) -> some View {
content
.buttonStyle(.bordered)
.tint(.brandPrimary)
.controlSize(.large)
}
}
extension View {
func standardButton() -> some View {
self.modifier(StandardButton())
}
}
.modifier(StandardButton())
.standardButton()
import SwiftUI
struct AdaptiveTextField: View {
@State private var text: String = ""
var body: some View {
HStack {
TextField("Enter text", text: $text)
.padding(.horizontal, 16)
.padding(.vertical, 10)
.background(
Capsule()
.fill(Color.blue)
)
.foregroundColor(.white)
.font(.system(size: 18, weight: .semibold, design: .rounded))
.frame(minWidth: 50)
.fixedSize(horizontal: true, vertical: false)
}
.padding()
}
}
#Preview {
AdaptiveTextField()
}