Skip to content

Fix reported bugs#321

Merged
pantelisss merged 8 commits intomainfrom
feature/fe-2037-investigate-reported-bugs
Nov 3, 2025
Merged

Fix reported bugs#321
pantelisss merged 8 commits intomainfrom
feature/fe-2037-investigate-reported-bugs

Conversation

@pantelisss
Copy link
Collaborator

@pantelisss pantelisss commented Oct 31, 2025

Why?

Two issues are described in the task

How?

  • About the first one (saved locations disappeared). It has to do with the caching logic. There are cases when the cache is not invalidated and the first cached forecast is the previous day's one. To resolve it, the use case now returns only today's and later forecasts.
  • About the second (infinite loading in stations and profile tab). For some reason, the saved user credentials in the keychain were missing. Once the refresh token had expired and there was no way to log in the user silently, this case was not handled properly. Now we handle this case

Testing

Not so easy. Let's check it codewise and have a discussion about it

Additional context

fixes fe-2037

Summary by CodeRabbit

  • New Features

    • Forecasts now show only current and future dates (outdated entries filtered).
  • Bug Fixes

    • Improved error handling when retrieving location state with a safe fallback.
    • Reset of authentication-failure state when login status changes to avoid stale errors.
  • Improvements

    • iPad layout constraints improved for weather stations screen.
    • Caching behavior updated for more frequent refreshes.
    • Updated underlying dependency for stability.

@pantelisss pantelisss requested a review from PavlosTze October 31, 2025 14:55
@coderabbitai
Copy link

coderabbitai bot commented Oct 31, 2025

Walkthrough

Refactored HomeViewModel to fetch current location state in a separate do-catch after fetching forecasts; added iPad width constraints in MyStationsView; reset auth-failure state on login changes in MyStationsViewModel; explicit nil completion in AuthInterceptor.retryLogin; filter cached forecasts to exclude past dates; updated swift-protobuf to 1.33.1 and adjusted a test date value.

Changes

Cohort / File(s) Summary
Location State Fetching Refactor
PresentationLayer/UIComponents/Screens/Home/HomeViewModel.swift
Moved getCurrentLocationState() into a separate do-catch executed after fetchForecasts(); added generic catch for forecast fetch and fallback to .empty when location fetch fails.
iPad Layout Constraints
PresentationLayer/UIComponents/Screens/WeatherStations/MyStations/MyStationsView.swift
Added iPadMaxWidth() modifiers to two layout branches (failure branch and empty/not-logged-in overlay) to constrain iPad width.
Authentication State & Interceptor
PresentationLayer/UIComponents/Screens/WeatherStations/MyStations/MyStationsViewModel.swift,
wxm-ios/DataLayer/DataLayer/Networking/Interceptors/AuthInterceptor.swift
MyStationsViewModel now resets isFailed and failObj when isUserLoggedIn changes; AuthInterceptor's retryLogin now calls completion(nil) when accountInfo is absent.
Forecast Filtering & Tests
wxm-ios/DomainLayer/DomainLayer/UseCases/LocationForecastsUseCase.swift,
WeatherXMTests/DomainLayer/UseCases/LocationForecastsUseCaseTests.swift
When cached forecasts exist, filter to only forecasts with date >= today (exclude past dates); test fixture updated to set cached forecast date to today's formatted date.
Dependency Update
wxm-ios.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
Bumped swift-protobuf from 1.31.1 (rev 2547...) to 1.33.1 (rev 97bb...).

Sequence Diagram(s)

sequenceDiagram
    participant View as Home View
    participant VM as HomeViewModel
    participant FC as Forecast Service
    participant LS as Location Service

    View->>VM: refresh()
    rect rgb(240,248,255)
        Note over VM,FC: Step 1 — Fetch forecasts (do-catch)
        VM->>FC: fetchForecasts()
        alt forecasts success
            FC-->>VM: forecasts
        else forecasts error
            FC-->>VM: error
            VM->>VM: log error
        end
    end
    rect rgb(245,255,240)
        Note over VM,LS: Step 2 — Get current location (separate do-catch)
        VM->>LS: getCurrentLocationState()
        alt location success
            LS-->>VM: locationState
            VM->>VM: currentLocationState = locationState
        else location error
            LS-->>VM: error
            VM->>VM: log error
            VM->>VM: currentLocationState = .empty
        end
    end
    VM-->>View: updated state
Loading
sequenceDiagram
    participant UC as LocationForecastsUseCase
    participant Cache as Forecast Cache
    participant Parser as Date Parser

    UC->>Cache: load cachedForecasts
    alt cachedForecasts present
        Cache-->>UC: cachedForecasts
        rect rgb(255,240,245)
            Note over UC,Parser: Filter out past dates
            UC->>Parser: parse forecast.date -> Date
            UC->>UC: retain date >= today
        end
        UC-->>Caller: return filteredForecasts
    else no cache
        UC->>UC: fetch from network
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Verify date parsing and timezone handling in LocationForecastsUseCase filtering.
  • Confirm HomeViewModel sequential error handling doesn't mask forecast errors and that state updates occur as intended.
  • Check MyStationsViewModel auth-state reset timing for unintended side effects.
  • Ensure AuthInterceptor's completion(nil) path is appropriate for retry semantics.

Suggested reviewers

  • PavlosTze

Poem

🐰
I hopped through code with nimble feet,
Moved location checks to keep flow neat,
Filtered forecasts to skip old days,
iPads fit snug in clever ways—
A little tweak, and sunshine stays!

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title check ❓ Inconclusive The pull request title 'Fix reported bugs' is vague and generic. While it is technically related to the changeset, it does not convey meaningful information about what specific bugs are being fixed or which changes are most important. A developer scanning the history would not understand the primary changes without reading the full description. Consider using a more descriptive title that specifies the bugs being fixed, such as 'Fix cache invalidation for saved locations and silent login handling' or similar. This would make the change history more informative and easier to scan.
✅ Passed checks (1 passed)
Check name Status Explanation
Description check ✅ Passed The pull request description addresses most required sections from the template. It includes Why (two issues described), How (explanations of caching logic fix and credential handling), Testing (acknowledges difficulty and suggests code review), and Additional context (references fe-2037). However, the Testing section is quite minimal and could be more detailed. The Screenshots section is appropriately omitted as not applicable.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/fe-2037-investigate-reported-bugs

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 891f584 and c0323a0.

📒 Files selected for processing (1)
  • wxm-ios/DomainLayer/DomainLayer/UseCases/LocationForecastsUseCase.swift (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • wxm-ios/DomainLayer/DomainLayer/UseCases/LocationForecastsUseCase.swift
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: WeatherXM | Unit tests | wxm-ios - iOS

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (4)
wxm-ios/DomainLayer/DomainLayer/UseCases/LocationForecastsUseCase.swift (1)

52-64: Consider adding logging for date parsing failures.

The filtering logic correctly addresses the caching issue by excluding past forecasts. However, when onlyDateStringToDate() returns nil (line 53), the forecast is silently dropped. Consider adding debug logging to track when date parsing fails, which could help diagnose future data issues.

Apply this diff to add logging:

 let forecasts = cachedForecasts.filter { forecast in
     guard let date = forecast.date.onlyDateStringToDate() else {
+        print("⚠️ Failed to parse forecast date: \(forecast.date)")
         return false
     }
     // Ensure that we return only forecasts later than today
     return date.days(from: Date.now) >= 0
 }
WeatherXMTests/DomainLayer/UseCases/LocationForecastsUseCaseTests.swift (1)

45-45: LGTM! Test data aligned with new filtering logic.

The test data now uses the current date, ensuring the cached forecast passes the new date filter. This correctly validates the happy path.

Consider adding a test case for past-dated forecasts to verify they're correctly filtered out:

@Test
func getCachedForecast_FiltersOutPastDates() async throws {
    let pastForecast = NetworkDeviceForecastResponse(
        tz: "123",
        date: Date.now.addingTimeInterval(-86400).getFormattedDate(format: .onlyDate), // Yesterday
        hourly: [],
        address: "Address"
    )
    let location = CLLocationCoordinate2D()
    useCase.cache.insertValue([pastForecast], expire: 60, for: location.cacheKey)
    
    let forecast = try await useCase.getForecast(for: .init()).toAsync().result.get()
    #expect(forecast.isEmpty)
}

Would you like me to open an issue to track adding this test case?

wxm-ios/DataLayer/DataLayer/Networking/Interceptors/AuthInterceptor.swift (1)

89-89: Empty catch blocks silently swallow errors.

The empty catch block at line 89 (and also at line 75) silently ignores exceptions, making debugging difficult. Consider logging these errors to help diagnose authentication issues.

Apply this diff to add error logging:

             try AuthRepositoryImpl().login(username: accountInfo.email, password: accountInfo.password)
                 .sink { response in
                     if response.error != nil {
                         completion(nil)
                     } else {
                         completion(response.value!)
                     }
                 }.store(in: &cancellableSet)
-        } catch {}
+        } catch {
+            print("⚠️ AuthInterceptor retryLogin failed: \(error)")
+            completion(nil)
+        }
PresentationLayer/UIComponents/Screens/Home/HomeViewModel.swift (1)

128-137: Sequential error handling improves resilience.

Separating the currentLocationState retrieval into its own error-handling block improves the robustness of the refresh flow. The fallback to .empty ensures the UI doesn't get stuck in a loading state when location fetch fails.

Consider using structured logging instead of print() for production diagnostics. If available in your codebase, use a logging framework:

} catch {
    Logger.shared.error("Failed to fetch forecasts: \(error)")
}

do {
    self.currentLocationState = try await getCurrentLocationState()
} catch {
    Logger.shared.error("Failed to get current location state: \(error)")
    self.currentLocationState = .empty
}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f28bc66 and 891f584.

📒 Files selected for processing (7)
  • PresentationLayer/UIComponents/Screens/Home/HomeViewModel.swift (1 hunks)
  • PresentationLayer/UIComponents/Screens/WeatherStations/MyStations/MyStationsView.swift (2 hunks)
  • PresentationLayer/UIComponents/Screens/WeatherStations/MyStations/MyStationsViewModel.swift (1 hunks)
  • WeatherXMTests/DomainLayer/UseCases/LocationForecastsUseCaseTests.swift (1 hunks)
  • wxm-ios.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved (1 hunks)
  • wxm-ios/DataLayer/DataLayer/Networking/Interceptors/AuthInterceptor.swift (1 hunks)
  • wxm-ios/DomainLayer/DomainLayer/UseCases/LocationForecastsUseCase.swift (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
WeatherXMTests/DomainLayer/UseCases/LocationForecastsUseCaseTests.swift (1)
wxm-ios/Toolkit/Toolkit/Utils/DateExtension.swift (1)
  • getFormattedDate (205-232)
wxm-ios/DomainLayer/DomainLayer/UseCases/LocationForecastsUseCase.swift (1)
wxm-ios/Toolkit/Toolkit/Utils/DateExtension.swift (2)
  • onlyDateStringToDate (307-311)
  • days (180-182)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: WeatherXM | Unit tests | wxm-ios - iOS
🔇 Additional comments (3)
PresentationLayer/UIComponents/Screens/WeatherStations/MyStations/MyStationsViewModel.swift (1)

83-84: LGTM! Proper auth failure state cleanup on login changes.

Resetting the authentication failure state when login status changes correctly addresses the infinite loading issue described in the PR. This ensures stale error states don't persist across login sessions.

PresentationLayer/UIComponents/Screens/WeatherStations/MyStations/MyStationsView.swift (1)

101-101: LGTM! iPad layout improvements applied consistently.

The iPad width constraints improve the layout on larger screens and are consistently applied to both the failure and empty state views.

wxm-ios/DataLayer/DataLayer/Networking/Interceptors/AuthInterceptor.swift (1)

90-92: LGTM! Handles missing account credentials properly.

The explicit nil completion when accountInfo is missing correctly addresses the infinite loading issue described in the PR. This ensures the retry logic doesn't hang when silent login is impossible.

Comment on lines +315 to +316
"revision" : "97bb244f7a575a419ebc8f3c2d33f2feb9c8f7f2",
"version" : "1.33.1"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify the swift-protobuf update for breaking changes or security fixes.

The swift-protobuf dependency has been updated from version 1.31.1 to 1.33.1. Please verify that there are no breaking changes or important security fixes in this update.


🌐 Web query:

swift-protobuf 1.33.1 release notes breaking changes

💡 Result:

No — swift-protobuf 1.33.1 is a patch release (version bump) and contains no breaking changes. [1]

Sources

  • Release notes: swift-protobuf 1.33.1 (GitHub). [1]

🌐 Web query:

swift-protobuf security fixes CVE 1.33.1

💡 Result:

I couldn't find any swift-protobuf 1.33.1 release or associated CVE. The latest documented releases are 1.32.0 (release notes) and earlier 1.31.x on the project releases page and package registry. [1][2]

If you meant a different package (e.g., Google protobuf or grpc) or a specific CVE number, tell me which one and I’ll look it up.

Sources:

  • swift-protobuf releases (GitHub). [1]
  • Swift Package Registry — swift-protobuf 1.32.0. [2]

🌐 Web query:

swift-protobuf latest version release history

💡 Result:

Latest stable: SwiftProtobuf 1.32.0 — released Oct 8, 2025. [1][2]

Recent release history (most relevant tags):

  • 1.32.0 — 08 Oct 2025. [1][2]
  • 1.31.2 — 08 Oct 2025. [1]
  • 1.31.1 — 15 Sep 2025. [1]
  • 1.31.0 — 19 Aug 2025. [1]
  • 1.30.0 — 28 May 2025. [1]

Full release list and changelogs on the project’s GitHub Releases page and package registry. [1][2]

Sources:
[1] apple/swift-protobuf — Releases (GitHub).
[2] SwiftProtobuf — Swift Package Registry (release 1.32.0).


Rewrite Package.resolved to use a valid swift-protobuf version; 1.33.1 does not exist.

The latest stable swift-protobuf release is 1.32.0 (October 8, 2025). The available versions are 1.32.0, 1.31.2, 1.31.1, 1.31.0, and 1.30.0. Version 1.33.1 specified in Package.resolved does not exist and will cause dependency resolution to fail. Update to either 1.32.0 (latest) or an earlier valid version.

🤖 Prompt for AI Agents
In wxm-ios.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
around lines 315-316, the package entry pins swift-protobuf to non-existent
version 1.33.1; replace it with a valid release (preferably "1.32.0") and the
matching revision for that tag, or regenerate the file: either manually set
"version" : "1.32.0" and update "revision" to the git commit SHA for
swift-protobuf v1.32.0, or run `swift package update` / `swift package resolve`
in the Xcode project to rewrite Package.resolved so it references an available
swift-protobuf version (1.32.0 or an earlier valid tag).

@weatherxmdev
Copy link
Collaborator

Code Coverage Summary

Framework Source Files Coverage
DataLayer.framework 49 66.82%
DomainLayer.framework 67 83.79%
Toolkit.framework 30 53.38%
WeatherXM.app 406 14.16%
station-intent.appex 2 83.33%
station-widgetExtension.appex 45 33.98%

@weatherxmdev
Copy link
Collaborator

Code Coverage Summary

Framework Source Files Coverage
DataLayer.framework 49 66.82%
DomainLayer.framework 67 83.79%
Toolkit.framework 30 53.38%
WeatherXM.app 406 14.17%
station-intent.appex 2 83.33%
station-widgetExtension.appex 45 34.23%

@pantelisss pantelisss merged commit e3f9f16 into main Nov 3, 2025
4 checks passed
@pantelisss pantelisss deleted the feature/fe-2037-investigate-reported-bugs branch November 3, 2025 13:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants