Skip to content

Conversation

@harutiro
Copy link
Member

@harutiro harutiro commented Sep 23, 2025

Summary

Issue #3「アーキテクチャ違反の修正」に対応し、ViewModelからUserDefaultsへの直接アクセス(68箇所)をClean Architectureに準拠したPreferenceRepositoryパターンに修正しました。

Key Changes

  • PreferenceRepositoryProtocol/PreferenceRepositoryを新規作成

    • UserDefaultsアクセスを抽象化し、テスタビリティを向上
    • フロアマップ、アンテナ、キャリブレーション、センシングフロー関連の設定管理を統合
  • 主要ViewModelクラスの依存性注入対応

    • FloorMapSettingViewModel: 16箇所のUserDefaults直接アクセスを修正
    • FloorMapViewModel: 10箇所のUserDefaults直接アクセスを修正
    • SimpleCalibrationViewModel: 15箇所のUserDefaults直接アクセスを修正
    • その他ConnectionManagement、DataCollection、SensingManagement、Trajectory等の各ViewModelを修正
  • Usecaseクラスの修正

    • ObservationDataUsecase: PreferenceRepository経由でfloorMapId取得
    • DataMigrationUsecase: 移行処理をPreferenceRepository経由に変更
  • テスト対応

    • SimpleCalibrationViewModelTestsでの依存性注入対応

Technical Improvements

  • ✅ Clean Architectureの原則に従ったRepository層の分離
  • ✅ プロトコル指向プログラミングによるテスタビリティの向上
  • ✅ 依存性注入パターンの適用で疎結合なアーキテクチャを実現
  • ✅ 後方互換性を保ちながらデフォルトパラメータで段階的移行

Test Plan

  • ビルド成功確認 (macOS Debug構成)
  • アプリケーション起動確認
  • SwiftFormat適用済み
  • 全テストケースのパス確認(一部テストが残存するが、アプリケーション動作は正常)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • 改善

    • アプリ全体の設定・状態管理を統一し、床マップ、較正結果、セッション履歴、アンテナ配置、接続統計などの保存/復元の信頼性を向上。
    • 初期データの読み込みやフロー進行(センシングフロー、軌跡表示など)がより一貫して動作。
  • リファクタリング

    • 複数画面で分散していた設定保持を一元化し、依存関係を明確化。将来的な拡張やデータ移行の安定性を強化。

@coderabbitai
Copy link

coderabbitai bot commented Sep 23, 2025

Warning

Rate limit exceeded

@harutiro has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 14 minutes and 47 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 3f86364 and 346dedc.

📒 Files selected for processing (13)
  • UWBViewerSystem/Domain/Repository/PreferenceRepository.swift (1 hunks)
  • UWBViewerSystem/Domain/Usecase/DataMigrationUsecase.swift (3 hunks)
  • UWBViewerSystem/Domain/Usecase/ObservationDataUsecase.swift (3 hunks)
  • UWBViewerSystem/Presentation/Router/SensingFlowNavigator.swift (1 hunks)
  • UWBViewerSystem/Presentation/Scenes/FloorMapTab/FloorMapSettingPage/FloorMapSettingViewModel.swift (3 hunks)
  • UWBViewerSystem/Presentation/Scenes/FloorMapTab/FloorMapViewModel.swift (7 hunks)
  • UWBViewerSystem/Presentation/Scenes/FloorMapTab/SystemCalibrationPage/SimpleCalibrationViewModel.swift (3 hunks)
  • UWBViewerSystem/Presentation/Scenes/SensingTab/ConnectionManagementPage/ConnectionManagementViewModel.swift (2 hunks)
  • UWBViewerSystem/Presentation/Scenes/SensingTab/DataCollectionPage/DataCollectionViewModel.swift (3 hunks)
  • UWBViewerSystem/Presentation/Scenes/SensingTab/SensingManagementPage/SensingManagementViewModel.swift (3 hunks)
  • UWBViewerSystem/Presentation/Scenes/SensingTab/SensingViewModel.swift (2 hunks)
  • UWBViewerSystem/Presentation/Scenes/SensingTab/TrajectoryViewPage/TrajectoryViewModel.swift (4 hunks)
  • UWBViewerSystemTests/SimpleCalibrationViewModelTests.swift (1 hunks)

Walkthrough

アプリ内の設定/状態保存をUserDefaults直叩きからPreferenceRepositoryに統一。新規プロトコルと実装を追加し、各Usecase/ViewModel/Router/TestsへDIで導入。フロアマップ情報、校正結果、接続統計、セッションフラグ、移行フラグ等の保存/読込/削除ロジックをRepository経由に置換。

Changes

Cohort / File(s) Summary
Preferences リポジトリ追加
UWBViewerSystem/Domain/Repository/PreferenceRepository.swift
新規: PreferenceRepositoryProtocol定義とUserDefaults実装。各種設定・Codable汎用保存/読込/削除API、移行フラグ、センシングフロー状態等を提供。
データ移行ユースケース
UWBViewerSystem/Domain/Usecase/DataMigrationUsecase.swift
依存性にPreferenceRepositoryを追加。移行フラグの保存/読込/リセットをRepository経由に変更。イニシャライザ更新。
観測データユースケース
UWBViewerSystem/Domain/Usecase/ObservationDataUsecase.swift
PreferenceRepositoryを注入。現在フロアマップID取得をRepository読込に変更。イニシャライザ更新。
ナビゲーター
UWBViewerSystem/Presentation/Router/SensingFlowNavigator.swift
PreferenceRepository依存を追加し、イニシャライザに引数を拡張。
フロアマップ設定VM
.../Presentation/Scenes/FloorMapTab/FloorMapSettingPage/FloorMapSettingViewModel.swift
保存/読込をRepositoryに置換(最終設定・現在フロアマップ情報)。DI対応。
フロアマップVM
.../Presentation/Scenes/FloorMapTab/FloorMapViewModel.swift
現在/有効フロアマップ状態と設定フラグの管理をRepositoryへ移行。通知発火は維持。DI対応。
簡易校正VM
.../Presentation/Scenes/FloorMapTab/SystemCalibrationPage/SimpleCalibrationViewModel.swift
フロアマップ情報の取得源をRepositoryへ変更。DI対応。
接続管理VM
.../Presentation/Scenes/SensingTab/ConnectionManagementPage/ConnectionManagementViewModel.swift
接続統計の保存/読込をRepositoryへ移行。初期化時に読込。DI対応。
データ収集VM
.../Presentation/Scenes/SensingTab/DataCollectionPage/DataCollectionViewModel.swift
直近セッションの保存/読込をCodable汎用APIでRepository化。DI対応。
センシング管理VM
.../Presentation/Scenes/SensingTab/SensingManagementPage/SensingManagementViewModel.swift
セッション実行フラグの設定をRepositoryへ。DI対応。
センシングVM
.../Presentation/Scenes/SensingTab/SensingViewModel.swift
システム状態チェックの各種Bool取得をRepositoryへ。イニシャライザ更新。
軌跡ビューVM
.../Presentation/Scenes/SensingTab/TrajectoryViewPage/TrajectoryViewModel.swift
直近セッション/アンテナ位置/フロアマップの取得をRepositoryへ全面移行。初期データ読込フロー追加。DI対応。
テスト更新
UWBViewerSystemTests/SimpleCalibrationViewModelTests.swift
SimpleCalibrationViewModelの新依存(PreferenceRepository)に合わせ初期化呼び出しを更新。

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User as ユーザー
  participant VM as ViewModel各種
  participant Pref as PreferenceRepository
  participant UD as UserDefaults

  User->>VM: 状態保存/読込操作
  VM->>Pref: save*/load*/set*/get*
  Pref->>UD: setObject/getObject(エンコード/デコード含む)
  UD-->>Pref: 値
  Pref-->>VM: 結果
  VM-->>User: UI更新/遷移
Loading
sequenceDiagram
  autonumber
  participant Mig as DataMigrationUsecase
  participant Pref as PreferenceRepository
  participant Store as UserDefaults

  Mig->>Pref: isMigrationCompleted(key)
  Pref->>Store: getBool(key)
  Store-->>Pref: 状態
  Pref-->>Mig: フラグ
  alt 未完了
    Mig->>Mig: データ変換/移行
    Mig->>Pref: setMigrationCompleted(key, true)
    Pref->>Store: setBool(true)
  else 完了済み
    Mig->>Mig: 何もしない/後処理
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

Poem

ぽんぽん跳ねて設定保存
キャロット色の記憶帳
Repoに集うフロアと線
既定の穴からポンと読む
移行の旗もひらひらと
今日も快調、耳も上向き 🥕🐇

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 21.13% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed タイトル「Issue #3: ViewModelからUserDefaultsへの直接アクセスをPreferenceRepositoryパターンに修正」は、ViewModel側の直接的なUserDefaultsアクセスをPreferenceRepositoryに置き換えるというPRの主要変更を明確に表しており、raw_summaryとpr_objectivesに記載された変更内容と整合しています。簡潔で具体的な表現になっており、履歴を眺めるレビュワーが主旨を把握しやすいため妥当と判断します。

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: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
UWBViewerSystem/Presentation/Scenes/FloorMapTab/FloorMapViewModel.swift (1)

244-251: currentFloorMapInfoの更新/削除漏れにより不整合の恐れ

アクティブなフロアマップ削除時にRepository側のcurrentFloorMapInfoが更新/削除されず、後続画面が古い情報を復元する可能性があります。以下の修正を推奨。

-        if floorMaps.isEmpty {
-            preferenceRepository.setHasFloorMapConfigured(false)
-            selectedFloorMap = nil
-        } else if map.isActive && !floorMaps.isEmpty {
-            floorMaps[0].isActive = true
-            selectedFloorMap = floorMaps[0]
-        }
+        if floorMaps.isEmpty {
+            preferenceRepository.setHasFloorMapConfigured(false)
+            preferenceRepository.removeCurrentFloorMapInfo()
+            selectedFloorMap = nil
+        } else if map.isActive {
+            floorMaps[0].isActive = true
+            let newSelected = floorMaps[0]
+            selectedFloorMap = newSelected
+            updateCurrentFloorMapInfo(newSelected.toFloorMapInfo())
+            preferenceRepository.setHasFloorMapConfigured(true)
+        }
🧹 Nitpick comments (17)
UWBViewerSystem/Domain/Usecase/ObservationDataUsecase.swift (2)

69-71: PreferenceRepositoryのDIは適切だが、デフォルト実装の直接生成はドメイン層の純度を下げます

Composition Rootから必須依存として注入し、ここではデフォルト値を持たせない方がテスト容易性・拡張性が上がります。

-    public init(
-        dataRepository: DataRepositoryProtocol,
-        uwbManager: UWBDataManager,
-        preferenceRepository: PreferenceRepositoryProtocol = PreferenceRepository()
-    ) {
+    public init(
+        dataRepository: DataRepositoryProtocol,
+        uwbManager: UWBDataManager,
+        preferenceRepository: PreferenceRepositoryProtocol
+    ) {

374-375: ObservationSession.floorMapIdはString?です — 型の整合を確認してください

ObservationSessionの定義(UWBViewerSystem/Domain/Entity/ObservationData.swift)は public let floorMapId: String? です。AntennaPositionData や SwiftDataRepository 等は floorMapId: String を前提にしている箇所があるため、ObservationSessionを非Optionalにするか、使用側で明示的にunwrap/代替処理を入れて型を揃えてください。

UWBViewerSystem/Presentation/Router/SensingFlowNavigator.swift (1)

20-25: preferenceRepositoryを注入したなら、UserDefaults直参照を段階的に置換しましょう

現状、saveFlowState/loadFlowStateや各completionチェックがUserDefaults直参照のままです。少なくとも hasExecutedSensingSession(Line 404)はRepository経由に変更し、将来的にはフロー状態(currentStep/completedSteps/isFlowCompleted)も型安全なAPIに集約してください。

参考(変更は該当関数内で実施):

// 例: センシング実行フラグの取得
private func checkSensingExecutionCompletion() -> Bool {
    preferenceRepository.getBool(forKey: "hasExecutedSensingSession")
}

フロー状態は、PreferenceRepositoryに専用メソッド(例: saveSensingFlowState/loadSensingFlowState)を追加してキー隠蔽・型安全化するのが望ましいです。API追加可否をご確認ください。

UWBViewerSystemTests/SimpleCalibrationViewModelTests.swift (2)

19-21: テストの分離性向上: PreferenceRepositoryを分離ストアで初期化

標準UserDefaults共有はテスト間干渉の温床です。RepositoryがUserDefaultsを注入可能であれば、suiteNameを分けたUserDefaultsで生成してください。なければテスト用のMock/インメモリ実装を用意しましょう。


24-33: UserDefaults直接操作をRepository経由へ寄せる

createIsolatedTestViewModel内のクリア処理は、同じRepositoryインスタンスでremoveObjectする方が今後の実装変更に強いです。

 @MainActor
 private func createIsolatedTestViewModel() -> SimpleCalibrationViewModel {
-    // テスト用のMockDataRepositoryを作成
-    let mockRepository = MockDataRepository()
-    let mockPreferenceRepository = PreferenceRepository()
-
-    // UserDefaultsをクリア
-    UserDefaults.standard.removeObject(forKey: "currentFloorMapInfo")
-
-    let viewModel = SimpleCalibrationViewModel(dataRepository: mockRepository, preferenceRepository: mockPreferenceRepository)
+    let mockRepository = MockDataRepository()
+    let mockPreferenceRepository = PreferenceRepository()
+    // Repository経由でクリア(APIがある前提。なければ追加検討)
+    mockPreferenceRepository.removeObject(forKey: "currentFloorMapInfo")
+    let viewModel = SimpleCalibrationViewModel(
+        dataRepository: mockRepository,
+        preferenceRepository: mockPreferenceRepository
+    )
 
     return viewModel
 }
UWBViewerSystem/Presentation/Scenes/SensingTab/SensingManagementPage/SensingManagementViewModel.swift (1)

197-200: フロー連携フラグの保存をRepositoryへ移行できています

SensingFlowNavigator側の参照もRepositoryに統一すると整合性が取りやすいです。

UWBViewerSystem/Presentation/Scenes/SensingTab/TrajectoryViewPage/TrajectoryViewModel.swift (3)

103-107: セッション一覧のRepository読込は適切です

キー文字列の集中管理(定数化 or Repository専用API)を検討ください。


215-228: フロア寸法が不正な場合のゼロ除算防止を追加

width/depthが0以下のケースにフォールバックしましょう。

-        let canvasSize = CGSize(width: 500, height: 500)  // マップキャンバスのサイズ
-        let scaleX = Double(canvasSize.width) / floorMapInfo.width
-        let scaleY = Double(canvasSize.height) / floorMapInfo.depth
+        let canvasSize = CGSize(width: 500, height: 500)  // マップキャンバスのサイズ
+        guard floorMapInfo.width > 0, floorMapInfo.depth > 0 else {
+            return CGPoint(x: 50, y: 50)
+        }
+        let scaleX = Double(canvasSize.width) / floorMapInfo.width
+        let scaleY = Double(canvasSize.height) / floorMapInfo.depth

36-45: デフォルトの時間フィルタで軌跡が0件になりやすい

startTimeFilter/endTimeFilterがともにDate()初期化だと現在時刻”のみ”に絞られます。初期表示は全件表示にした方が自然です(例: distantPast/distantFuture)。

例(該当プロパティ宣言部の変更案・抜粋):

@Published var startTimeFilter = Date.distantPast
@Published var endTimeFilter = Date.distantFuture
UWBViewerSystem/Presentation/Scenes/SensingTab/SensingViewModel.swift (1)

46-49: ストリングキーの散在を避け、リポジトリの型安全なAPIを使ってください
hasFloorMapConfigured/hasDeviceConnected は既にリポジトリ側に専用メソッドがあるため、SensingViewModel で文字列キーを直接使わずそちらを呼び出してください。
修正例(UWBViewerSystem/Presentation/Scenes/SensingTab/SensingViewModel.swift 行47–48):

  • preferenceRepository.getBool(forKey: "hasFloorMapConfigured") → preferenceRepository.getHasFloorMapConfigured()
  • preferenceRepository.getBool(forKey: "hasDeviceConnected") → dataRepository.loadHasDeviceConnected()(または該当リポジトリのメソッド)
    参照実装: UWBViewerSystem/Domain/Repository/PreferenceRepository.swift (getHasFloorMapConfigured / setHasFloorMapConfigured), UWBViewerSystem/Domain/Repository/DataRepository.swift (loadHasDeviceConnected / saveHasDeviceConnected), テスト: UWBViewerSystemTests/TestHelpers/MockDataRepository.swift
UWBViewerSystem/Presentation/Scenes/FloorMapTab/FloorMapSettingPage/FloorMapSettingViewModel.swift (1)

288-290: 保存完了時に構成フラグを立てる

フロアマップ保存成功後に構成済みフラグも立てておくと初回導線が安定します(他画面のフォールバックと整合)。

         // フロアマップ情報を保存
         preferenceRepository.saveCurrentFloorMapInfo(info)
+        preferenceRepository.setHasFloorMapConfigured(true)
UWBViewerSystem/Presentation/Scenes/SensingTab/ConnectionManagementPage/ConnectionManagementViewModel.swift (1)

221-229: Int64の切り捨て回避と型安全化

  • dataTransferredをIntへ変換して保存すると環境によっては桁あふれリスク。NSNumber経由でInt64として保存/復元を推奨。
  • 可能なら辞書ではなくCodableな構造体での保存に寄せましょう(Repositoryの汎用setData/getDataが活用可)。
     private func saveStatistics() {
-        let statistics = [
+        let statistics: [String: Any] = [
             "totalConnections": totalConnections,
             "totalMessages": totalMessages,
-            "dataTransferred": Int(dataTransferred),
+            "dataTransferred": dataTransferred, // Int64としてNSNumberにブリッジされる
         ]
 
         preferenceRepository.saveConnectionStatistics(statistics)
     }
 
     private func loadStatistics() {
-        if let statistics = preferenceRepository.loadConnectionStatistics() {
-            totalConnections = statistics["totalConnections"] as? Int ?? 0
-            totalMessages = statistics["totalMessages"] as? Int ?? 0
-            dataTransferred = Int64(statistics["dataTransferred"] as? Int ?? 0)
+        if let statistics = preferenceRepository.loadConnectionStatistics() {
+            totalConnections = statistics["totalConnections"] as? Int ?? 0
+            totalMessages = statistics["totalMessages"] as? Int ?? 0
+            if let n = statistics["dataTransferred"] as? NSNumber {
+                dataTransferred = n.int64Value
+            } else {
+                dataTransferred = 0
+            }
         }
     }

型安全化(参考・別ファイル修正が必要):

// モデル
struct ConnectionStatistics: Codable {
    let totalConnections: Int
    let totalMessages: Int
    let dataTransferred: Int64
}

// Repositoryに型付きAPIを追加
func saveConnectionStatistics(_ stats: ConnectionStatistics) { try? setData(stats, forKey: "ConnectionStatisticsV2") }
func loadConnectionStatisticsV2() -> ConnectionStatistics? { getData(ConnectionStatistics.self, forKey: "ConnectionStatisticsV2") }

Also applies to: 232-236

UWBViewerSystem/Presentation/Scenes/FloorMapTab/SystemCalibrationPage/SimpleCalibrationViewModel.swift (1)

558-567: FloorMapChanged通知も監視して即時反映を

UserDefaults全体の変更監視に加え、FloorMapViewModelが投げる"FloorMapChanged"をピンポイントで購読すると反映がより確実です。

     private func setupDataObserver() {
         // UserDefaultsの "currentFloorMapInfo" キーの変更を監視
         NotificationCenter.default.publisher(for: UserDefaults.didChangeNotification)
             .sink { [weak self] _ in
                 Task { @MainActor in
                     self?.loadCurrentFloorMapData()
                 }
             }
             .store(in: &cancellables)
+
+        // FloorMap変更のドメイン通知を監視
+        NotificationCenter.default.publisher(for: .init("FloorMapChanged"))
+            .sink { [weak self] notification in
+                guard let self else { return }
+                if let info = notification.object as? FloorMapInfo {
+                    Task { @MainActor in
+                        self.currentFloorMapId = info.id
+                        self.currentFloorMapInfo = info
+                        self.loadFloorMapImage(for: info.id)
+                    }
+                } else {
+                    Task { @MainActor in
+                        self.loadCurrentFloorMapData()
+                    }
+                }
+            }
+            .store(in: &cancellables)
     }
UWBViewerSystem/Domain/Repository/PreferenceRepository.swift (3)

249-256: setDataのシグネチャはジェネリック化を推奨

引数でのsome Codableは最新ツールチェイン依存です。T: CodableでgetDataと対称にしておくと互換性が高まります。

-    public func setData(_ value: some Codable, forKey key: String) throws {
+    public func setData<T: Codable>(_ value: T, forKey key: String) throws {
         let encoded = try JSONEncoder().encode(value)
         userDefaults.set(encoded, forKey: key)
     }

205-211: 接続統計は型付き保存を検討

[String: Any]は呼び出し側での取り扱いが不安定です。Codableな構造体(例: ConnectionStatistics)でV2キー保存へ移行し、旧形式は移行用に読み出す方針を推奨。


156-171: シンプル型はUserDefaultsのネイティブ型での保存も可

currentStepcompletedStepssetString/userDefaults.set([String])で足ります。JSON化は過剰なので、必要性がなければ単純化を検討ください(互換性配慮の上で)。

UWBViewerSystem/Presentation/Scenes/SensingTab/DataCollectionPage/DataCollectionViewModel.swift (1)

159-165: SensingSessionはCodableで保存は問題なし — 文字列キーはRepository専用メソッドへ移譲してください

SensingSessionがCodableであることを確認しました(UWBViewerSystem/Domain/Entity/SensingSession.swift)。DataCollectionViewModelのsaveRecentSessionsは現在 "RecentSensingSessions" を直接指定しているため、PreferenceRepositoryに saveRecentSensingSessions(_:) / loadRecentSensingSessions() のような専用APIを追加してキー管理を一元化してください。該当: UWBViewerSystem/Presentation/Scenes/SensingTab/DataCollectionPage/DataCollectionViewModel.swift (159–165, 167–171).

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b5e5d76 and 3f86364.

📒 Files selected for processing (13)
  • UWBViewerSystem/Domain/Repository/PreferenceRepository.swift (1 hunks)
  • UWBViewerSystem/Domain/Usecase/DataMigrationUsecase.swift (3 hunks)
  • UWBViewerSystem/Domain/Usecase/ObservationDataUsecase.swift (3 hunks)
  • UWBViewerSystem/Presentation/Router/SensingFlowNavigator.swift (1 hunks)
  • UWBViewerSystem/Presentation/Scenes/FloorMapTab/FloorMapSettingPage/FloorMapSettingViewModel.swift (3 hunks)
  • UWBViewerSystem/Presentation/Scenes/FloorMapTab/FloorMapViewModel.swift (7 hunks)
  • UWBViewerSystem/Presentation/Scenes/FloorMapTab/SystemCalibrationPage/SimpleCalibrationViewModel.swift (3 hunks)
  • UWBViewerSystem/Presentation/Scenes/SensingTab/ConnectionManagementPage/ConnectionManagementViewModel.swift (2 hunks)
  • UWBViewerSystem/Presentation/Scenes/SensingTab/DataCollectionPage/DataCollectionViewModel.swift (3 hunks)
  • UWBViewerSystem/Presentation/Scenes/SensingTab/SensingManagementPage/SensingManagementViewModel.swift (3 hunks)
  • UWBViewerSystem/Presentation/Scenes/SensingTab/SensingViewModel.swift (2 hunks)
  • UWBViewerSystem/Presentation/Scenes/SensingTab/TrajectoryViewPage/TrajectoryViewModel.swift (4 hunks)
  • UWBViewerSystemTests/SimpleCalibrationViewModelTests.swift (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (11)
UWBViewerSystem/Presentation/Scenes/SensingTab/ConnectionManagementPage/ConnectionManagementViewModel.swift (1)
UWBViewerSystem/Domain/Repository/PreferenceRepository.swift (2)
  • saveConnectionStatistics (205-207)
  • loadConnectionStatistics (209-211)
UWBViewerSystem/Domain/Usecase/DataMigrationUsecase.swift (1)
UWBViewerSystem/Domain/Repository/PreferenceRepository.swift (3)
  • isMigrationCompleted (219-221)
  • setMigrationCompleted (215-217)
  • removeObject (259-261)
UWBViewerSystem/Domain/Usecase/ObservationDataUsecase.swift (1)
UWBViewerSystem/Domain/Repository/PreferenceRepository.swift (1)
  • loadCurrentFloorMapInfo (87-89)
UWBViewerSystem/Presentation/Scenes/FloorMapTab/FloorMapViewModel.swift (1)
UWBViewerSystem/Domain/Repository/PreferenceRepository.swift (3)
  • loadCurrentFloorMapInfo (87-89)
  • setHasFloorMapConfigured (110-112)
  • saveCurrentFloorMapInfo (79-85)
UWBViewerSystem/Presentation/Scenes/SensingTab/SensingViewModel.swift (1)
UWBViewerSystem/Domain/Repository/PreferenceRepository.swift (1)
  • getBool (229-231)
UWBViewerSystem/Presentation/Scenes/FloorMapTab/FloorMapSettingPage/FloorMapSettingViewModel.swift (1)
UWBViewerSystem/Domain/Repository/PreferenceRepository.swift (3)
  • loadLastFloorSettings (102-108)
  • saveLastFloorSettings (95-100)
  • saveCurrentFloorMapInfo (79-85)
UWBViewerSystemTests/SimpleCalibrationViewModelTests.swift (1)
UWBViewerSystem/Domain/Repository/PreferenceRepository.swift (1)
  • removeObject (259-261)
UWBViewerSystem/Presentation/Scenes/SensingTab/DataCollectionPage/DataCollectionViewModel.swift (1)
UWBViewerSystem/Domain/Repository/PreferenceRepository.swift (2)
  • setData (249-252)
  • getData (254-257)
UWBViewerSystem/Presentation/Scenes/SensingTab/SensingManagementPage/SensingManagementViewModel.swift (1)
UWBViewerSystem/Domain/Repository/PreferenceRepository.swift (1)
  • setHasExecutedSensingSession (179-181)
UWBViewerSystem/Presentation/Scenes/FloorMapTab/SystemCalibrationPage/SimpleCalibrationViewModel.swift (1)
UWBViewerSystem/Domain/Repository/PreferenceRepository.swift (1)
  • loadCurrentFloorMapInfo (87-89)
UWBViewerSystem/Presentation/Scenes/SensingTab/TrajectoryViewPage/TrajectoryViewModel.swift (2)
UWBViewerSystem/Presentation/Scenes/FloorMapTab/SystemCalibrationPage/SimpleCalibrationViewModel.swift (2)
  • loadInitialData (169-173)
  • loadAntennaPositions (460-493)
UWBViewerSystem/Domain/Repository/PreferenceRepository.swift (2)
  • getData (254-257)
  • loadCurrentFloorMapInfo (87-89)
🔇 Additional comments (19)
UWBViewerSystem/Domain/Usecase/ObservationDataUsecase.swift (1)

79-87: 初期化子へのPreferenceRepository導入は妥当です

依存の明確化・テスト性の向上に寄与しています。

UWBViewerSystem/Domain/Usecase/DataMigrationUsecase.swift (3)

11-22: MigrationフラグのPreferenceRepository移行は適切です

ドメインユースケースの責務に集中できています。


110-112: UserDefaultsキー確認("sensingSessions")
リポジトリ検索で参照は削除箇所(UWBViewerSystem/Domain/Usecase/DataMigrationUsecase.swift:111)のみでした。旧バージョンや別モジュールで使われていないか、実際に保存されるデータかを確認してください。


48-49: 移行完了フラグ書き込みはOK — migrationKeyの一貫利用を全コードベースで確認してください
場所: UWBViewerSystem/Domain/Usecase/DataMigrationUsecase.swift(48–49)
自動検索で関連参照が見つかりませんでした。migrationKeyの重複・誤綴りがないか、リポジトリ全体で 'migrationKey' と 'setMigrationCompleted'(および既存の完了フラグ名)を検索して確認してください。

UWBViewerSystem/Presentation/Scenes/SensingTab/SensingManagementPage/SensingManagementViewModel.swift (2)

18-22: DI対応の方針は適切です

UseCaseとPreferenceRepositoryの明示注入で責務が明確になっています。


30-35: 初期化子の拡張も妥当です

既存呼び出しへの影響を最小化しつつ拡張できています。

UWBViewerSystem/Presentation/Scenes/SensingTab/SensingViewModel.swift (1)

30-34: PreferenceRepositoryの導入は適切です

参照の集中で将来のストア変更にも強くなります。

UWBViewerSystem/Presentation/Scenes/SensingTab/TrajectoryViewPage/TrajectoryViewModel.swift (2)

50-55: DI導入と初期データ読み込みの整理は良いです

初期化時のロードで画面表示の初期状態が安定します。


127-143: アンテナ位置のRepository読込は適切です

座標→画面座標変換も分離されていて読みやすいです。

UWBViewerSystem/Presentation/Scenes/SensingTab/DataCollectionPage/DataCollectionViewModel.swift (1)

23-27: DI導入は妥当です

UseCase/Repositoryの直接注入への移行は明確で影響範囲も限定的。デフォルト引数で後方互換も担保できています。

Also applies to: 32-34, 43-43

UWBViewerSystem/Presentation/Scenes/FloorMapTab/FloorMapViewModel.swift (3)

65-69: PreferenceRepositoryのDI導入は適切です

初期化子の簡潔さとデフォルト実装の提供が良いです。


161-175: フォールバック時の復元ロジックは妥当です

Repository状態のトレース出力とselectedFloorMapの同期まで一貫しています。


209-214: 変更通知の発行は適切です

Repository更新後にNotificationを飛ばしており、依存側の同期に有用です。

UWBViewerSystem/Presentation/Scenes/FloorMapTab/FloorMapSettingPage/FloorMapSettingViewModel.swift (2)

18-18: DI導入は適切です

PreferenceRepositoryの注入でテスト容易性が向上しています。

Also applies to: 68-73


254-272: 設定値の読み戻しはOK

nil/空文字の扱いと既定値維持の方針が明確です。

UWBViewerSystem/Presentation/Scenes/SensingTab/ConnectionManagementPage/ConnectionManagementViewModel.swift (1)

67-70: RepositoryのDI導入と初期ロードは良いです

統計の初期ロードをinit/initializeConnection双方で呼ぶ点も安全側で良いです。

Also applies to: 77-89

UWBViewerSystem/Presentation/Scenes/FloorMapTab/SystemCalibrationPage/SimpleCalibrationViewModel.swift (2)

140-146: PreferenceRepositoryのDI導入はOK

初期データロードの流れと整合しています。


309-340: 確認済: FloorMapInfo.image は拡張で計算プロパティ(Codable に含まれない)

FloorMapInfo は CommonTypes.swift に定義され、プラットフォーム別 extension で image (NSImage?/UIImage?) が計算プロパティとして実装されているため、Codable のエンコード対象ではなく現在の参照は問題ありません。
場所: UWBViewerSystem/Domain/Entity/CommonTypes.swift

UWBViewerSystem/Domain/Repository/PreferenceRepository.swift (1)

87-107: lastFloorSettingsのOptional復元方針は妥当

0初期化を避け、未設定を明確化できています。現状の実装で問題ありません。

harutiro and others added 3 commits September 23, 2025 22:16
## 変更内容
- PreferenceRepositoryProtocol/PreferenceRepositoryを新規作成し、UserDefaultsアクセスを抽象化
- 主要ViewModelクラス(FloorMapSettingViewModel、FloorMapViewModel、SimpleCalibrationViewModel等)での依存性注入対応
- UsecaseクラスでのUserDefaults直接アクセスをPreferenceRepository経由に変更
- テストファイルの依存性注入対応

## 技術的改善
- Clean Architectureの原則に従ったRepository層の分離
- プロトコル指向プログラミングによるテスタビリティの向上
- 依存性注入パターンの適用で疎結合なアーキテクチャを実現

## 検証済み
- ビルド成功確認
- アプリケーション起動確認完了

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
…vationDataUsecaseに包括的なSwiftDocコメントを追加

- PreferenceRepositoryProtocol: アプリケーション設定管理の全メソッドにドキュメント追加
- PreferenceRepository: UserDefaults実装クラスに詳細な設計方針と使用例を追加
- DataMigrationUsecase: データ移行プロセスの説明と冪等性保証の文書化
- ObservationDataUsecase: UWB観測データ収集の包括的なドキュメント追加
- 各メソッドのパラメータ、戻り値、エラーハンドリングを詳細に説明
- 使用例とアーキテクチャにおける位置づけを明記

80%のDocstring Coverageを目指した包括的なドキュメント改善を実施。

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
@harutiro harutiro force-pushed the issue-3-fix-architecture-violations branch from a7520a6 to 346dedc Compare September 23, 2025 13:20
@harutiro harutiro merged commit 966497c into main Sep 23, 2025
2 checks passed
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.

2 participants