Add Today View dashboard replacing Care tab (Phase 6)

Replace the Care tab with a new Today View dashboard that shows
overdue and today's care tasks grouped by room. Features include:

- TodayView: Main dashboard with greeting, progress stats, and task sections
- TodayViewModel: Room-based task grouping with completion tracking
- QuickStatsBar: Progress indicator showing completed vs total tasks
- TaskSection: Collapsible sections for overdue/today tasks
- RoomTaskGroup: Tasks grouped by room with "Water all" bulk action
- InMemoryRoomRepository: In-memory room storage for testing/mocks

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Trey t
2026-01-23 15:05:55 -06:00
parent 08ced7dbbb
commit efd935568a
9 changed files with 998 additions and 10 deletions

View File

@@ -6,6 +6,15 @@
objectVersion = 77;
objects = {
/* Begin PBXBuildFile section */
010B95AE71B789A1929646CE /* TodayViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A34C0DA41757D0CD1B7AB99 /* TodayViewModel.swift */; };
5DB7D935A323777A1B908A37 /* RoomTaskGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 678533C17B8C3244E2001F4F /* RoomTaskGroup.swift */; };
E1AE868BC224D8A4AFE1CD52 /* TodayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A9D5ED974C43A2EC68CD03B /* TodayView.swift */; };
E201A13692202CDE6B2DE12B /* TaskSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = DADA0723BB8443C632252796 /* TaskSection.swift */; };
EB273C140861D3673719DC63 /* QuickStatsBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = C50ADB17181CA3A5FB44BBE2 /* QuickStatsBar.swift */; };
FA125D54D0111F44B104862B /* InMemoryRoomRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52FD1E71E8C36B0075A932F2 /* InMemoryRoomRepository.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
1C4B79FA2F21C37C00ED69CF /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
@@ -27,6 +36,12 @@
1C4B79E82F21C37A00ED69CF /* PlantGuide.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PlantGuide.app; sourceTree = BUILT_PRODUCTS_DIR; };
1C4B79F92F21C37C00ED69CF /* PlantGuideTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PlantGuideTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
1C4B7A032F21C37C00ED69CF /* PlantGuideUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PlantGuideUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
52FD1E71E8C36B0075A932F2 /* InMemoryRoomRepository.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = InMemoryRoomRepository.swift; sourceTree = "<group>"; };
678533C17B8C3244E2001F4F /* RoomTaskGroup.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = RoomTaskGroup.swift; sourceTree = "<group>"; };
7A9D5ED974C43A2EC68CD03B /* TodayView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = TodayView.swift; sourceTree = "<group>"; };
8A34C0DA41757D0CD1B7AB99 /* TodayViewModel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = TodayViewModel.swift; sourceTree = "<group>"; };
C50ADB17181CA3A5FB44BBE2 /* QuickStatsBar.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = QuickStatsBar.swift; sourceTree = "<group>"; };
DADA0723BB8443C632252796 /* TaskSection.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = TaskSection.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
@@ -50,11 +65,15 @@
};
1C4B79FC2F21C37C00ED69CF /* PlantGuideTests */ = {
isa = PBXFileSystemSynchronizedRootGroup;
exceptions = (
);
path = PlantGuideTests;
sourceTree = "<group>";
};
1C4B7A062F21C37C00ED69CF /* PlantGuideUITests */ = {
isa = PBXFileSystemSynchronizedRootGroup;
exceptions = (
);
path = PlantGuideUITests;
sourceTree = "<group>";
};
@@ -85,6 +104,17 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
1A0266DEC4BEC766E4813767 /* Components */ = {
isa = PBXGroup;
children = (
C50ADB17181CA3A5FB44BBE2 /* QuickStatsBar.swift */,
DADA0723BB8443C632252796 /* TaskSection.swift */,
678533C17B8C3244E2001F4F /* RoomTaskGroup.swift */,
);
name = Components;
path = Components;
sourceTree = "<group>";
};
1C4B79DF2F21C37A00ED69CF = {
isa = PBXGroup;
children = (
@@ -92,6 +122,7 @@
1C4B79FC2F21C37C00ED69CF /* PlantGuideTests */,
1C4B7A062F21C37C00ED69CF /* PlantGuideUITests */,
1C4B79E92F21C37A00ED69CF /* Products */,
7B600A469FEF4379984ED673 /* PlantGuide */,
);
sourceTree = "<group>";
};
@@ -105,6 +136,63 @@
name = Products;
sourceTree = "<group>";
};
43A10090BDB504EEA8160579 /* Data */ = {
isa = PBXGroup;
children = (
775B6E967C5DFFD7F1871824 /* Repositories */,
);
name = Data;
path = Data;
sourceTree = "<group>";
};
775B6E967C5DFFD7F1871824 /* Repositories */ = {
isa = PBXGroup;
children = (
52FD1E71E8C36B0075A932F2 /* InMemoryRoomRepository.swift */,
);
name = Repositories;
path = Repositories;
sourceTree = "<group>";
};
7B600A469FEF4379984ED673 /* PlantGuide */ = {
isa = PBXGroup;
children = (
DEFE3CA84863FD85C7F7BB48 /* Presentation */,
43A10090BDB504EEA8160579 /* Data */,
);
name = PlantGuide;
path = PlantGuide;
sourceTree = "<group>";
};
96D83367DDD373621B7CA753 /* Scenes */ = {
isa = PBXGroup;
children = (
EB55B50C41964C736A4FF8A3 /* TodayView */,
);
name = Scenes;
path = Scenes;
sourceTree = "<group>";
};
DEFE3CA84863FD85C7F7BB48 /* Presentation */ = {
isa = PBXGroup;
children = (
96D83367DDD373621B7CA753 /* Scenes */,
);
name = Presentation;
path = Presentation;
sourceTree = "<group>";
};
EB55B50C41964C736A4FF8A3 /* TodayView */ = {
isa = PBXGroup;
children = (
8A34C0DA41757D0CD1B7AB99 /* TodayViewModel.swift */,
7A9D5ED974C43A2EC68CD03B /* TodayView.swift */,
1A0266DEC4BEC766E4813767 /* Components */,
);
name = TodayView;
path = TodayView;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@@ -124,8 +212,6 @@
1C4B79EA2F21C37A00ED69CF /* PlantGuide */,
);
name = PlantGuide;
packageProductDependencies = (
);
productName = PlantGuide;
productReference = 1C4B79E82F21C37A00ED69CF /* PlantGuide.app */;
productType = "com.apple.product-type.application";
@@ -147,8 +233,6 @@
1C4B79FC2F21C37C00ED69CF /* PlantGuideTests */,
);
name = PlantGuideTests;
packageProductDependencies = (
);
productName = PlantGuideTests;
productReference = 1C4B79F92F21C37C00ED69CF /* PlantGuideTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
@@ -170,8 +254,6 @@
1C4B7A062F21C37C00ED69CF /* PlantGuideUITests */,
);
name = PlantGuideUITests;
packageProductDependencies = (
);
productName = PlantGuideUITests;
productReference = 1C4B7A032F21C37C00ED69CF /* PlantGuideUITests.xctest */;
productType = "com.apple.product-type.bundle.ui-testing";
@@ -249,6 +331,12 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
010B95AE71B789A1929646CE /* TodayViewModel.swift in Sources */,
E1AE868BC224D8A4AFE1CD52 /* TodayView.swift in Sources */,
EB273C140861D3673719DC63 /* QuickStatsBar.swift in Sources */,
E201A13692202CDE6B2DE12B /* TaskSection.swift in Sources */,
5DB7D935A323777A1B908A37 /* RoomTaskGroup.swift in Sources */,
FA125D54D0111F44B104862B /* InMemoryRoomRepository.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};