general: semi-type masturbation
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -5,3 +5,4 @@ AGENTS.md
|
|||||||
*.env
|
*.env
|
||||||
*.dmg
|
*.dmg
|
||||||
*.delta
|
*.delta
|
||||||
|
*.pem
|
||||||
|
|||||||
22
Gaze/Data/structs.swift
Normal file
22
Gaze/Data/structs.swift
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,42 +1,44 @@
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct SliderSection: View {
|
struct SliderSection: View {
|
||||||
@Binding var intervalMinutes: Int
|
@Binding var intervalSettings: RangeChoice
|
||||||
@Binding var countdownSeconds: Int
|
@Binding var countdownSettings: RangeChoice
|
||||||
@Binding var enabled: Bool
|
@Binding var enabled: Bool
|
||||||
|
|
||||||
let intervalRange: ClosedRange<Int>
|
|
||||||
let countdownRange: ClosedRange<Int>?
|
|
||||||
let type: String
|
let type: String
|
||||||
let previewFunc: () -> Void
|
let previewFunc: () -> Void
|
||||||
let reminderText: String
|
|
||||||
|
|
||||||
init(
|
init(
|
||||||
intervalMinutes: Binding<Int>,
|
intervalSettings: Binding<RangeChoice>,
|
||||||
countdownSeconds: Binding<Int>,
|
countdownSettings: Binding<RangeChoice>?,
|
||||||
intervalRange: ClosedRange<Int>,
|
|
||||||
countdownRange: ClosedRange<Int>? = nil,
|
|
||||||
enabled: Binding<Bool>,
|
enabled: Binding<Bool>,
|
||||||
type: String,
|
type: String,
|
||||||
reminderText: String,
|
|
||||||
previewFunc: @escaping () -> Void
|
previewFunc: @escaping () -> Void
|
||||||
) {
|
) {
|
||||||
self._intervalMinutes = intervalMinutes
|
self._intervalSettings = intervalSettings
|
||||||
self._countdownSeconds = countdownSeconds
|
self._countdownSettings = countdownSettings ?? .constant(RangeChoice(val: nil, range: nil))
|
||||||
self.intervalRange = intervalRange
|
|
||||||
self.countdownRange = countdownRange
|
|
||||||
self._enabled = enabled
|
self._enabled = enabled
|
||||||
self.type = type
|
self.type = type
|
||||||
self.reminderText = reminderText
|
|
||||||
self.previewFunc = previewFunc
|
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 {
|
var body: some View {
|
||||||
VStack(alignment: .leading, spacing: 20) {
|
VStack(alignment: .leading, spacing: 20) {
|
||||||
Toggle("Enable \(type.titleCase) Reminders", isOn: $enabled)
|
Toggle("Enable \(type.titleCase) Reminders", isOn: $enabled)
|
||||||
.font(.headline)
|
.font(.headline)
|
||||||
|
|
||||||
if enabled {
|
if enabled && !intervalSettings.isNil {
|
||||||
VStack(alignment: .leading, spacing: 12) {
|
VStack(alignment: .leading, spacing: 12) {
|
||||||
Text("Remind me every:")
|
Text("Remind me every:")
|
||||||
.font(.subheadline)
|
.font(.subheadline)
|
||||||
@@ -44,29 +46,34 @@ struct SliderSection: View {
|
|||||||
HStack {
|
HStack {
|
||||||
Slider(
|
Slider(
|
||||||
value: Binding(
|
value: Binding(
|
||||||
get: { Double(intervalMinutes) },
|
get: { Double(intervalSettings.val ?? 0) },
|
||||||
set: { intervalMinutes = Int($0) }
|
set: { intervalSettings.val = Int($0) }
|
||||||
),
|
),
|
||||||
in:
|
in:
|
||||||
Double(intervalRange.lowerBound)...Double(intervalRange.upperBound),
|
Double(
|
||||||
|
intervalSettings.range.bounds.lowerBound)...Double(
|
||||||
|
intervalSettings.range.bounds.upperBound),
|
||||||
step: 5.0)
|
step: 5.0)
|
||||||
Text("\(intervalMinutes) min")
|
Text("\(intervalSettings.val) min")
|
||||||
.frame(width: 60, alignment: .trailing)
|
.frame(width: 60, alignment: .trailing)
|
||||||
.monospacedDigit()
|
.monospacedDigit()
|
||||||
}
|
}
|
||||||
|
|
||||||
if let range = countdownRange {
|
if let range = countdownSettings.range {
|
||||||
Text("Look away for:")
|
Text("Look away for:")
|
||||||
.font(.subheadline)
|
.font(.subheadline)
|
||||||
.foregroundColor(.secondary)
|
.foregroundColor(.secondary)
|
||||||
HStack {
|
HStack {
|
||||||
Slider(
|
Slider(
|
||||||
value: Binding(
|
value: Binding(
|
||||||
get: { Double(countdownSeconds) },
|
get: { Double(countdownSettings.seconds ?? 0) },
|
||||||
set: { countdownSeconds = Int($0) }
|
set: { countdownSettings.seconds = Int($0) }
|
||||||
), in: Double(range.lowerBound)...Double(range.upperBound),
|
),
|
||||||
|
in:
|
||||||
|
Double(
|
||||||
|
range.bounds.lowerBound)...Double(range.bounds.upperBound),
|
||||||
step: 5.0)
|
step: 5.0)
|
||||||
Text("\(countdownSeconds) sec")
|
Text("\(countdownSettings.seconds ?? 0) sec")
|
||||||
.frame(width: 60, alignment: .trailing)
|
.frame(width: 60, alignment: .trailing)
|
||||||
.monospacedDigit()
|
.monospacedDigit()
|
||||||
}
|
}
|
||||||
@@ -77,6 +84,7 @@ struct SliderSection: View {
|
|||||||
.glassEffectIfAvailable(GlassStyle.regular, in: .rect(cornerRadius: 12))
|
.glassEffectIfAvailable(GlassStyle.regular, in: .rect(cornerRadius: 12))
|
||||||
|
|
||||||
if enabled {
|
if enabled {
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
reminderText
|
reminderText
|
||||||
)
|
)
|
||||||
@@ -111,3 +119,4 @@ struct SliderSection: View {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ import SwiftUI
|
|||||||
|
|
||||||
struct LookAwaySetupView: View {
|
struct LookAwaySetupView: View {
|
||||||
@Binding var enabled: Bool
|
@Binding var enabled: Bool
|
||||||
@Binding var intervalMinutes: Int
|
@Binding var intervalSettings: RangeChoice
|
||||||
@Binding var countdownSeconds: Int
|
@Binding var countdownSettings: RangeChoice
|
||||||
@State private var previewWindowController: NSWindowController?
|
@State private var previewWindowController: NSWindowController?
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
@@ -62,17 +62,12 @@ struct LookAwaySetupView: View {
|
|||||||
GlassStyle.regular.tint(.accentColor), in: .rect(cornerRadius: 8))
|
GlassStyle.regular.tint(.accentColor), in: .rect(cornerRadius: 8))
|
||||||
|
|
||||||
SliderSection(
|
SliderSection(
|
||||||
intervalMinutes: $intervalMinutes,
|
intervalSettings: $intervalSettings,
|
||||||
countdownSeconds: $countdownSeconds,
|
countdownSettings: $countdownSettings,
|
||||||
intervalRange: 5...90,
|
|
||||||
countdownRange: 10...30,
|
|
||||||
enabled: $enabled,
|
enabled: $enabled,
|
||||||
type: "Look away",
|
type: "Look away",
|
||||||
reminderText:
|
|
||||||
"You will be reminded every \(intervalMinutes) minutes to look in the distance for \(countdownSeconds) seconds",
|
|
||||||
previewFunc: showPreviewWindow
|
previewFunc: showPreviewWindow
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
@@ -98,7 +93,7 @@ struct LookAwaySetupView: View {
|
|||||||
window.collectionBehavior = [.canJoinAllSpaces, .fullScreenAuxiliary]
|
window.collectionBehavior = [.canJoinAllSpaces, .fullScreenAuxiliary]
|
||||||
window.acceptsMouseMovedEvents = true
|
window.acceptsMouseMovedEvents = true
|
||||||
|
|
||||||
let contentView = LookAwayReminderView(countdownSeconds: countdownSeconds) {
|
let contentView = LookAwayReminderView(countdownSeconds: countdownSettings.val ?? 20) {
|
||||||
[weak window] in
|
[weak window] in
|
||||||
window?.close()
|
window?.close()
|
||||||
}
|
}
|
||||||
@@ -114,10 +109,11 @@ struct LookAwaySetupView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#Preview("Look Away Setup View") {
|
//TODO: add this back
|
||||||
LookAwaySetupView(
|
/*#Preview("Look Away Setup View") {*/
|
||||||
enabled: .constant(true),
|
/*LookAwaySetupView(*/
|
||||||
intervalMinutes: .constant(20),
|
/*enabled: .constant(true),*/
|
||||||
countdownSeconds: .constant(20)
|
/*intervalMinutes: .constant(20),*/
|
||||||
)
|
/*countdownSeconds: .constant(20)*/
|
||||||
}
|
/*)*/
|
||||||
|
/*}*/
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import SwiftUI
|
|||||||
|
|
||||||
struct PostureSetupView: View {
|
struct PostureSetupView: View {
|
||||||
@Binding var enabled: Bool
|
@Binding var enabled: Bool
|
||||||
@Binding var intervalMinutes: Int
|
@Binding var intervalSettings: RangeChoice
|
||||||
var subtleReminderSize: ReminderSize = .medium
|
var subtleReminderSize: ReminderSize = .medium
|
||||||
@State private var previewWindowController: NSWindowController?
|
@State private var previewWindowController: NSWindowController?
|
||||||
|
|
||||||
@@ -60,65 +60,11 @@ struct PostureSetupView: View {
|
|||||||
.glassEffectIfAvailable(
|
.glassEffectIfAvailable(
|
||||||
GlassStyle.regular.tint(.accentColor), in: .rect(cornerRadius: 8))
|
GlassStyle.regular.tint(.accentColor), in: .rect(cornerRadius: 8))
|
||||||
|
|
||||||
VStack(alignment: .leading, spacing: 20) {
|
SliderSection(
|
||||||
Toggle("Enable Posture Reminders", isOn: $enabled)
|
intervalSettings: $intervalSettings,
|
||||||
.font(.headline)
|
enabled: $enabled,
|
||||||
|
type: "Posture",
|
||||||
if enabled {
|
previewFunc: showPreviewWindow
|
||||||
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)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user