Your app has 5 critical interconnected issues caused by:
- Improper data flow between Firebase and local TinyDB
- Incomplete linking validation that only works on one screen
- Missing real-time UI updates for linked children count
- Hardcoded colors breaking theme system
- Missing user validation in Firebase signup
✗ Linking only works inside "Link My Child" page
✗ Outside that page, app acts as if accounts aren't linked
✗ Parent dashboard doesn't recognize linked children
✗ Task creation fails because linking status unknown
// Current (WRONG):
await TinyDB.setString('linked_children', _linkedChildren.join(','));
// Problem: Stored as CSV string, not in Firestore user document// Current (WRONG):
static Future<void> linkChildToParent({
required String parentUid,
required String childUid,
...
}) async {
// Updates Firestore ONLY
// But parent dashboard reads from TinyDB 'linked_children' (CSV string)
// MISMATCH: Two sources of truth!
}// Current (WRONG) in parent_dashboard.dart:
Future<void> _loadLinkedChildren() async {
final linkedChildrenJson = await TinyDB.getString('linked_children');
// Only reads TinyDB (local CSV string), ignores Firestore!
// After restart or app refresh, linking "disappears"
}✅ Use Firestore as single source of truth
✅ Update parent document's linkedChildren array
✅ Update child document's parentId field
✅ Add real-time listeners to parent dashboard
✅ Remove CSV string approach
Implementation:
- Firestore parent document stores
linkedChildren: [childUid1, childUid2, ...](array) - Firestore child document stores
parentId: parentUid(string) - Parent dashboard uses StreamBuilder to listen to linkedChildren changes
- No more reading from TinyDB CSV strings for linking status
✗ Badge shows 0 even though children linked
✗ Badge only updates after restart (if at all)
✗ No real-time update when linking/unlinking
// Current (WRONG):
int _linkedChildren = [];
// Loads ONCE in initState, never updates
// Event if linking happens, UI stays frozen// Current: No StreamBuilder or listener
// Parent must manually call setState() (which doesn't happen)// Missing: StreamBuilder that watches linkedChildren array
// Should show count = linkedChildren.length✅ Add StreamBuilder to watch linkedChildren changes ✅ Update badge count in real-time ✅ Add loading indicator while fetching
Implementation:
StreamBuilder<DocumentSnapshot>(
stream: _firestore.collection('users').doc(parentUid).snapshots(),
builder: (ctx, snapshot) {
final count = (snapshot.data?.get('linkedChildren') as List?)?.length ?? 0;
return Badge(label: Text('$count'), ...);
},
)✗ Task creation asks to "link a child again"
✗ Happens even after successful linking
✗ Task never actually created in Firestore
✗ Child doesn't see tasks on dashboard
// Current (WRONG) in task creation:
if (parentId.isEmpty || childId.isEmpty) {
throw Exception('parentId and childId cannot be empty');
}
// Problem: parentId from TinyDB 'parent_id' or Firestore?
// Problem: childId from where? Not passed correctly!// Current (WRONG):
final parentId = await TinyDB.getString('parent_id');
// Issue: What if user is parent but this key doesn't exist?
// Issue: Firebase UID ≠ parent ID from our ID generator// Current (WRONG):
// Task creation needs to know which child to assign to
// But this isn't validated or passed through properly// Current: Tasks stored in: parents/{parentId}/tasks/{taskId}
// But parentId might be using wrong ID (personal vs UID)
// Creating path mismatch = tasks never found!✅ Use Firebase UID as parentId consistently ✅ Store parent's Firebase UID in 'current_user_uid' ✅ Pass childUid explicitly to task creation ✅ Validate linking before task creation ✅ Use StreamBuilder to show child selector
Implementation:
static Future<String?> createTask({
required String parentUid, // Firebase UID
required String childUid, // Firebase UID
required String title,
...
}) async {
// Validate linking
final childDoc = await _firestore.collection('users').doc(childUid).get();
final linkedParentId = childDoc.get('parentId');
if (linkedParentId != parentUid) {
throw Exception('Child not linked to this parent');
}
// Create task
await _firestore
.collection('parents')
.doc(parentUid)
.collection('tasks')
.add({
'parentId': parentUid,
'childId': childUid,
'title': title,
...
});
}✗ Only buttons change color
✗ Background stays same color in child UI
✗ Widgets don't respond to theme change
✗ Colors hardcoded everywhere
// Current (WRONG) - hardcoded everywhere:
Container(
color: const Color(0xFF5ADCDE), // Hardcoded teal
child: Text('Task', style: TextStyle(color: const Color(0xFF212121)))
)
// Problem: These colors never change with theme!// Should be:
Container(
color: Theme.of(context).colorScheme.primary, // Responds to theme
child: Text('Task',
style: Theme.of(context).textTheme.bodyLarge
)
)// ThemeProvider implemented correctly
// But child_dashboard.dart and parent_dashboard.dart:
// - Don't use Theme.of(context).colorScheme
// - Use hardcoded Color(0xFF...) values
// - Don't watch ThemeProvider changes// AppBar uses theme ✓
// Cards might use theme ✓
// Buttons might use theme ✓
// Text colors usually hardcoded ✗
// Container backgrounds hardcoded ✗
// FloatingActionButton hardcoded ✗✅ Replace all hardcoded colors with Theme.of(context).colorScheme ✅ Use Material design tokens ✅ Update app_theme_modern.dart with proper color schemes ✅ Test theme toggle applies everywhere
Implementation Steps:
- Replace
Color(0xFF5ADCDE)→Theme.of(context).colorScheme.primary - Replace
Colors.white→Theme.of(context).colorScheme.onPrimary - Replace
Color(0xFF212121)→Theme.of(context).colorScheme.onSurface - All Containers, Cards, Buttons use colorScheme colors
- All Text uses textTheme from Theme.of(context)
✗ Can log in but user not in Firebase Auth
✗ Firestore users collection empty
✗ No user document created
✗ Only works in TinyDB (local)
// Current in main.dart:
try {
await FirebaseService.initialize();
} catch (e) {
print('Firebase initialization failed, using TinyDB offline mode: $e');
}
// Problem: If Firebase fails, silently switches to TinyDB
// User created only in TinyDB, not Firebase!// Current in AuthService.signUp():
if (FirebaseService.isInitialized) {
final uid = await FirebaseService.createUserWithEmailPassword(...);
if (uid != null) {
await TinyDB.setString('current_user_uid', uid);
return uid;
}
}
// Fallback: createUserWithEmailPassword() fails
return await _signUpTinyDB(...); // Creates ONLY in TinyDB!// Current in FirebaseService.createUserWithEmailPassword():
await _firestore.collection('users').doc(uid).set({
'uid': uid,
'email': email,
'username': username,
'role': role,
...
});
// But if any field missing or Firestore rule denies: silent fail// Current firestore.rules:
match /users/{userId} {
allow create: if request.auth.uid != null &&
request.resource.data.uid == request.auth.uid;
}
// Problem: Requires all fields to be present on create
// If field missing: entire write fails!✅ Ensure Firebase Auth user created first ✅ Then create Firestore user document with all required fields ✅ Fix Firestore security rules to be permissive on create ✅ Add proper error handling & logging ✅ Verify user in both Auth and Firestore before returning success
Implementation:
static Future<String?> createUserWithEmailPassword({...}) async {
try {
// 1. Create Firebase Auth user
final userCredential = await _auth.createUserWithEmailAndPassword(
email: email,
password: password,
);
final uid = userCredential.user?.uid;
if (uid == null) throw Exception('Failed to create auth user');
// 2. Create Firestore user document
await _firestore.collection('users').doc(uid).set({
'uid': uid,
'email': email,
'username': username,
'role': role,
'createdAt': FieldValue.serverTimestamp(),
'linkedChildren': [], // Empty array for parents
'parentId': null, // Null for parents
'ecoPoints': 0,
'waterSaved': 0.0,
'co2Saved': 0.0,
}, SetOptions(merge: false));
// 3. Store locally
await TinyDB.setString('current_user_uid', uid);
// 4. Verify
final doc = await _firestore.collection('users').doc(uid).get();
if (!doc.exists) throw Exception('User document not created');
return uid;
} catch (e) {
print('ERROR in createUserWithEmailPassword: $e');
rethrow; // Don't fallback to TinyDB!
}
}Issue #5: No Firebase Users
↓
Issue #1: Linking Not Recognized App-Wide
↓
Issue #3: Can't Create Tasks (No valid parentId)
↓
Issue #2: Badge Count Not Updating (No children to count)
Issue #4 (Theme): Independent but visible when other issues prevent navigation
| File | Issue(s) | Changes |
|---|---|---|
lib/services/firebase_service.dart |
#1, #3, #5 | User creation, linking logic, task validation |
lib/services/auth_service.dart |
#1, #5 | Better signup flow |
lib/services/task_service.dart |
#3 | Linking validation before task creation |
lib/Screens/parent_dashboard.dart |
#1, #2, #4 | StreamBuilder for children, use Theme.of() |
lib/Screens/child_dashboard.dart |
#4 | Use Theme.of() for all colors |
lib/theme/app_theme_modern.dart |
#4 | Ensure complete color schemes |
firestore.rules |
#5 | Loosen create restrictions |
lib/Screens/add_child_screen.dart |
#1 | Call Firebase service properly |
After fixes, test:
- Parent logs in
- Parent enters child username → links child
- Close app completely
- Reopen app → linking still works
- Parent can see child on dashboard
- Parent can create task for child
- Link first child → badge shows 1
- Link second child → badge updates to 2 (instantly)
- Close/reopen app → badge still shows 2
- Unlink child → badge updates to 1
- Parent linked with child
- Parent creates task
- Task appears in Firestore parents/{parentId}/tasks
- Child sees task on dashboard
- Child can mark complete
- Settings → Display → Select Dark Mode
- All widgets turn dark (not just buttons)
- Navigate between screens → stays dark
- Close/reopen app → still dark
- Switch to Light Mode → all widgets light
- Create new parent account
- Check Firebase Auth → user exists
- Check Firestore users collection → document exists
- Check all fields present: uid, email, username, role, linkedChildren, etc.
- Fix Issue #5 first (User creation) - enables Firebase for other fixes
- Fix Issue #1 next (Linking) - foundation for task system
- Fix Issue #3 then (Task creation) - validates linking works
- Fix Issue #2 next (Badge count) - nice to have, should work after #1
- Fix Issue #4 last (Theme) - cosmetic but important for UX