// // ContentView.swift // LibreSecrets // // Created by Christian Cleberg on 2024-01-10. // import SwiftUI import UniformTypeIdentifiers struct ContentView: View { // Create initial variables @State private var speed = 50.0 @State private var isEditing = false @State private var enableNumbers = false @State private var enableSpecial = false @State private var enableCapitalization = false @State private var isCopied: Bool = false // Create Picker options to choose password type enum PasswordType: String, CaseIterable, Identifiable { case random, xkcd var id: Self { self } } @State private var passwordType: PasswordType = .random // Generates a random string of alphanumeric, numeric (optional), and special (optional) characters per user-determined length func randomString(length: Int) -> String { var characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" if enableNumbers { characters.append("0123456789") } if enableSpecial { characters.append("!%&()*+,-./:;<=>?@[^_`{|}~") } return String((0.. String { var randomLine = "" for i in 1...length { if let wordsFilePath = Bundle.main.path(forResource: "words", ofType: nil) { do { let wordsString = try String(contentsOfFile: wordsFilePath) let wordLines = wordsString.components(separatedBy: .newlines) if enableCapitalization { randomLine += wordLines[numericCast(arc4random_uniform(numericCast(wordLines.count)))].capitalized } else { randomLine += wordLines[numericCast(arc4random_uniform(numericCast(wordLines.count)))] } if i != length { randomLine += "-" } if i == length && enableNumbers { randomLine += String(Int.random(in: 0..<9)) } } catch { // contentsOfFile throws an error print("Error: \(error)") } } } return randomLine } // Generate the view var body: some View { VStack { VStack { Text("Password Generator") .font(.largeTitle) Text("Save your password somewhere safe!") .font(.caption) } Form { Section(header: Text("Password Type")) { Picker("Type", selection: $passwordType) { Text("Random").tag(PasswordType.random) Text("XKCD").tag(PasswordType.xkcd) } } if passwordType == .random { Section(header: Text("Random Password")) { Slider( value: $speed, in: 8...36, step: 1 ) { Text("Characters") } minimumValueLabel: { Text("8") } maximumValueLabel: { Text("36") } onEditingChanged: { editing in isEditing = editing } .onAppear { self.speed = 12 } Toggle("Numbers", isOn: $enableNumbers) Toggle("Special Characters", isOn: $enableSpecial) } let password = randomString(length: Int(speed)) Text("\(password)") .onTapGesture { let clipboard = UIPasteboard.general clipboard.setValue(password, forPasteboardType: UTType.plainText.identifier) withAnimation { isCopied = true } DispatchQueue.main.asyncAfter(wallDeadline: .now() + 3) { withAnimation { isCopied = false } } } } else { Section(header: Text("XKCD Password")) { Slider( value: $speed, in: 1...10, step: 1 ) { Text("Words") } minimumValueLabel: { Text("1") } maximumValueLabel: { Text("10") } onEditingChanged: { editing in isEditing = editing } .onAppear { self.speed = 4 } Toggle("Numbers", isOn: $enableNumbers) Toggle("Capitalize Words", isOn: $enableCapitalization) } let password = randomWord(length: Int(speed)) Text("\(password)") .onTapGesture { let clipboard = UIPasteboard.general clipboard.setValue(password, forPasteboardType: UTType.plainText.identifier) withAnimation { isCopied = true } DispatchQueue.main.asyncAfter(wallDeadline: .now() + 3) { withAnimation { isCopied = false } } } } } if isCopied { Text("Copied successfully!") .foregroundColor(.white) .bold() .font(.footnote) .frame(width: 140, height: 30) .background(Color.indigo.cornerRadius(7)) } } .padding() } } #Preview { ContentView() }