Skip to content

gerardg/BlinkCodeTest

Repository files navigation

BlinkCodeTest

Architecture

ChatViewModel is a @MainActor ObservableObject and holds the only copy of the conversation list. Both screens read from and write to this one instance, so a sent message updates the inbox and the open thread at the same time.

ConversationService is an actor. It handles JSON load and save, and being an actor keeps file I/O off the main thread without scattering Task.detached at the call sites.

Conversation and Message are plain Codable structs. Snake-case JSON keys are mapped via keyDecodingStrategy.

A note on ObservableObject

This uses the older ObservableObject / @Published / @StateObject pattern rather than the newer @Observable macro. The team isn't able to adopt @Observable yet, so I matched the style they actually use. The shape of the view model is the same either way; switching it later is a mechanical change.

Offline first

On launch, ConversationService.load() looks for a saved file in the app's Documents directory. If nothing is there, it falls back to the bundled code_test_data.json seed. Every send writes the full conversation list back to that file atomically. Kill the app, relaunch, and the messages are still there.

Sorting

Conversations are sorted by lastUpdated descending in the view model after load and after every send, so the most recently active thread sits on top. Messages are sorted ascending in the message view, oldest first.

What I'd do with more time

Split MessageView out into its own MessageViewModel instead of reaching back into ChatViewModel. Fine at this size, awkward at scale.

Replace whole-file JSON persistence with SwiftData or per-conversation files. Rewriting the entire list on every send wastes work once threads get long.

Surface save failures in the UI instead of swallowing them with a print.

Sort messages once when the conversation opens rather than re-sorting inside the view's body on every render.

Add unit tests for the sort and send logic in ChatViewModel, plus a fake ConversationService to drive the offline-first paths.

Cover the missing states: empty inbox, failed load, failed save. Also accessibility labels on rows and a proper keyboard-aware layout.

On AI usage

Used Claude as a co-pilot for architecture discussion and SwiftUI syntax reminders. Code, decisions, and design choices are mine.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages