diff options
Diffstat (limited to 'LibreSecrets')
-rw-r--r-- | LibreSecrets/ContentView.swift | 164 |
1 files changed, 159 insertions, 5 deletions
diff --git a/LibreSecrets/ContentView.swift b/LibreSecrets/ContentView.swift index c4de5a2..25c34c4 100644 --- a/LibreSecrets/ContentView.swift +++ b/LibreSecrets/ContentView.swift @@ -2,18 +2,172 @@ // ContentView.swift // LibreSecrets // -// Created by Christian Cleberg on 2024-01-13. +// 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..<length).map{ _ in characters.randomElement()! }) + } + + // Generates a series of words separated by "-", including a digit (optional), and capitalization (optional) per user-determined length + func randomWord(length: Int) -> 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 { - Image(systemName: "globe") - .imageScale(.large) - .foregroundStyle(.tint) - Text("Hello, world!") + + 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() } |