general: semi-type masturbation

This commit is contained in:
Michael Freno
2026-01-12 12:39:39 -05:00
parent 4f799544b7
commit 359389f326
6 changed files with 76 additions and 103 deletions

1
.gitignore vendored
View File

@@ -5,3 +5,4 @@ AGENTS.md
*.env
*.dmg
*.delta
*.pem

22
Gaze/Data/structs.swift Normal file
View File

@@ -0,0 +1,22 @@
struct Range: Codable {
var bounds: ClosedRange<Int>
var step: Int
}
struct RangeChoice: Equatable {
var val: Int?
let range: Range?
static func == (lhs: RangeChoice, rhs: RangeChoice) -> Bool {
lhs.val == rhs.val && lhs.range?.bounds.lowerBound == rhs.range?.bounds.lowerBound
&& lhs.range?.bounds.upperBound == rhs.range?.bounds.upperBound
}
init(val: Int? = nil, range: Range? = nil) {
self.val = val
self.range = range
}
var isNil: Bool {
return val == nil || range == nil
}
}

View File

@@ -1,42 +1,44 @@
import SwiftUI
struct SliderSection: View {
@Binding var intervalMinutes: Int
@Binding var countdownSeconds: Int
@Binding var intervalSettings: RangeChoice
@Binding var countdownSettings: RangeChoice
@Binding var enabled: Bool
let intervalRange: ClosedRange<Int>
let countdownRange: ClosedRange<Int>?
let type: String
let previewFunc: () -> Void
let reminderText: String
init(
intervalMinutes: Binding<Int>,
countdownSeconds: Binding<Int>,
intervalRange: ClosedRange<Int>,
countdownRange: ClosedRange<Int>? = nil,
intervalSettings: Binding<RangeChoice>,
countdownSettings: Binding<RangeChoice>?,
enabled: Binding<Bool>,
type: String,
reminderText: String,
previewFunc: @escaping () -> Void
) {
self._intervalMinutes = intervalMinutes
self._countdownSeconds = countdownSeconds
self.intervalRange = intervalRange
self.countdownRange = countdownRange
self._intervalSettings = intervalSettings
self._countdownSettings = countdownSettings ?? .constant(RangeChoice(val: nil, range: nil))
self._enabled = enabled
self.type = type
self.reminderText = reminderText
self.previewFunc = previewFunc
}
var reminderText: String {
guard enabled else {
return "\(type) reminders are currently disabled."
}
if countdownSettings.isNil && intervalSettings.isNil {
return "You will be reminded every \(intervalSettings.val) minutes"
}
return
"You will be \(countdownSettings.isNil ? "subtly" : "") reminded every \(intervalSettings.val) minutes for \(countdownSettings.val!) seconds"
}
var body: some View {
VStack(alignment: .leading, spacing: 20) {
Toggle("Enable \(type.titleCase) Reminders", isOn: $enabled)
.font(.headline)
if enabled {
if enabled && !intervalSettings.isNil {
VStack(alignment: .leading, spacing: 12) {
Text("Remind me every:")
.font(.subheadline)
@@ -44,29 +46,34 @@ struct SliderSection: View {
HStack {
Slider(
value: Binding(
get: { Double(intervalMinutes) },
set: { intervalMinutes = Int($0) }
get: { Double(intervalSettings.val ?? 0) },
set: { intervalSettings.val = Int($0) }
),
in:
Double(intervalRange.lowerBound)...Double(intervalRange.upperBound),
Double(
intervalSettings.range.bounds.lowerBound)...Double(
intervalSettings.range.bounds.upperBound),
step: 5.0)
Text("\(intervalMinutes) min")
Text("\(intervalSettings.val) min")
.frame(width: 60, alignment: .trailing)
.monospacedDigit()
}
if let range = countdownRange {
if let range = countdownSettings.range {
Text("Look away for:")
.font(.subheadline)
.foregroundColor(.secondary)
HStack {
Slider(
value: Binding(
get: { Double(countdownSeconds) },
set: { countdownSeconds = Int($0) }
), in: Double(range.lowerBound)...Double(range.upperBound),
get: { Double(countdownSettings.seconds ?? 0) },
set: { countdownSettings.seconds = Int($0) }
),
in:
Double(
range.bounds.lowerBound)...Double(range.bounds.upperBound),
step: 5.0)
Text("\(countdownSeconds) sec")
Text("\(countdownSettings.seconds ?? 0) sec")
.frame(width: 60, alignment: .trailing)
.monospacedDigit()
}
@@ -77,6 +84,7 @@ struct SliderSection: View {
.glassEffectIfAvailable(GlassStyle.regular, in: .rect(cornerRadius: 12))
if enabled {
Text(
reminderText
)
@@ -111,3 +119,4 @@ struct SliderSection: View {
)
}
}

View File

@@ -14,8 +14,8 @@ import SwiftUI
struct LookAwaySetupView: View {
@Binding var enabled: Bool
@Binding var intervalMinutes: Int
@Binding var countdownSeconds: Int
@Binding var intervalSettings: RangeChoice
@Binding var countdownSettings: RangeChoice
@State private var previewWindowController: NSWindowController?
var body: some View {
@@ -62,17 +62,12 @@ struct LookAwaySetupView: View {
GlassStyle.regular.tint(.accentColor), in: .rect(cornerRadius: 8))
SliderSection(
intervalMinutes: $intervalMinutes,
countdownSeconds: $countdownSeconds,
intervalRange: 5...90,
countdownRange: 10...30,
intervalSettings: $intervalSettings,
countdownSettings: $countdownSettings,
enabled: $enabled,
type: "Look away",
reminderText:
"You will be reminded every \(intervalMinutes) minutes to look in the distance for \(countdownSeconds) seconds",
previewFunc: showPreviewWindow
)
}
Spacer()
@@ -98,7 +93,7 @@ struct LookAwaySetupView: View {
window.collectionBehavior = [.canJoinAllSpaces, .fullScreenAuxiliary]
window.acceptsMouseMovedEvents = true
let contentView = LookAwayReminderView(countdownSeconds: countdownSeconds) {
let contentView = LookAwayReminderView(countdownSeconds: countdownSettings.val ?? 20) {
[weak window] in
window?.close()
}
@@ -114,10 +109,11 @@ struct LookAwaySetupView: View {
}
}
#Preview("Look Away Setup View") {
LookAwaySetupView(
enabled: .constant(true),
intervalMinutes: .constant(20),
countdownSeconds: .constant(20)
)
}
//TODO: add this back
/*#Preview("Look Away Setup View") {*/
/*LookAwaySetupView(*/
/*enabled: .constant(true),*/
/*intervalMinutes: .constant(20),*/
/*countdownSeconds: .constant(20)*/
/*)*/
/*}*/

View File

@@ -10,7 +10,7 @@ import SwiftUI
struct PostureSetupView: View {
@Binding var enabled: Bool
@Binding var intervalMinutes: Int
@Binding var intervalSettings: RangeChoice
var subtleReminderSize: ReminderSize = .medium
@State private var previewWindowController: NSWindowController?
@@ -60,65 +60,11 @@ struct PostureSetupView: View {
.glassEffectIfAvailable(
GlassStyle.regular.tint(.accentColor), in: .rect(cornerRadius: 8))
VStack(alignment: .leading, spacing: 20) {
Toggle("Enable Posture Reminders", isOn: $enabled)
.font(.headline)
if enabled {
VStack(alignment: .leading, spacing: 12) {
Text("Remind me every:")
.font(.subheadline)
.foregroundColor(.secondary)
HStack {
Slider(
value: Binding(
get: { Double(intervalMinutes) },
set: { intervalMinutes = Int($0) }
), in: 15...90, step: 5)
Text("\(intervalMinutes) min")
.frame(width: 60, alignment: .trailing)
.monospacedDigit()
}
}
}
}
.padding()
.glassEffectIfAvailable(GlassStyle.regular, in: .rect(cornerRadius: 12))
if enabled {
Text(
"You will be subtly reminded every \(intervalMinutes) minutes to check your posture"
)
.font(.subheadline)
.foregroundColor(.secondary)
} else {
Text(
"Posture reminders are currently disabled."
)
.font(.caption)
.foregroundColor(.secondary)
}
// Preview button
Button(action: {
showPreviewWindow()
}) {
HStack(spacing: 8) {
Image(systemName: "eye")
.foregroundColor(.white)
Text("Preview Reminder")
.font(.headline)
.foregroundColor(.white)
}
.padding(.horizontal, 16)
.padding(.vertical, 10)
.contentShape(RoundedRectangle(cornerRadius: 10))
}
.buttonStyle(.plain)
.glassEffectIfAvailable(
GlassStyle.regular.tint(.accentColor).interactive(), in: .rect(cornerRadius: 10)
SliderSection(
intervalSettings: $intervalSettings,
enabled: $enabled,
type: "Posture",
previewFunc: showPreviewWindow
)
}

View File

@@ -1 +0,0 @@
/Users/mike/Code/freno-dev