[03-Developer] #226 Catalog Gallery 구현
- Drift schema v2: Protocols.category CHECK 6→7 (light_circadian/sleep/movement/
nutrition/focus_cognition/recovery_stress/emotion_relationship). schemaVersion
1→2 + onUpgrade migrateV1ToV2 (DROP+CREATE+reseed flag 클리어).
- protocols.json 34 항목 v2 재분류 (1차 효과 기준). emotion_relationship 0 매핑.
- 도메인: DisplayCategory enum (8) + CatalogItem sealed (Protocol/Break/Diet).
- 데이터: CatalogRepository.all/byId/referencesByIds (3 source 통합).
- 상태: catalog_providers.dart (catalogItems / groupedByCategory / refsByIds).
- UI: ProtocolGalleryScreen (카테고리 칩 + 카드 그리드) + ProtocolPreviewScreen
(모든 필드 + reference 펼치기 + "내 습관으로" disabled placeholder) +
CatalogCard / CategoryChipRow / ReferenceExpandCard. HabitListScreen 빈
상태 CTA + AppBar 액션.
- 테스트: migration_v1_to_v2 3건 + display_category 5건 + catalog_repository
9건 + gallery widget 3건 + preview widget 3건 = 23 신규. 기존 88 회귀 0,
flutter analyze 0 issues. 110 passed / 1 skipped.
설계서: docs/design/226-catalog-gallery/{README, fn-catalog_repository,
fn-migration_v1_to_v2}.md + ADR-0004.
Refs #226
This commit is contained in:
59
app/test/domain/catalog/display_category_test.dart
Normal file
59
app/test/domain/catalog/display_category_test.dart
Normal file
@@ -0,0 +1,59 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:life_helper/domain/catalog/display_category.dart';
|
||||
|
||||
void main() {
|
||||
test('fromProtocolCategory maps all 7 protocol categories', () {
|
||||
expect(DisplayCategory.fromProtocolCategory('light_circadian'),
|
||||
DisplayCategory.lightCircadian);
|
||||
expect(DisplayCategory.fromProtocolCategory('sleep'),
|
||||
DisplayCategory.sleep);
|
||||
expect(DisplayCategory.fromProtocolCategory('movement'),
|
||||
DisplayCategory.movement);
|
||||
expect(DisplayCategory.fromProtocolCategory('nutrition'),
|
||||
DisplayCategory.nutrition);
|
||||
expect(DisplayCategory.fromProtocolCategory('focus_cognition'),
|
||||
DisplayCategory.focusCognition);
|
||||
expect(DisplayCategory.fromProtocolCategory('recovery_stress'),
|
||||
DisplayCategory.recoveryStress);
|
||||
expect(DisplayCategory.fromProtocolCategory('emotion_relationship'),
|
||||
DisplayCategory.emotionRelationship);
|
||||
});
|
||||
|
||||
test('fromProtocolCategory returns null for unknown / break_habit', () {
|
||||
expect(DisplayCategory.fromProtocolCategory('break_habit'), isNull);
|
||||
expect(DisplayCategory.fromProtocolCategory('health'), isNull);
|
||||
expect(DisplayCategory.fromProtocolCategory(''), isNull);
|
||||
});
|
||||
|
||||
test('breakHabit enum has null protocolKey (별도 source)', () {
|
||||
expect(DisplayCategory.breakHabit.protocolKey, isNull);
|
||||
});
|
||||
|
||||
test('all 8 enum values have label + icon', () {
|
||||
for (final c in DisplayCategory.values) {
|
||||
expect(c.label.isNotEmpty, true, reason: '${c.name} label');
|
||||
}
|
||||
expect(DisplayCategory.values.length, 8);
|
||||
});
|
||||
|
||||
test('real seed: 모든 protocols.json id 가 정확히 1 DisplayCategory 에 매핑', () {
|
||||
// Load from disk (test runs from app/).
|
||||
final file = File('assets/seed/protocols.json');
|
||||
final rows = json.decode(file.readAsStringSync()) as List;
|
||||
expect(rows.length, 34, reason: 'protocols.json count');
|
||||
final seenCategories = <DisplayCategory>{};
|
||||
for (final r in rows.cast<Map<String, dynamic>>()) {
|
||||
final cat = r['category'] as String;
|
||||
final dc = DisplayCategory.fromProtocolCategory(cat);
|
||||
expect(dc, isNotNull,
|
||||
reason: 'id=${r['id']} category=$cat not mapped');
|
||||
seenCategories.add(dc!);
|
||||
}
|
||||
// 매핑 누락은 없어야 함, 단 emotion_relationship 은 0 매핑 OK.
|
||||
expect(seenCategories.contains(DisplayCategory.breakHabit), false,
|
||||
reason: 'protocols 는 breakHabit 와 직접 매핑 X');
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user