general: continued refinements
This commit is contained in:
@@ -34,7 +34,7 @@ struct LookAwaySetupView: View {
|
|||||||
|
|
||||||
// Vertically centered content
|
// Vertically centered content
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
VStack(spacing: 30) {
|
VStack(spacing: 30) {
|
||||||
// InfoBox with link functionality
|
// InfoBox with link functionality
|
||||||
HStack(spacing: 12) {
|
HStack(spacing: 12) {
|
||||||
@@ -74,7 +74,7 @@ struct LookAwaySetupView: View {
|
|||||||
value: Binding(
|
value: Binding(
|
||||||
get: { Double(intervalMinutes) },
|
get: { Double(intervalMinutes) },
|
||||||
set: { intervalMinutes = Int($0) }
|
set: { intervalMinutes = Int($0) }
|
||||||
), in: 5...60, step: 5)
|
), in: 5...90, step: 5)
|
||||||
|
|
||||||
Text("\(intervalMinutes) min")
|
Text("\(intervalMinutes) min")
|
||||||
.frame(width: 60, alignment: .trailing)
|
.frame(width: 60, alignment: .trailing)
|
||||||
@@ -117,7 +117,7 @@ struct LookAwaySetupView: View {
|
|||||||
.foregroundColor(.secondary)
|
.foregroundColor(.secondary)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
}
|
}
|
||||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ struct OnboardingContainerView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.frame(minWidth: 1000, minHeight: 750)
|
.frame(minWidth: 1000, minHeight: 800)
|
||||||
.opacity(isAnimatingOut ? 0 : 1)
|
.opacity(isAnimatingOut ? 0 : 1)
|
||||||
.scaleEffect(isAnimatingOut ? 0.3 : 1.0)
|
.scaleEffect(isAnimatingOut ? 0.3 : 1.0)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ struct SettingsOnboardingView: View {
|
|||||||
.padding(.top, 20)
|
.padding(.top, 20)
|
||||||
.padding(.bottom, 30)
|
.padding(.bottom, 30)
|
||||||
|
|
||||||
// Vertically centered content
|
|
||||||
Spacer()
|
Spacer()
|
||||||
VStack(spacing: 30) {
|
VStack(spacing: 30) {
|
||||||
Text("Configure app preferences and support the project")
|
Text("Configure app preferences and support the project")
|
||||||
@@ -34,7 +33,6 @@ struct SettingsOnboardingView: View {
|
|||||||
.multilineTextAlignment(.center)
|
.multilineTextAlignment(.center)
|
||||||
|
|
||||||
VStack(spacing: 20) {
|
VStack(spacing: 20) {
|
||||||
// Launch at Login Toggle
|
|
||||||
HStack {
|
HStack {
|
||||||
VStack(alignment: .leading, spacing: 4) {
|
VStack(alignment: .leading, spacing: 4) {
|
||||||
Text("Launch at Login")
|
Text("Launch at Login")
|
||||||
@@ -62,13 +60,41 @@ struct SettingsOnboardingView: View {
|
|||||||
.font(.caption)
|
.font(.caption)
|
||||||
.foregroundColor(.secondary)
|
.foregroundColor(.secondary)
|
||||||
|
|
||||||
Picker("Size", selection: $subtleReminderSize) {
|
HStack(spacing: 12) {
|
||||||
ForEach(ReminderSize.allCases, id: \.self) { size in
|
ForEach(ReminderSize.allCases, id: \.self) { size in
|
||||||
Text(size.displayName).tag(size)
|
Button(action: {
|
||||||
|
subtleReminderSize = size
|
||||||
|
}) {
|
||||||
|
VStack(spacing: 8) {
|
||||||
|
Circle()
|
||||||
|
.fill(
|
||||||
|
subtleReminderSize == size
|
||||||
|
? Color.accentColor
|
||||||
|
: Color.secondary.opacity(0.3)
|
||||||
|
)
|
||||||
|
.frame(
|
||||||
|
width: iconSize(for: size),
|
||||||
|
height: iconSize(for: size))
|
||||||
|
|
||||||
|
Text(size.displayName)
|
||||||
|
.font(.caption)
|
||||||
|
.fontWeight(
|
||||||
|
subtleReminderSize == size ? .semibold : .regular
|
||||||
|
)
|
||||||
|
.foregroundColor(
|
||||||
|
subtleReminderSize == size ? .primary : .secondary)
|
||||||
|
}
|
||||||
|
.frame(maxWidth: .infinity, minHeight: 60)
|
||||||
|
.padding(.vertical, 12)
|
||||||
|
}
|
||||||
|
.glassEffect(
|
||||||
|
subtleReminderSize == size
|
||||||
|
? .regular.tint(.accentColor.opacity(0.3))
|
||||||
|
: .regular,
|
||||||
|
in: .rect(cornerRadius: 10)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.pickerStyle(.segmented)
|
|
||||||
.labelsHidden()
|
|
||||||
}
|
}
|
||||||
.padding()
|
.padding()
|
||||||
.glassEffect(.regular, in: .rect(cornerRadius: 12))
|
.glassEffect(.regular, in: .rect(cornerRadius: 12))
|
||||||
@@ -158,6 +184,14 @@ struct SettingsOnboardingView: View {
|
|||||||
print("Failed to set launch at login: \(error)")
|
print("Failed to set launch at login: \(error)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func iconSize(for size: ReminderSize) -> CGFloat {
|
||||||
|
switch size {
|
||||||
|
case .small: return 20
|
||||||
|
case .medium: return 32
|
||||||
|
case .large: return 48
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#Preview("Settings Onboarding - Launch Disabled") {
|
#Preview("Settings Onboarding - Launch Disabled") {
|
||||||
|
|||||||
@@ -74,7 +74,8 @@ struct UserTimersView: View {
|
|||||||
} else {
|
} else {
|
||||||
ScrollView {
|
ScrollView {
|
||||||
VStack(spacing: 8) {
|
VStack(spacing: 8) {
|
||||||
ForEach(Array(userTimers.enumerated()), id: \.element.id) { index, timer in
|
ForEach(Array(userTimers.enumerated()), id: \.element.id) {
|
||||||
|
index, timer in
|
||||||
UserTimerRow(
|
UserTimerRow(
|
||||||
timer: $userTimers[index],
|
timer: $userTimers[index],
|
||||||
onEdit: {
|
onEdit: {
|
||||||
@@ -144,7 +145,7 @@ struct UserTimerRow: View {
|
|||||||
Circle()
|
Circle()
|
||||||
.fill(timer.color)
|
.fill(timer.color)
|
||||||
.frame(width: 12, height: 12)
|
.frame(width: 12, height: 12)
|
||||||
|
|
||||||
Image(systemName: timer.type == .subtle ? "eye.circle" : "rectangle.on.rectangle")
|
Image(systemName: timer.type == .subtle ? "eye.circle" : "rectangle.on.rectangle")
|
||||||
.foregroundColor(timer.color)
|
.foregroundColor(timer.color)
|
||||||
.frame(width: 24)
|
.frame(width: 24)
|
||||||
@@ -166,7 +167,7 @@ struct UserTimerRow: View {
|
|||||||
.labelsHidden()
|
.labelsHidden()
|
||||||
.toggleStyle(.switch)
|
.toggleStyle(.switch)
|
||||||
.controlSize(.small)
|
.controlSize(.small)
|
||||||
|
|
||||||
Button(action: onEdit) {
|
Button(action: onEdit) {
|
||||||
Image(systemName: "pencil.circle.fill")
|
Image(systemName: "pencil.circle.fill")
|
||||||
.font(.title3)
|
.font(.title3)
|
||||||
@@ -216,11 +217,14 @@ struct UserTimerEditSheet: View {
|
|||||||
self.onSave = onSave
|
self.onSave = onSave
|
||||||
self.onCancel = onCancel
|
self.onCancel = onCancel
|
||||||
|
|
||||||
_title = State(initialValue: timer?.title ?? UserTimer.generateTitle(for: existingTimersCount))
|
_title = State(
|
||||||
|
initialValue: timer?.title ?? UserTimer.generateTitle(for: existingTimersCount))
|
||||||
_message = State(initialValue: timer?.message ?? "")
|
_message = State(initialValue: timer?.message ?? "")
|
||||||
_type = State(initialValue: timer?.type ?? .subtle)
|
_type = State(initialValue: timer?.type ?? .subtle)
|
||||||
_timeOnScreen = State(initialValue: timer?.timeOnScreenSeconds ?? 30)
|
_timeOnScreen = State(initialValue: timer?.timeOnScreenSeconds ?? 30)
|
||||||
_selectedColorHex = State(initialValue: timer?.colorHex ?? UserTimer.defaultColors[existingTimersCount % UserTimer.defaultColors.count])
|
_selectedColorHex = State(
|
||||||
|
initialValue: timer?.colorHex
|
||||||
|
?? UserTimer.defaultColors[existingTimersCount % UserTimer.defaultColors.count])
|
||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
@@ -239,12 +243,15 @@ struct UserTimerEditSheet: View {
|
|||||||
.font(.caption)
|
.font(.caption)
|
||||||
.foregroundColor(.secondary)
|
.foregroundColor(.secondary)
|
||||||
}
|
}
|
||||||
|
|
||||||
VStack(alignment: .leading, spacing: 8) {
|
VStack(alignment: .leading, spacing: 8) {
|
||||||
Text("Color")
|
Text("Color")
|
||||||
.font(.headline)
|
.font(.headline)
|
||||||
|
|
||||||
LazyVGrid(columns: Array(repeating: GridItem(.flexible(), spacing: 12), count: 8), spacing: 12) {
|
LazyVGrid(
|
||||||
|
columns: Array(repeating: GridItem(.flexible(), spacing: 12), count: 8),
|
||||||
|
spacing: 12
|
||||||
|
) {
|
||||||
ForEach(UserTimer.defaultColors, id: \.self) { colorHex in
|
ForEach(UserTimer.defaultColors, id: \.self) { colorHex in
|
||||||
Button(action: {
|
Button(action: {
|
||||||
selectedColorHex = colorHex
|
selectedColorHex = colorHex
|
||||||
@@ -254,9 +261,13 @@ struct UserTimerEditSheet: View {
|
|||||||
.frame(width: 32, height: 32)
|
.frame(width: 32, height: 32)
|
||||||
.overlay(
|
.overlay(
|
||||||
Circle()
|
Circle()
|
||||||
.strokeBorder(Color.white, lineWidth: selectedColorHex == colorHex ? 3 : 0)
|
.strokeBorder(
|
||||||
|
Color.white,
|
||||||
|
lineWidth: selectedColorHex == colorHex ? 3 : 0)
|
||||||
)
|
)
|
||||||
.shadow(color: selectedColorHex == colorHex ? .accentColor : .clear, radius: 4)
|
.shadow(
|
||||||
|
color: selectedColorHex == colorHex ? .accentColor : .clear,
|
||||||
|
radius: 4)
|
||||||
}
|
}
|
||||||
.buttonStyle(.plain)
|
.buttonStyle(.plain)
|
||||||
}
|
}
|
||||||
@@ -264,9 +275,6 @@ struct UserTimerEditSheet: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
VStack(alignment: .leading, spacing: 8) {
|
VStack(alignment: .leading, spacing: 8) {
|
||||||
Text("Display Type")
|
|
||||||
.font(.headline)
|
|
||||||
|
|
||||||
Picker("Display Type", selection: $type) {
|
Picker("Display Type", selection: $type) {
|
||||||
ForEach(UserTimerType.allCases) { timerType in
|
ForEach(UserTimerType.allCases) { timerType in
|
||||||
Text(timerType.displayName).tag(timerType)
|
Text(timerType.displayName).tag(timerType)
|
||||||
@@ -276,28 +284,30 @@ struct UserTimerEditSheet: View {
|
|||||||
|
|
||||||
Text(
|
Text(
|
||||||
type == .subtle
|
type == .subtle
|
||||||
? "Small reminder in corner of screen"
|
? "Small reminder at top of screen"
|
||||||
: "Full screen reminder with animation"
|
: "Full screen reminder with animation"
|
||||||
)
|
)
|
||||||
.font(.caption)
|
.font(.caption)
|
||||||
.foregroundColor(.secondary)
|
.foregroundColor(.secondary)
|
||||||
}
|
}
|
||||||
|
|
||||||
VStack(alignment: .leading, spacing: 8) {
|
if type == .overlay {
|
||||||
Text("Duration on Screen")
|
VStack(alignment: .leading, spacing: 8) {
|
||||||
.font(.headline)
|
Text("Duration on Screen")
|
||||||
HStack {
|
.font(.headline)
|
||||||
Slider(
|
HStack {
|
||||||
value: Binding(
|
Slider(
|
||||||
get: { Double(timeOnScreen) },
|
value: Binding(
|
||||||
set: { timeOnScreen = Int($0) }
|
get: { Double(timeOnScreen) },
|
||||||
),
|
set: { timeOnScreen = Int($0) }
|
||||||
in: 5...120,
|
),
|
||||||
step: 5
|
in: 5...30,
|
||||||
)
|
step: 1
|
||||||
Text("\(timeOnScreen)s")
|
)
|
||||||
.frame(width: 50, alignment: .trailing)
|
Text("\(timeOnScreen)s")
|
||||||
.monospacedDigit()
|
.frame(width: 50, alignment: .trailing)
|
||||||
|
.monospacedDigit()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,7 +357,8 @@ struct UserTimerEditSheet: View {
|
|||||||
UserTimersView(
|
UserTimersView(
|
||||||
userTimers: .constant([
|
userTimers: .constant([
|
||||||
UserTimer(
|
UserTimer(
|
||||||
id: "1", title: "User Reminder 1", type: .subtle, timeOnScreenSeconds: 30, message: "Take a break", colorHex: "9B59B6"),
|
id: "1", title: "User Reminder 1", type: .subtle, timeOnScreenSeconds: 30,
|
||||||
|
message: "Take a break", colorHex: "9B59B6"),
|
||||||
UserTimer(
|
UserTimer(
|
||||||
id: "2", title: "User Reminder 2", type: .overlay, timeOnScreenSeconds: 60,
|
id: "2", title: "User Reminder 2", type: .overlay, timeOnScreenSeconds: 60,
|
||||||
message: "Stretch your legs", colorHex: "3498DB"),
|
message: "Stretch your legs", colorHex: "3498DB"),
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ struct SettingsWindowView: View {
|
|||||||
}
|
}
|
||||||
.padding()
|
.padding()
|
||||||
}
|
}
|
||||||
.frame(minWidth: 700, minHeight: 750)
|
.frame(minWidth: 750, minHeight: 800)
|
||||||
.onReceive(
|
.onReceive(
|
||||||
NotificationCenter.default.publisher(for: Notification.Name("SwitchToSettingsTab"))
|
NotificationCenter.default.publisher(for: Notification.Name("SwitchToSettingsTab"))
|
||||||
) { notification in
|
) { notification in
|
||||||
|
|||||||
Reference in New Issue
Block a user