diff --git a/.githooks/pre-commit b/.githooks/pre-commit index 58c7131..4578b26 100755 --- a/.githooks/pre-commit +++ b/.githooks/pre-commit @@ -24,7 +24,7 @@ echo "🔍 Running SwiftLint on staged files…" # Lint only the staged files (faster than full project) echo "$staged_swift_files" | while read -r file; do if [[ -f "$file" ]]; then - swiftlint lint --quiet --strict --use-script-input-files <<< "$file" || { + swiftlint lint --quiet --strict "$file" || { echo "" echo "❌ SwiftLint failed. Fix the issues above, then re-stage and commit." echo " To bypass (NOT recommended), use: git commit --no-verify" diff --git a/.swiftlint.yml b/.swiftlint.yml index 77cea0e..7aba661 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -90,7 +90,7 @@ force_cast: force_try: severity: error # error: same force_unwrapping: - severity: warning # warning today → bump to error after cleanup PR + severity: error # Custom project rules custom_rules: diff --git a/Savely/Managers/CameraManager.swift b/Savely/Managers/CameraManager.swift index 671d5ec..152d012 100755 --- a/Savely/Managers/CameraManager.swift +++ b/Savely/Managers/CameraManager.swift @@ -87,10 +87,11 @@ class CameraManager: NSObject, ObservableObject { } func setPreviewLayer(to view: UIView) { - previewLayer = AVCaptureVideoPreviewLayer(session: session) - previewLayer?.videoGravity = .resizeAspectFill - previewLayer?.frame = view.bounds - view.layer.insertSublayer(previewLayer!, at: 0) + let layer = AVCaptureVideoPreviewLayer(session: session) + layer.videoGravity = .resizeAspectFill + layer.frame = view.bounds + previewLayer = layer + view.layer.insertSublayer(layer, at: 0) } func capturePhoto() { diff --git a/Savely/Models/ExpenseModel.swift b/Savely/Models/ExpenseModel.swift index 9d9cbf0..9a4dcd0 100755 --- a/Savely/Models/ExpenseModel.swift +++ b/Savely/Models/ExpenseModel.swift @@ -29,7 +29,11 @@ extension ExpenseModel { print("Fetching expenses from \(startDate) to \(endDate)") // Precompute adjusted end date - let adjustedEndDate = Calendar.current.startOfDay(for: Calendar.current.date(byAdding: .day, value: 1, to: endDate)!) + guard let nextDay = Calendar.current.date(byAdding: .day, value: 1, to: endDate) else { + print("Error computing adjusted end date for expense fetch") + return [] + } + let adjustedEndDate = Calendar.current.startOfDay(for: nextDay) let fetchDescriptor = FetchDescriptor( predicate: #Predicate { diff --git a/Savely/Models/IncomeModel.swift b/Savely/Models/IncomeModel.swift index 35c12bf..4558762 100644 --- a/Savely/Models/IncomeModel.swift +++ b/Savely/Models/IncomeModel.swift @@ -29,7 +29,11 @@ extension IncomeModel { print("Fetching incomes from \(startDate) to \(endDate)") // Precompute adjusted end date - let adjustedEndDate = Calendar.current.startOfDay(for: Calendar.current.date(byAdding: .day, value: 1, to: endDate)!) + guard let nextDay = Calendar.current.date(byAdding: .day, value: 1, to: endDate) else { + print("Error computing adjusted end date for income fetch") + return [] + } + let adjustedEndDate = Calendar.current.startOfDay(for: nextDay) let fetchDescriptor = FetchDescriptor( predicate: #Predicate { diff --git a/Savely/Utilities/OpenAIClient.swift b/Savely/Utilities/OpenAIClient.swift index e20a7e5..4e2ef3e 100644 --- a/Savely/Utilities/OpenAIClient.swift +++ b/Savely/Utilities/OpenAIClient.swift @@ -23,8 +23,11 @@ class OpenAIClient { } func fetchTip(prompt: String) async -> String? { - let url = URL(string: "https://api.openai.com/v1/chat/completions")! - + guard let url = URL(string: "https://api.openai.com/v1/chat/completions") else { + return nil + } + + // Construir el mensaje para el modelo let messages = [ OpenAIChatMessage(role: "system", content: "Eres un asistente financiero."), diff --git a/Savely/Utilities/SignInWithAppleHelper.swift b/Savely/Utilities/SignInWithAppleHelper.swift index 67c332c..a5e7530 100644 --- a/Savely/Utilities/SignInWithAppleHelper.swift +++ b/Savely/Utilities/SignInWithAppleHelper.swift @@ -233,6 +233,6 @@ extension SignInWithAppleHelper: ASAuthorizationControllerDelegate { extension UIViewController: ASAuthorizationControllerPresentationContextProviding { public func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor { - return self.view.window! + return self.view.window ?? ASPresentationAnchor() } } diff --git a/Savely/ViewModels/Dashboard/ReportsViewModel.swift b/Savely/ViewModels/Dashboard/ReportsViewModel.swift index d4fb318..722b57c 100644 --- a/Savely/ViewModels/Dashboard/ReportsViewModel.swift +++ b/Savely/ViewModels/Dashboard/ReportsViewModel.swift @@ -74,7 +74,8 @@ class ReportsViewModel: ObservableObject { print("Fetching weekly incomes...") let adjustedStartDate = Calendar.current.startOfDay(for: startDate) - let adjustedEndDate = Calendar.current.startOfDay(for: Calendar.current.date(byAdding: .day, value: 1, to: endDate)!) + guard let nextDay = Calendar.current.date(byAdding: .day, value: 1, to: endDate) else { return [] } + let adjustedEndDate = Calendar.current.startOfDay(for: nextDay) let fetchDescriptor = FetchDescriptor( predicate: #Predicate { @@ -89,7 +90,8 @@ class ReportsViewModel: ObservableObject { print("Fetching weekly expenses...") let adjustedStartDate = Calendar.current.startOfDay(for: startDate) - let adjustedEndDate = Calendar.current.startOfDay(for: Calendar.current.date(byAdding: .day, value: 1, to: endDate)!) + guard let nextDay = Calendar.current.date(byAdding: .day, value: 1, to: endDate) else { return [] } + let adjustedEndDate = Calendar.current.startOfDay(for: nextDay) let fetchDescriptor = FetchDescriptor( predicate: #Predicate { diff --git a/Savely/ViewModels/ProfileTab/ProfileViewModel.swift b/Savely/ViewModels/ProfileTab/ProfileViewModel.swift index 1bfd847..1dfe2e8 100644 --- a/Savely/ViewModels/ProfileTab/ProfileViewModel.swift +++ b/Savely/ViewModels/ProfileTab/ProfileViewModel.swift @@ -122,7 +122,8 @@ class ProfileViewModel: ObservableObject { private func fetchWeeklyIncome(from startDate: Date, to endDate: Date, in context: ModelContext) async throws -> [IncomeModel] { print("fetchWeeklyIncome: Fetching incomes...") let adjustedStartDate = Calendar.current.startOfDay(for: startDate) - let adjustedEndDate = Calendar.current.startOfDay(for: Calendar.current.date(byAdding: .day, value: 1, to: endDate)!) + guard let nextDay = Calendar.current.date(byAdding: .day, value: 1, to: endDate) else { return [] } + let adjustedEndDate = Calendar.current.startOfDay(for: nextDay) let fetchDescriptor = FetchDescriptor( predicate: #Predicate { @@ -139,7 +140,8 @@ class ProfileViewModel: ObservableObject { private func fetchWeeklyExpenses(from startDate: Date, to endDate: Date, in context: ModelContext) async throws -> [ExpenseModel] { print("fetchWeeklyExpenses: Fetching expenses...") let adjustedStartDate = Calendar.current.startOfDay(for: startDate) - let adjustedEndDate = Calendar.current.startOfDay(for: Calendar.current.date(byAdding: .day, value: 1, to: endDate)!) + guard let nextDay = Calendar.current.date(byAdding: .day, value: 1, to: endDate) else { return [] } + let adjustedEndDate = Calendar.current.startOfDay(for: nextDay) let fetchDescriptor = FetchDescriptor( predicate: #Predicate { diff --git a/Savely/Views/MainNavigationView.swift b/Savely/Views/MainNavigationView.swift index 3398e98..d9d62a8 100755 --- a/Savely/Views/MainNavigationView.swift +++ b/Savely/Views/MainNavigationView.swift @@ -656,7 +656,7 @@ struct WarmQuickDepositView: View { Button(action: saveDeposit) { let goalName = selectedGoal.map { $0.name.components(separatedBy: ",").first ?? $0.name } - Text(goalName != nil ? "Add $\(Int(selectedPreset)) to \(goalName!)" : "Select a goal") + Text(goalName.map { "Add $\(Int(selectedPreset)) to \($0)" } ?? "Select a goal") .font(.system(size: 15, weight: .semibold)).foregroundStyle(.white) .frame(maxWidth: .infinity).frame(height: 50) .background(selectedGoal != nil ? Color.warmGreen : Color.warmInkMuted)