Skip to content

Commit 807be03

Browse files
committed
feat(service): add demo data initializer service
- Implement DemoDataInitializerService to ensure essential user-specific data exists in demo environment - Add methods to initialize UserAppSettings, UserContentPreferences, and User object in memory - Include error handling and logging for data initialization process - Service is designed specifically for demo environment, as production/development use backend API for data initialization
1 parent 6febb45 commit 807be03

File tree

1 file changed

+181
-0
lines changed

1 file changed

+181
-0
lines changed
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
import 'package:core/core.dart';
2+
import 'package:data_repository/data_repository.dart';
3+
import 'package:flutter/material.dart'; // Required for ThemeMode, AppBaseTheme, etc.
4+
5+
/// {@template demo_data_initializer_service}
6+
/// A service responsible for ensuring that essential user-specific data
7+
/// (like [UserAppSettings], [UserContentPreferences], and the [User] object
8+
/// itself) exists in the data in-memory clients when a user is first encountered
9+
/// in the demo environment.
10+
///
11+
/// This service is specifically designed for the in-memory data clients
12+
/// used in the demo environment. In production/development environments,
13+
/// the backend API is responsible for initializing user data.
14+
/// {@endtemplate}
15+
class DemoDataInitializerService {
16+
/// {@macro demo_data_initializer_service}
17+
const DemoDataInitializerService({
18+
required DataRepository<UserAppSettings> userAppSettingsRepository,
19+
required DataRepository<UserContentPreferences>
20+
userContentPreferencesRepository,
21+
required DataRepository<User> userRepository,
22+
}) : _userAppSettingsRepository = userAppSettingsRepository,
23+
_userContentPreferencesRepository = userContentPreferencesRepository,
24+
_userRepository = userRepository;
25+
26+
final DataRepository<UserAppSettings> _userAppSettingsRepository;
27+
final DataRepository<UserContentPreferences>
28+
_userContentPreferencesRepository;
29+
final DataRepository<User> _userRepository;
30+
31+
/// Initializes essential user-specific data in the in-memory clients
32+
/// for the given [user].
33+
///
34+
/// This method checks if [UserAppSettings], [UserContentPreferences],
35+
/// and the [User] object itself exist for the provided user ID. If any
36+
/// are missing, it creates them with default values.
37+
///
38+
/// This prevents "READ FAILED" errors when the application attempts to
39+
/// access these user-specific data points for a newly signed-in anonymous
40+
/// user in the demo environment.
41+
Future<void> initializeUserSpecificData(User user) async {
42+
print(
43+
'[DemoDataInitializerService] Initializing user-specific data for '
44+
'user ID: ${user.id}',
45+
);
46+
47+
// Ensure UserAppSettings exist
48+
await _ensureUserAppSettingsExist(user.id);
49+
50+
// Ensure UserContentPreferences exist
51+
await _ensureUserContentPreferencesExist(user.id);
52+
53+
// Ensure the User object itself is up-to-date in the user client
54+
await _ensureUserClientUserExists(user);
55+
56+
print(
57+
'[DemoDataInitializerService] User-specific data initialization '
58+
'completed for user ID: ${user.id}',
59+
);
60+
}
61+
62+
/// Ensures that [UserAppSettings] exist for the given [userId].
63+
/// If not found, creates default settings.
64+
Future<void> _ensureUserAppSettingsExist(String userId) async {
65+
try {
66+
await _userAppSettingsRepository.read(id: userId, userId: userId);
67+
print(
68+
'[DemoDataInitializerService] UserAppSettings found for user ID: $userId.',
69+
);
70+
} on NotFoundException {
71+
print(
72+
'[DemoDataInitializerService] UserAppSettings not found for user ID: '
73+
'$userId. Creating default settings.',
74+
);
75+
final defaultSettings = UserAppSettings(
76+
id: userId,
77+
displaySettings: const DisplaySettings(
78+
baseTheme: AppBaseTheme.system,
79+
accentTheme: AppAccentTheme.defaultBlue,
80+
fontFamily: 'SystemDefault',
81+
textScaleFactor: AppTextScaleFactor.medium,
82+
fontWeight: AppFontWeight.regular,
83+
),
84+
language: languagesFixturesData.firstWhere(
85+
(l) => l.code == 'en',
86+
orElse: () => throw StateError(
87+
'Default language "en" not found in language fixtures.',
88+
),
89+
),
90+
feedPreferences: const FeedDisplayPreferences(
91+
headlineDensity: HeadlineDensity.standard,
92+
headlineImageStyle: HeadlineImageStyle.smallThumbnail,
93+
showSourceInHeadlineFeed: true,
94+
showPublishDateInHeadlineFeed: true,
95+
),
96+
);
97+
await _userAppSettingsRepository.create(item: defaultSettings, userId: userId);
98+
print(
99+
'[DemoDataInitializerService] Default UserAppSettings created for '
100+
'user ID: $userId.',
101+
);
102+
} catch (e, s) {
103+
print(
104+
'[DemoDataInitializerService] Error ensuring UserAppSettings exist '
105+
'for user ID: $userId: $e\n$s',
106+
);
107+
rethrow;
108+
}
109+
}
110+
111+
/// Ensures that [UserContentPreferences] exist for the given [userId].
112+
/// If not found, creates default preferences.
113+
Future<void> _ensureUserContentPreferencesExist(String userId) async {
114+
try {
115+
await _userContentPreferencesRepository.read(id: userId, userId: userId);
116+
print(
117+
'[DemoDataInitializerService] UserContentPreferences found for user ID: $userId.',
118+
);
119+
} on NotFoundException {
120+
print(
121+
'[DemoDataInitializerService] UserContentPreferences not found for '
122+
'user ID: $userId. Creating default preferences.',
123+
);
124+
final defaultPreferences = UserContentPreferences(
125+
id: userId,
126+
followedCountries: const [],
127+
followedSources: const [],
128+
followedTopics: const [],
129+
savedHeadlines: const [],
130+
);
131+
await _userContentPreferencesRepository.create(
132+
item: defaultPreferences,
133+
userId: userId,
134+
);
135+
print(
136+
'[DemoDataInitializerService] Default UserContentPreferences created '
137+
'for user ID: $userId.',
138+
);
139+
} catch (e, s) {
140+
print(
141+
'[DemoDataInitializerService] Error ensuring UserContentPreferences '
142+
'exist for user ID: $userId: $e\n$s',
143+
);
144+
rethrow;
145+
}
146+
}
147+
148+
/// Ensures that the [User] object for the given [user] exists in the
149+
/// user client. If not found, creates it. If found, updates it.
150+
///
151+
/// This is important because the `AuthInmemory` client might create a
152+
/// basic user, but the `DataInMemory<User>` client might not have it
153+
/// immediately.
154+
Future<void> _ensureUserClientUserExists(User user) async {
155+
try {
156+
await _userRepository.read(id: user.id, userId: user.id);
157+
// If user exists, ensure it's up-to-date (e.g., if roles changed)
158+
await _userRepository.update(id: user.id, item: user, userId: user.id);
159+
print(
160+
'[DemoDataInitializerService] User object found and updated in '
161+
'user client for ID: ${user.id}.',
162+
);
163+
} on NotFoundException {
164+
print(
165+
'[DemoDataInitializerService] User object not found in user client '
166+
'for ID: ${user.id}. Creating it.',
167+
);
168+
await _userRepository.create(item: user, userId: user.id);
169+
print(
170+
'[DemoDataInitializerService] User object created in user client '
171+
'for ID: ${user.id}.',
172+
);
173+
} catch (e, s) {
174+
print(
175+
'[DemoDataInitializerService] Error ensuring User object exists in '
176+
'user client for ID: ${user.id}: $e\n$s',
177+
);
178+
rethrow;
179+
}
180+
}
181+
}

0 commit comments

Comments
 (0)