mirror of
https://github.com/neon443/RNG_Swift.git
synced 2026-03-11 06:49:12 +00:00
Rewrote basically half the app
+ reamde + noDebug.xcscheme + ui improvements +max die is 100+overflow protextion +fix giant padding in diceview +rewrite rng2() +ui friedlification +rewrite arrCombine
This commit is contained in:
8
README.md
Normal file
8
README.md
Normal file
@@ -0,0 +1,8 @@
|
||||
# RNG_Swift
|
||||
|
||||
A fully featured Randomizer written in Swift with UI in SwiftUI!
|
||||
|
||||
## Features
|
||||
- Number generator
|
||||
- Password generator
|
||||
- Die Generator
|
||||
78
RNG.xcodeproj/xcshareddata/xcschemes/RNG-noDebug.xcscheme
Normal file
78
RNG.xcodeproj/xcshareddata/xcschemes/RNG-noDebug.xcscheme
Normal file
@@ -0,0 +1,78 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1610"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES"
|
||||
buildArchitectures = "Automatic">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "A9794C7E2CB70ADA00527984"
|
||||
BuildableName = "RNG.app"
|
||||
BlueprintName = "RNG"
|
||||
ReferencedContainer = "container:RNG.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
shouldAutocreateTestPlan = "YES">
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = ""
|
||||
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "A9794C7E2CB70ADA00527984"
|
||||
BuildableName = "RNG.app"
|
||||
BlueprintName = "RNG"
|
||||
ReferencedContainer = "container:RNG.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "A9794C7E2CB70ADA00527984"
|
||||
BuildableName = "RNG.app"
|
||||
BlueprintName = "RNG"
|
||||
ReferencedContainer = "container:RNG.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
@@ -12,22 +12,23 @@ struct ContentView: View {
|
||||
VStack {
|
||||
NavigationSplitView {
|
||||
List {
|
||||
Section("Generate...") {
|
||||
NavigationLink {
|
||||
NumberView()
|
||||
.navigationTitle("Random Number Generator")
|
||||
.navigationTitle("Numbers")
|
||||
} label: {
|
||||
HStack {
|
||||
Text("Random Number Generator")
|
||||
Text("Numbers")
|
||||
Spacer()
|
||||
Image(systemName: "textformat.123")
|
||||
}
|
||||
}
|
||||
NavigationLink {
|
||||
DiceView()
|
||||
.navigationTitle("Dice")
|
||||
.navigationTitle("Die")
|
||||
} label: {
|
||||
HStack {
|
||||
Text("Dice")
|
||||
Text("Die")
|
||||
Spacer()
|
||||
Image(systemName: "die.face.1")
|
||||
Image(systemName: "die.face.2.fill")
|
||||
@@ -39,10 +40,10 @@ struct ContentView: View {
|
||||
}
|
||||
NavigationLink {
|
||||
PasswordView()
|
||||
.navigationTitle("Password")
|
||||
.navigationTitle("Passwords")
|
||||
} label: {
|
||||
HStack {
|
||||
Text("Password")
|
||||
Text("Passwords")
|
||||
Spacer()
|
||||
Image(systemName: "rectangle.and.pencil.and.ellipsis")
|
||||
}
|
||||
@@ -50,6 +51,7 @@ struct ContentView: View {
|
||||
}
|
||||
.navigationTitle("RNG")
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
}
|
||||
} detail: {
|
||||
Image(systemName: "dice.fill")
|
||||
}
|
||||
@@ -57,3 +59,6 @@ struct ContentView: View {
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
ContentView()
|
||||
}
|
||||
|
||||
@@ -8,28 +8,38 @@
|
||||
import SwiftUI
|
||||
|
||||
struct DiceView: View {
|
||||
@State var generated: [Int] = [0]
|
||||
@State var advanced: Bool = false
|
||||
@State var generated: [Int] = []
|
||||
@State var displayDies: [Int] = []
|
||||
@State var displayMultiDieMode = ""
|
||||
@State var multiDieMode = "plus"
|
||||
@State var result = 0
|
||||
@State var result: UInt = 0
|
||||
@State var resultDescription = ""
|
||||
@State var history: [Int] = []
|
||||
let columns = [GridItem(.adaptive(minimum: 25, maximum: 75))]
|
||||
@State var dies: Double = 2
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
List {
|
||||
Section("Number of die") {
|
||||
Toggle(isOn: $advanced) {
|
||||
Text("Advanced Mode")
|
||||
}
|
||||
HStack {
|
||||
Text( String( Int(dies) ) )
|
||||
.font(.system(size: 25, weight: .bold))
|
||||
Text(String(Int(dies)))
|
||||
.font(.system(size: 20, weight: .heavy))
|
||||
.frame(width: ((dies > 99) ? 40 : (dies > 9) ? 30 : 20))
|
||||
Divider()
|
||||
Text("1")
|
||||
if advanced {
|
||||
Slider(value: $dies, in: 1...100, step: 1)
|
||||
Text("100")
|
||||
} else {
|
||||
Slider(value: $dies, in: 1...20, step: 1)
|
||||
Text("20")
|
||||
}
|
||||
}
|
||||
}
|
||||
Section("Multi die mode") {
|
||||
Picker(selection: $multiDieMode, label: Text("ioug")) {
|
||||
Image(systemName: "plus").tag("plus")
|
||||
@@ -37,36 +47,36 @@ struct DiceView: View {
|
||||
}.pickerStyle(SegmentedPickerStyle())
|
||||
}
|
||||
Section("Visual") {
|
||||
HStack {
|
||||
Spacer()
|
||||
if displayDies.isEmpty {
|
||||
Text("Results are visualised here when you press the generate button")
|
||||
.font(.subheadline)
|
||||
Text("Tap Generate to get started!")
|
||||
.font(.headline)
|
||||
.fontWeight(.heavy)
|
||||
.frame(alignment: .center)
|
||||
} else {
|
||||
LazyVGrid(columns: columns, spacing: 10) {
|
||||
LazyVGrid(columns: columns, spacing: 2.5) {
|
||||
ForEach(0..<displayDies.count, id: \.self) { index in
|
||||
Image(systemName: "die.face.\(displayDies[index])")
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.frame(width: 50, height: 50)
|
||||
.frame(width: 40, height: 40)
|
||||
if index != displayDies.count-1 {
|
||||
Image(systemName: displayMultiDieMode)
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.frame(width: 10, height: 10)
|
||||
.frame(width: 15, height: 15)
|
||||
}
|
||||
}
|
||||
}.padding()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Text(String(result))
|
||||
.font(.system(size: 75, weight: .bold))
|
||||
.font(.system(size: 50, weight: .bold))
|
||||
.foregroundColor(.gray)
|
||||
.frame(height: 50)
|
||||
.frame(height: 40)
|
||||
Text(resultDescription)
|
||||
.frame(height: 20)
|
||||
.frame(height: 10)
|
||||
.font(.system(size: 10))
|
||||
Button {
|
||||
generated = rngN6DieArr(dies: Int(dies))
|
||||
displayDies = generated
|
||||
@@ -90,12 +100,12 @@ func describeResult(inp: [Int], combineMode: String) -> String {
|
||||
var result = ""
|
||||
var symbol = ""
|
||||
if inp.isEmpty {
|
||||
return "0"
|
||||
return ""
|
||||
} else {
|
||||
if combineMode == "plus" {
|
||||
symbol = " + "
|
||||
symbol = "+"
|
||||
} else if combineMode == "multiply" {
|
||||
symbol = " x "
|
||||
symbol = "x"
|
||||
}
|
||||
for i in 0...len {
|
||||
if i == len {
|
||||
@@ -104,7 +114,6 @@ func describeResult(inp: [Int], combineMode: String) -> String {
|
||||
result += String(inp[i]) + symbol
|
||||
}
|
||||
}
|
||||
result += " = " + String(arrCombine(arr: inp, combineMode: combineMode))
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,36 +5,17 @@
|
||||
// Created by Nihaal on 09/10/2024.
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//fix date created
|
||||
//TODO: readd ios 16 support
|
||||
//TODO: try to use inject
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct NumberView: View {
|
||||
@State var low: String = "1"
|
||||
@State var high: String = "10"
|
||||
@State var exclude: String = "none"
|
||||
@State var generated = "5"
|
||||
@State var generated = ""
|
||||
@State var prevGen = ""
|
||||
@State var generatedInt: Int = 0
|
||||
@State var prevGenInt: Int = 0
|
||||
@State var dispResult = 5
|
||||
@State var dispResult = 0
|
||||
var body: some View {
|
||||
List {
|
||||
HStack {
|
||||
@@ -65,30 +46,18 @@ struct NumberView: View {
|
||||
}
|
||||
Section("Description") {
|
||||
Text(describeInputs(min: low, max: high, exclude: exclude))
|
||||
.font(.headline)
|
||||
.fontWeight(.heavy)
|
||||
.frame(alignment: .center)
|
||||
}
|
||||
}
|
||||
Text(String(dispResult))
|
||||
.font(.system(size: 75, weight: .bold))
|
||||
Text(generated)
|
||||
.font(.system(size: 50, weight: .bold))
|
||||
.foregroundColor(.gray)
|
||||
.frame(height: 50)
|
||||
.frame(height: 40)
|
||||
Button {
|
||||
prevGen = generated
|
||||
generated = rng2(min: low, max: high, exclude: exclude)
|
||||
prevGenInt = Int(prevGen)!
|
||||
generatedInt = Int(generated)!
|
||||
if prevGenInt < generatedInt {
|
||||
for _ in prevGenInt...generatedInt {
|
||||
dispResult += 1
|
||||
//sleep( UInt32( 1 / (generatedInt - prevGenInt) ) )
|
||||
}
|
||||
} else if prevGenInt > generatedInt {
|
||||
for _ in generatedInt...prevGenInt {
|
||||
dispResult -= 1
|
||||
//sleep( UInt32( 1 / (prevGenInt - generatedInt) ) )
|
||||
}
|
||||
} else if prevGenInt == generatedInt {
|
||||
dispResult = generatedInt
|
||||
}
|
||||
generated = rng3(min: low, max: high, exclude: exclude)
|
||||
} label: {
|
||||
Text("Generate")
|
||||
.padding(.horizontal)
|
||||
@@ -96,25 +65,25 @@ struct NumberView: View {
|
||||
}
|
||||
.buttonStyle(BorderedProminentButtonStyle())
|
||||
.cornerRadius(15)
|
||||
.padding(.bottom)
|
||||
.padding(.vertical)
|
||||
}
|
||||
}
|
||||
|
||||
func describeInputs(min: String, max: String, exclude: String) -> String {
|
||||
let validExcludes = ["start", "end", "both", "none"]
|
||||
let validExcludes = ["start", "none", "end", "both"]
|
||||
guard validExcludes.contains(exclude) else {
|
||||
print("invalid exclude: " + exclude)
|
||||
return "invalid exclude: " + exclude
|
||||
}
|
||||
|
||||
var result = "Any number from "
|
||||
result += min != "" ? min : "_"
|
||||
result += min
|
||||
result += " to "
|
||||
result += max != "" ? max : "_"
|
||||
result += max
|
||||
|
||||
if min == "" || max == "" {
|
||||
return "Enter values above."
|
||||
} else {
|
||||
}
|
||||
switch exclude {
|
||||
case "start":
|
||||
result += ", excluding \(min)"
|
||||
@@ -127,47 +96,30 @@ func describeInputs(min: String, max: String, exclude: String) -> String {
|
||||
default:
|
||||
result = "invalid 'exclude'"
|
||||
}
|
||||
}
|
||||
result += "."
|
||||
return result
|
||||
return result + "."
|
||||
}
|
||||
|
||||
enum rng2Errors: Error {
|
||||
case h
|
||||
}
|
||||
|
||||
func rng2(min: String, max: String, exclude: String) -> String {
|
||||
guard min != "" || max != "" else {
|
||||
return "Enter values above."
|
||||
func rng3(min: String, max: String, exclude: String) -> String {
|
||||
var newMin = Int(min)!
|
||||
var newMax = Int(max)!
|
||||
guard newMin <= newMax else {
|
||||
return "Invalid inputs"
|
||||
}
|
||||
guard var minInt = Int(min) else {
|
||||
print("invalid min")
|
||||
return "-1"
|
||||
guard newMin != newMax else {
|
||||
return "No numbers"
|
||||
}
|
||||
guard var maxInt = Int(max), maxInt >= minInt else {
|
||||
print("invalid max or is less than min")
|
||||
return "-1"
|
||||
guard newMin + 1 != newMax else {
|
||||
return "No numbers"
|
||||
}
|
||||
guard exclude != "both", min != max else {
|
||||
print("excluding both but min == max")
|
||||
return "No possible numbers, both bounds equal."
|
||||
}
|
||||
let minIntPlus1 = minInt + 1
|
||||
guard exclude != "both", minIntPlus1 != maxInt else {
|
||||
print("excluding both but min +1 == max")
|
||||
return "No possible numbers."
|
||||
}
|
||||
var generated = 0
|
||||
if exclude == "both" {
|
||||
maxInt -= 1
|
||||
minInt += 1
|
||||
newMax -= 1
|
||||
newMin += 1
|
||||
} else if exclude == "start" {
|
||||
minInt += 1
|
||||
newMin += 1
|
||||
} else if exclude == "end" {
|
||||
maxInt -= 1
|
||||
newMax -= 1
|
||||
}
|
||||
generated = rng(min: minInt, max: maxInt)
|
||||
return String(generated)
|
||||
return String(rng(min: newMin, max: newMax))
|
||||
}
|
||||
|
||||
#Preview {
|
||||
|
||||
@@ -10,12 +10,12 @@ import SwiftUI
|
||||
struct PasswordView: View {
|
||||
@State var selectedOptions: [PassOption] = []
|
||||
let options: [PassOption] = [
|
||||
PassOption(name: "0-9", chars: Array("0123456789")),
|
||||
PassOption(name: "a-z", chars: Array("abcdefghijklmnopqrstuvwxyz")),
|
||||
PassOption(name: "A-Z", chars: Array("ABCDEFGHIJKLMNOPQRSTUVWXYZ"))
|
||||
PassOption(name: "Digits", chars: Array("0123456789")),
|
||||
PassOption(name: "Lowercase characters", chars: Array("abcdefghijklmnopqrstuvwxyz")),
|
||||
PassOption(name: "Uppercase characters", chars: Array("ABCDEFGHIJKLMNOPQRSTUVWXYZ"))
|
||||
]
|
||||
@State var presetLen = 4
|
||||
@State var customLen = 8
|
||||
@State var customLen: Int = 0
|
||||
@State var generated = ""
|
||||
@State var result = ""
|
||||
@State var history: [Int] = []
|
||||
@@ -23,16 +23,6 @@ struct PasswordView: View {
|
||||
var body: some View {
|
||||
VStack {
|
||||
List {
|
||||
Text("Hello, world!")
|
||||
.font(.largeTitle)
|
||||
.foregroundColor(.white)
|
||||
.padding()
|
||||
.background(Color.blue)
|
||||
.padding()
|
||||
.background(Color.mint)
|
||||
.padding()
|
||||
.background(Color.green)
|
||||
|
||||
Section("Include") {
|
||||
ForEach(options) { option in
|
||||
Toggle(isOn: Binding(
|
||||
@@ -59,23 +49,19 @@ struct PasswordView: View {
|
||||
Text("Custom: \(customLen)").tag(-1)
|
||||
}
|
||||
.pickerStyle(SegmentedPickerStyle())
|
||||
}
|
||||
|
||||
if presetLen == -1 {
|
||||
TextField("Custom", value: $customLen, formatter: NumberFormatter())
|
||||
.keyboardType(.numberPad)
|
||||
.frame(width: 50)
|
||||
}
|
||||
|
||||
Text(String(result))
|
||||
.font(.system(size: 75, weight: .bold))
|
||||
.foregroundColor(.gray)
|
||||
.frame(height: 50)
|
||||
}
|
||||
}
|
||||
|
||||
Text(String(generated))
|
||||
.font(.system(size: 75, weight: .bold))
|
||||
.font(.system(size: 50, weight: .bold))
|
||||
.foregroundColor(.gray)
|
||||
.frame(height: 50)
|
||||
.frame(height: 40)
|
||||
|
||||
Button {
|
||||
generated = genPass(selectdOpts: selectedOptions, len: (presetLen == -1 ? customLen : presetLen))
|
||||
@@ -89,7 +75,6 @@ struct PasswordView: View {
|
||||
.padding(.vertical)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
struct Option: Identifiable {
|
||||
let id: Int
|
||||
|
||||
@@ -35,15 +35,22 @@ func totalDoubleArr(arr: [Double]) -> Double {
|
||||
}
|
||||
|
||||
// array combiner, adds or multiplies all ints in an array
|
||||
func arrCombine(arr: [Int], combineMode: String) -> Int {
|
||||
var output = 0
|
||||
func arrCombine(arr: [Int], combineMode: String) -> UInt {
|
||||
var newArr: [UInt] = []
|
||||
for i in 0...(arr.count-1) {
|
||||
newArr.append(UInt(arr[i]))
|
||||
}
|
||||
var output: UInt = 0
|
||||
if combineMode == "plus" {
|
||||
for num in arr {
|
||||
for num in newArr {
|
||||
output += num
|
||||
}
|
||||
} else if combineMode == "multiply" {
|
||||
output = 1
|
||||
for num in arr {
|
||||
for num in newArr {
|
||||
guard output <= UInt.max / num else {
|
||||
return UInt.max //cap at uint.max 2^64
|
||||
}
|
||||
output *= num
|
||||
}
|
||||
} else {
|
||||
@@ -53,11 +60,8 @@ func arrCombine(arr: [Int], combineMode: String) -> Int {
|
||||
return output
|
||||
}
|
||||
|
||||
|
||||
func rng(min: Int, max: Int) -> Int {
|
||||
var rng = 0
|
||||
rng = Int.random(in: min...max)
|
||||
return rng
|
||||
return Int.random(in: min...max)
|
||||
}
|
||||
|
||||
func rng6Die() -> Int {
|
||||
@@ -69,6 +73,7 @@ func rngCDie(min: Int, max: Int) -> Int {
|
||||
}
|
||||
|
||||
func rngN6DieArr(dies: Int) -> [Int] {
|
||||
guard dies > 0 else { return [] }
|
||||
var output: [Int] = []
|
||||
for _ in 1...dies {
|
||||
output.append(rng6Die())
|
||||
|
||||
Reference in New Issue
Block a user