New version v2.3.6
This commit is contained in:
@@ -142,7 +142,7 @@ It's better to admit "I need more information" or "I cannot do that" than to fak
|
||||
tabButton(7, icon: "brain", label: "Skills")
|
||||
tabButton(4, icon: "arrow.triangle.2.circlepath", label: "Sync")
|
||||
tabButton(5, icon: "envelope", label: "Email")
|
||||
tabButton(8, icon: "doc.text", label: "Paperless")
|
||||
tabButton(8, icon: "doc.text", label: "Paperless", beta: true)
|
||||
tabButton(9, icon: "icloud.and.arrow.up", label: "Backup")
|
||||
}
|
||||
.padding(.horizontal, 16)
|
||||
@@ -283,10 +283,42 @@ It's better to admit "I need more information" or "I cannot do that" than to fak
|
||||
.toggleStyle(.switch)
|
||||
}
|
||||
rowDivider()
|
||||
row("MCP (File Access)") {
|
||||
Toggle("", isOn: $settingsService.mcpEnabled)
|
||||
row("Reasoning (Thinking)") {
|
||||
Toggle("", isOn: $settingsService.reasoningEnabled)
|
||||
.toggleStyle(.switch)
|
||||
}
|
||||
if settingsService.reasoningEnabled {
|
||||
rowDivider()
|
||||
row("Reasoning Effort") {
|
||||
Picker("", selection: $settingsService.reasoningEffort) {
|
||||
Text("High (~80%)").tag("high")
|
||||
Text("Medium (~50%)").tag("medium")
|
||||
Text("Low (~20%)").tag("low")
|
||||
Text("Minimal (~10%)").tag("minimal")
|
||||
}
|
||||
.labelsHidden()
|
||||
.fixedSize()
|
||||
}
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
Text(reasoningEffortDescription)
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
.padding(.horizontal, 12)
|
||||
.padding(.bottom, 4)
|
||||
rowDivider()
|
||||
row("Hide Reasoning in Response") {
|
||||
Toggle("", isOn: $settingsService.reasoningExclude)
|
||||
.toggleStyle(.switch)
|
||||
}
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
Text("Model thinks internally but reasoning is not shown in chat")
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
.padding(.horizontal, 12)
|
||||
.padding(.bottom, 4)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2050,13 +2082,25 @@ It's better to admit "I need more information" or "I cannot do that" than to fak
|
||||
|
||||
// MARK: - Tab Navigation
|
||||
|
||||
private func tabButton(_ tag: Int, icon: String, label: String) -> some View {
|
||||
private func tabButton(_ tag: Int, icon: String, label: LocalizedStringKey, beta: Bool = false) -> some View {
|
||||
Button(action: { selectedTab = tag }) {
|
||||
VStack(spacing: 3) {
|
||||
Image(systemName: icon)
|
||||
.font(.system(size: 22))
|
||||
.frame(height: 28)
|
||||
.foregroundStyle(selectedTab == tag ? .blue : .secondary)
|
||||
ZStack(alignment: .topTrailing) {
|
||||
Image(systemName: icon)
|
||||
.font(.system(size: 22))
|
||||
.frame(height: 28)
|
||||
.foregroundStyle(selectedTab == tag ? .blue : .secondary)
|
||||
if beta {
|
||||
Text("β")
|
||||
.font(.system(size: 8, weight: .bold))
|
||||
.foregroundStyle(.white)
|
||||
.padding(.horizontal, 3)
|
||||
.padding(.vertical, 1)
|
||||
.background(Color.orange)
|
||||
.clipShape(Capsule())
|
||||
.offset(x: 6, y: -2)
|
||||
}
|
||||
}
|
||||
Text(label)
|
||||
.font(.system(size: 11))
|
||||
.foregroundStyle(selectedTab == tag ? .blue : .secondary)
|
||||
@@ -2070,7 +2114,7 @@ It's better to admit "I need more information" or "I cannot do that" than to fak
|
||||
.buttonStyle(.plain)
|
||||
}
|
||||
|
||||
private func tabTitle(_ tag: Int) -> String {
|
||||
private func tabTitle(_ tag: Int) -> LocalizedStringKey {
|
||||
switch tag {
|
||||
case 0: return "General"
|
||||
case 1: return "MCP"
|
||||
@@ -2086,13 +2130,23 @@ It's better to admit "I need more information" or "I cannot do that" than to fak
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Reasoning Helpers
|
||||
|
||||
private var reasoningEffortDescription: LocalizedStringKey {
|
||||
switch settingsService.reasoningEffort {
|
||||
case "high": return "Uses ~80% of max tokens for reasoning — best for hard problems"
|
||||
case "medium": return "Uses ~50% of max tokens for reasoning — balanced default"
|
||||
case "low": return "Uses ~20% of max tokens for reasoning — faster, cheaper"
|
||||
case "minimal": return "Uses ~10% of max tokens for reasoning — lightest thinking"
|
||||
default: return "Uses ~50% of max tokens for reasoning — balanced default"
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Layout Helpers
|
||||
|
||||
private func row<Content: View>(_ label: String, @ViewBuilder content: () -> Content) -> some View {
|
||||
private func row<Content: View>(_ label: LocalizedStringKey, @ViewBuilder content: () -> Content) -> some View {
|
||||
HStack(alignment: .center, spacing: 12) {
|
||||
if !label.isEmpty {
|
||||
Text(label).font(.system(size: 14))
|
||||
}
|
||||
Text(label).font(.system(size: 14))
|
||||
Spacer()
|
||||
content()
|
||||
}
|
||||
@@ -2100,7 +2154,7 @@ It's better to admit "I need more information" or "I cannot do that" than to fak
|
||||
.padding(.vertical, 10)
|
||||
}
|
||||
|
||||
private func sectionHeader(_ title: String) -> some View {
|
||||
private func sectionHeader(_ title: LocalizedStringKey) -> some View {
|
||||
Text(title)
|
||||
.font(.system(size: 12, weight: .semibold))
|
||||
.foregroundStyle(.secondary)
|
||||
@@ -2205,7 +2259,7 @@ It's better to admit "I need more information" or "I cannot do that" than to fak
|
||||
return .green
|
||||
}
|
||||
|
||||
private var syncStatusText: String {
|
||||
private var syncStatusText: LocalizedStringKey {
|
||||
guard settingsService.syncEnabled else { return "Disabled" }
|
||||
guard settingsService.syncConfigured else { return "Not configured" }
|
||||
guard gitSync.syncStatus.isCloned else { return "Not cloned" }
|
||||
@@ -2318,19 +2372,9 @@ It's better to admit "I need more information" or "I cannot do that" than to fak
|
||||
}
|
||||
|
||||
private func timeAgo(_ date: Date) -> String {
|
||||
let seconds = Int(Date().timeIntervalSince(date))
|
||||
if seconds < 60 {
|
||||
return "just now"
|
||||
} else if seconds < 3600 {
|
||||
let minutes = seconds / 60
|
||||
return "\(minutes) minute\(minutes == 1 ? "" : "s") ago"
|
||||
} else if seconds < 86400 {
|
||||
let hours = seconds / 3600
|
||||
return "\(hours) hour\(hours == 1 ? "" : "s") ago"
|
||||
} else {
|
||||
let days = seconds / 86400
|
||||
return "\(days) day\(days == 1 ? "" : "s") ago"
|
||||
}
|
||||
let formatter = RelativeDateTimeFormatter()
|
||||
formatter.unitsStyle = .full
|
||||
return formatter.localizedString(for: date, relativeTo: .now)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user