Skip to content
Merged

hope #13

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions dhavnii.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -267,11 +267,14 @@
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
CFBundleShortVersionString = 1.0;
CODE_SIGN_ENTITLEMENTS = dhavnii/dhavnii.entitlements;
CODE_SIGN_STYLE = Automatic;
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Manual;
CODE_SIGNING_ALLOWED = YES;
CODE_SIGNING_REQUIRED = YES;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1;
ENABLE_APP_SANDBOX = NO;
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_HARDENED_RUNTIME = NO;
ENABLE_PREVIEWS = YES;
ENABLE_USER_SELECTED_FILES = readonly;
GENERATE_INFOPLIST_FILE = NO;
Expand Down Expand Up @@ -301,11 +304,14 @@
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
CFBundleShortVersionString = 1.0;
CODE_SIGN_ENTITLEMENTS = dhavnii/dhavnii.entitlements;
CODE_SIGN_STYLE = Automatic;
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Manual;
CODE_SIGNING_ALLOWED = YES;
CODE_SIGNING_REQUIRED = YES;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1;
ENABLE_APP_SANDBOX = NO;
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_HARDENED_RUNTIME = NO;
ENABLE_PREVIEWS = YES;
ENABLE_USER_SELECTED_FILES = readonly;
GENERATE_INFOPLIST_FILE = NO;
Expand Down
25 changes: 23 additions & 2 deletions dhavnii/Core/Security/SecureStorage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,36 @@ internal enum SecureStorage {
guard let data = apiKey.data(using: .utf8) else {
throw KeychainError.conversionFailed
}


// Create an Access object with no trusted-application list.
//
// When a keychain item is stored WITHOUT an explicit SecAccess, macOS
// automatically creates an ACL tied to the storing app's code signature.
// For an unsigned (or ad-hoc-signed) app this means every new build gets
// a different signature, and macOS prompts the user for their system
// password on every launch because it sees a "different" app trying to
// read the item.
//
// Passing a SecAccess with an empty trusted-application array and the
// kSecACLAuthorizationAny flag tells the keychain to allow any
// application to read this item without prompting. This is the correct
// approach for unsigned, non-sandboxed apps that distribute outside the
// Mac App Store.
var access: SecAccess?
let accessStatus = SecAccessCreate("openwispher_api_keys" as CFString, [] as CFArray, &access)
guard accessStatus == errSecSuccess, let secAccess = access else {
throw KeychainError.invalidStatus(accessStatus)
}

let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: key,
kSecAttrService as String: "openwispher_api_keys",
kSecValueData as String: data,
// AfterFirstUnlock: accessible after the user logs in once per boot,
// without prompting for the system password on every app launch.
kSecAttrAccessible as String: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
kSecAttrAccessible as String: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly,
kSecAttrAccess as String: secAccess
]

let status = SecItemAdd(query as CFDictionary, nil)
Expand Down
8 changes: 5 additions & 3 deletions dhavnii/Core/UI/LiquidGlassHelpers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import AppKit
import SwiftUI

internal extension View {
extension View {
@ViewBuilder
func liquidGlassSurface(
cornerRadius: CGFloat,
Expand Down Expand Up @@ -82,8 +82,10 @@ internal extension View {
internal struct LiquidGlassBackground: View {
var body: some View {
Group {
VisualEffectBlur(material: .windowBackground, blendingMode: .withinWindow, state: .active)
.overlay(Color.black.opacity(0.3))
VisualEffectBlur(
material: .underWindowBackground, blendingMode: .behindWindow, state: .active
)
.overlay(Color.black.opacity(0.3))
}
.ignoresSafeArea()
}
Expand Down
21 changes: 12 additions & 9 deletions dhavnii/Features/Home/HomeView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ struct HomeView: View {
detailContent
}
.frame(minWidth: 700, minHeight: 500)
.background(WindowConfigurator())
.liquidGlassWindowBackground()
.seamlessToolbarWindowBackground()
.preferredColorScheme(.dark)
}

Expand Down Expand Up @@ -112,7 +115,7 @@ struct HomeView: View {
.padding(.vertical, 8)
.background(
RoundedRectangle(cornerRadius: 8, style: .continuous)
.fill(Color.primary.opacity(0.05))
.fill(.regularMaterial)
)
}
.buttonStyle(.plain)
Expand Down Expand Up @@ -224,7 +227,7 @@ struct HomeContentView: View {
HStack {
Text("Transcriptions")
.font(.system(size: 13, weight: .medium))
.foregroundStyle(.secondary)
.foregroundStyle(.clear)

Spacer()

Expand Down Expand Up @@ -393,16 +396,16 @@ private struct TranscriptionRow: View {

Spacer()
}
.opacity(isHovered ? 1 : 0.6)
// .opacity(isHovered ? 1 : 0.6)
}
.padding(.horizontal, 24)
.padding(.vertical, 16)
.background(
RoundedRectangle(cornerRadius: 8, style: .continuous)
.fill(Color.primary.opacity(isHovered ? 0.05 : 0))
)
.animation(.easeInOut(duration: 0.15), value: isHovered)
.contentShape(Rectangle())
// .background(
// RoundedRectangle(cornerRadius: 8, style: .continuous)
// .fill(Color.primary.opacity(isHovered ? 0.05 : 0))
// )
// .animation(.easeInOut(duration: 0.15), value: isHovered)
// .contentShape(Rectangle())
}
}

Expand Down
36 changes: 15 additions & 21 deletions dhavnii/Features/Onboarding/OnboardingView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,16 @@ struct OnboardingView: View {

var body: some View {
ZStack {

stepContent
.padding(.horizontal, 32)
.transition(.opacity.combined(with: .scale(scale: 0.98)))
}
.frame(
width: UIConstants.Window.onboardingWidth, height: UIConstants.Window.onboardingHeight
)
.background(WindowConfigurator())
.seamlessToolbarWindowBackground()
.preferredColorScheme(.dark)

.task {
// Initial check
Expand Down Expand Up @@ -110,21 +112,6 @@ struct OnboardingView: View {
.animation(.easeInOut(duration: 0.3), value: currentStep)
}

// MARK: - Background

private var onboardingBackground: some View {
RadialGradient(
colors: [
Color(red: 0.18, green: 0.18, blue: 0.19),
Color(red: 0.12, green: 0.12, blue: 0.13),
],
center: .center,
startRadius: 0,
endRadius: 520
)
.ignoresSafeArea()
}

// MARK: - Step Content

@ViewBuilder
Expand Down Expand Up @@ -518,10 +505,13 @@ private struct PermissionsCard<Content: View>: View {
var body: some View {
content
.frame(maxWidth: .infinity)
.background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: 22))
.background(
RoundedRectangle(cornerRadius: 22, style: .continuous)
.fill(Color.white.opacity(0.08))
)
.overlay(
RoundedRectangle(cornerRadius: 22)
.stroke(.primary.opacity(0.08), lineWidth: 0.5)
.stroke(Color.white.opacity(0.12), lineWidth: 0.5)
)
}
}
Expand All @@ -536,10 +526,13 @@ private struct OnboardingPanel<Content: View>: View {
var body: some View {
content
.frame(maxWidth: .infinity)
.background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: 22))
.background(
RoundedRectangle(cornerRadius: 22, style: .continuous)
.fill(Color.white.opacity(0.08))
)
.overlay(
RoundedRectangle(cornerRadius: 22)
.stroke(.primary.opacity(0.08), lineWidth: 0.5)
.stroke(Color.white.opacity(0.12), lineWidth: 0.5)
)
}
}
Expand Down Expand Up @@ -691,7 +684,8 @@ private final class HotkeyRecorderNSView: NSView {
}

let modifierFlags = event.modifierFlags
let hasModifiers = modifierFlags.contains(.command)
let hasModifiers =
modifierFlags.contains(.command)
|| modifierFlags.contains(.option)
|| modifierFlags.contains(.control)
|| modifierFlags.contains(.shift)
Expand Down
55 changes: 15 additions & 40 deletions dhavnii/Features/Settings/SettingsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,34 +40,8 @@ internal struct SettingsView: View {
}
}

var iconGradient: [Color] {
switch self {
case .permissions:
return [
Color(red: 0.20, green: 0.78, blue: 0.55),
Color(red: 0.08, green: 0.55, blue: 0.45),
]
case .providers:
return [
Color(red: 0.25, green: 0.62, blue: 0.98),
Color(red: 0.10, green: 0.42, blue: 0.90),
]
case .general:
return [
Color(red: 0.98, green: 0.63, blue: 0.24),
Color(red: 0.92, green: 0.42, blue: 0.20),
]
case .history:
return [
Color(red: 0.56, green: 0.45, blue: 0.98),
Color(red: 0.35, green: 0.30, blue: 0.88),
]
case .about:
return [
Color(red: 0.94, green: 0.38, blue: 0.58),
Color(red: 0.84, green: 0.22, blue: 0.44),
]
}
var iconColor: Color {
Color.white.opacity(0.15)
}
}

Expand All @@ -80,6 +54,7 @@ internal struct SettingsView: View {
}
.frame(minWidth: 750, minHeight: 550)
.background(WindowConfigurator())
.liquidGlassWindowBackground()
.seamlessToolbarWindowBackground()
.preferredColorScheme(.dark)
}
Expand Down Expand Up @@ -138,7 +113,7 @@ internal struct SettingsView: View {

private func settingsSidebarItem(for section: SettingsSection) -> some View {
HStack(spacing: 10) {
SidebarIconTile(systemName: section.icon, colors: section.iconGradient)
SidebarIconTile(systemName: section.icon, color: section.iconColor)

Text(section.rawValue)
.font(.system(size: 13, weight: .medium))
Expand Down Expand Up @@ -260,7 +235,7 @@ private struct SettingsRow<Content: View>: View {
.padding(.horizontal, 16)
.background(
RoundedRectangle(cornerRadius: 10, style: .continuous)
.fill(Color.primary.opacity(0.03))
.fill(Color.primary.opacity(0.04))
)
}
}
Expand Down Expand Up @@ -291,11 +266,11 @@ private struct SettingsGroup<Content: View>: View {
}
.background(
RoundedRectangle(cornerRadius: 12, style: .continuous)
.fill(Color.primary.opacity(0.02))
.fill(Color.white.opacity(0.08))
)
.overlay(
RoundedRectangle(cornerRadius: 12, style: .continuous)
.stroke(Color.primary.opacity(0.06), lineWidth: 0.5)
.stroke(Color.white.opacity(0.12), lineWidth: 0.5)
)
}
}
Expand Down Expand Up @@ -465,11 +440,11 @@ private struct PermissionRow: View {
}
.background(
RoundedRectangle(cornerRadius: 12, style: .continuous)
.fill(Color.primary.opacity(0.02))
.fill(.regularMaterial)
)
.overlay(
RoundedRectangle(cornerRadius: 12, style: .continuous)
.stroke(Color.primary.opacity(0.06), lineWidth: 0.5)
.stroke(Color.primary.opacity(0.10), lineWidth: 0.5)
)
}
}
Expand Down Expand Up @@ -861,11 +836,11 @@ private struct ProviderCard: View {
}
.background(
RoundedRectangle(cornerRadius: 12, style: .continuous)
.fill(Color.primary.opacity(0.02))
.fill(.regularMaterial)
)
.overlay(
RoundedRectangle(cornerRadius: 12, style: .continuous)
.stroke(Color.primary.opacity(0.06), lineWidth: 0.5)
.stroke(Color.primary.opacity(0.10), lineWidth: 0.5)
)
.onAppear { checkKey() }
.onAppear {
Expand Down Expand Up @@ -1177,11 +1152,11 @@ private struct FallbackSettingsCard: View {
}
.background(
RoundedRectangle(cornerRadius: 12, style: .continuous)
.fill(Color.primary.opacity(0.02))
.fill(.regularMaterial)
)
.overlay(
RoundedRectangle(cornerRadius: 12, style: .continuous)
.stroke(Color.primary.opacity(0.06), lineWidth: 0.5)
.stroke(Color.primary.opacity(0.10), lineWidth: 0.5)
)
.onAppear {
checkFallbackKey()
Expand Down Expand Up @@ -1620,11 +1595,11 @@ private struct AboutSettingsView: View {
.padding(16)
.background(
RoundedRectangle(cornerRadius: 12, style: .continuous)
.fill(Color.primary.opacity(0.02))
.fill(Color.white.opacity(0.08))
)
.overlay(
RoundedRectangle(cornerRadius: 12, style: .continuous)
.stroke(Color.primary.opacity(0.06), lineWidth: 0.5)
.stroke(Color.white.opacity(0.12), lineWidth: 0.5)
)
.padding(.horizontal, 60)
Spacer()
Expand Down
Loading