I am trying to create a social media app; I want to see my posts in profile page, I can only see them for a second, then they are replaced by no posts
03:03 13 Apr 2026
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:google_fonts/google_fonts.dart';
import 'auth_service.dart';

class ProfilePage extends StatefulWidget {
  const ProfilePage({super.key});

  @override
  State createState() => _ProfilePageState();
}

class _ProfilePageState extends State {
  final auth = AuthService();
  final db = FirebaseFirestore.instance;

  final usernameCtrl = TextEditingController();
  final bioCtrl = TextEditingController();
  String gender = "Not set";

  /* ================= EDIT MODAL ================= */
  void openEditModal(Map? data) {
    usernameCtrl.text = data?['username'] ?? "";
    bioCtrl.text = data?['bio'] ?? "";
    gender = data?['gender'] ?? "Not set";

    showGeneralDialog(
      context: context,
      barrierDismissible: true,
      barrierLabel: "Edit",
      barrierColor: Colors.black.withOpacity(0.4),
      transitionDuration: const Duration(milliseconds: 250),
      pageBuilder: (_, __, ___) {
        return Center(
          child: Material(
            color: Colors.transparent,
            child: Container(
              margin: const EdgeInsets.symmetric(horizontal: 18),
              padding: const EdgeInsets.all(20),
              decoration: BoxDecoration(
                color: Colors.white,
                borderRadius: BorderRadius.circular(24),
              ),
              child: Column(
                mainAxisSize: MainAxisSize.min,
                children: [
                  Text(
                    "Edit Profile",
                    style: GoogleFonts.montserrat(
                      fontSize: 18,
                      fontWeight: FontWeight.w700,
                    ),
                  ),
                  const SizedBox(height: 16),

                  _field("Username", usernameCtrl),
                  const SizedBox(height: 10),
                  _field("Bio", bioCtrl, maxLines: 2),

                  const SizedBox(height: 10),

                  Container(
                    padding: const EdgeInsets.symmetric(horizontal: 14),
                    decoration: BoxDecoration(
                      color: const Color(0xFFF5F5F5),
                      borderRadius: BorderRadius.circular(30),
                    ),
                    child: DropdownButtonHideUnderline(
                      child: DropdownButton(
                        value: gender,
                        isExpanded: true,
                        items: const [
                          DropdownMenuItem(value: "Not set", child: Text("Not set")),
                          DropdownMenuItem(value: "Male", child: Text("Male")),
                          DropdownMenuItem(value: "Female", child: Text("Female")),
                          DropdownMenuItem(value: "Other", child: Text("Other")),
                        ],
                        onChanged: (val) => setState(() {
                          gender = val ?? "Not set";
                        }),
                      ),
                    ),
                  ),

                  const SizedBox(height: 18),

                  SizedBox(
                    width: double.infinity,
                    height: 50,
                    child: ElevatedButton(
                      style: ElevatedButton.styleFrom(
                        backgroundColor: Colors.black,
                        shape: RoundedRectangleBorder(
                          borderRadius: BorderRadius.circular(50),
                        ),
                      ),
                      onPressed: () async {
                        await db.collection('users').doc(auth.uid).set({
                          "username": usernameCtrl.text.trim(),
                          "bio": bioCtrl.text.trim(),
                          "gender": gender,
                          "email": auth.email,
                        }, SetOptions(merge: true));

                        Navigator.pop(context);
                        setState(() {});
                      },
                      child: Text(
                        "Save",
                        style: GoogleFonts.montserrat(color: Colors.white),
                      ),
                    ),
                  ),
                ],
              ),
            ),
          ),
        );
      },
    );
  }

  Widget _field(String hint, TextEditingController ctrl, {int maxLines = 1}) {
    return TextField(
      controller: ctrl,
      maxLines: maxLines,
      style: GoogleFonts.montserrat(),
      decoration: InputDecoration(
        hintText: hint,
        filled: true,
        fillColor: const Color(0xFFF5F5F5),
        border: OutlineInputBorder(
          borderRadius: BorderRadius.circular(30),
          borderSide: BorderSide.none,
        ),
      ),
    );
  }

  /* ================= SAFE IMAGE ================= */
  Widget safeImage(String url) {
    if (url.isEmpty) {
      return const ColoredBox(color: Colors.black12);
    }

    return Image.network(
      url,
      fit: BoxFit.cover,

      // prevents crash / broken UI
      errorBuilder: (_, __, ___) => const ColoredBox(
        color: Colors.black12,
        child: Center(child: Icon(Icons.broken_image)),
      ),
    );
  }

  /* ================= UI ================= */
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,

      body: SafeArea(
        child: StreamBuilder(
          stream: db.collection('users').doc(auth.uid).snapshots(),
          builder: (context, userSnap) {
            if (!userSnap.hasData) {
              return const Center(child: CircularProgressIndicator());
            }

            final data =
                userSnap.data!.data() as Map? ?? {};

            final username = data['username'] ?? "No username";
            final bio = data['bio'] ?? "No bio yet";
            final gender = data['gender'] ?? "Not set";
            final email = data['email'] ?? auth.email;

            return SingleChildScrollView(
              padding: const EdgeInsets.all(20),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [

                  /// HEADER
                  Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: [
                      Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          Text(
                            "Profile",
                            style: GoogleFonts.montserrat(
                              fontSize: 28,
                              fontWeight: FontWeight.w700,
                            ),
                          ),
                          Text(
                            "Your account space",
                            style: GoogleFonts.montserrat(
                              fontSize: 13,
                              color: Colors.black54,
                            ),
                          ),
                        ],
                      ),
                      GestureDetector(
                        onTap: () => openEditModal(data),
                        child: const Icon(Icons.edit),
                      )
                    ],
                  ),

                  const SizedBox(height: 25),

                  /// PROFILE CARD
                  Container(
                    width: double.infinity,
                    padding: const EdgeInsets.all(20),
                    decoration: BoxDecoration(
                      color: const Color(0xFFF8F8F8),
                      borderRadius: BorderRadius.circular(24),
                    ),
                    child: Column(
                      children: [
                        const CircleAvatar(
                          radius: 40,
                          backgroundColor: Colors.black,
                          child: Icon(Icons.person, color: Colors.white),
                        ),
                        const SizedBox(height: 10),

                        Text(
                          username,
                          textAlign: TextAlign.center,
                          style: GoogleFonts.montserrat(
                            fontSize: 22,
                            fontWeight: FontWeight.w800,
                          ),
                        ),

                        Text(email),
                        const SizedBox(height: 10),
                        Text(bio, textAlign: TextAlign.center),

                        const SizedBox(height: 10),

                        Container(
                          padding: const EdgeInsets.symmetric(
                              horizontal: 14, vertical: 6),
                          decoration: BoxDecoration(
                            color: Colors.black,
                            borderRadius: BorderRadius.circular(20),
                          ),
                          child: Text(
                            gender,
                            style: const TextStyle(color: Colors.white),
                          ),
                        )
                      ],
                    ),
                  ),

                  const SizedBox(height: 25),

                  Text(
                    "Posts",
                    style: GoogleFonts.montserrat(
                      fontSize: 18,
                      fontWeight: FontWeight.w700,
                    ),
                  ),

                  const SizedBox(height: 10),

                  /// 🔥 FIXED STREAM (NO LOADER FLICKER BUG)
                  StreamBuilder(
                    stream: db
                        .collection("posts")
                        .where("userId", isEqualTo: auth.uid)
                        .orderBy("createdAt", descending: true)
                        .snapshots(),

                    builder: (context, postSnap) {
                      // ONLY SHOW LOADER IF NO DATA EVER EXISTS
                      if (postSnap.connectionState ==
                              ConnectionState.waiting &&
                          !postSnap.hasData) {
                        return const Center(
                            child: CircularProgressIndicator());
                      }

                      if (!postSnap.hasData ||
                          postSnap.data!.docs.isEmpty) {
                        return const Center(child: Text("No posts yet"));
                      }

                      final posts = postSnap.data!.docs;

                      return GridView.builder(
                        shrinkWrap: true,
                        physics: const NeverScrollableScrollPhysics(),
                        itemCount: posts.length,
                        gridDelegate:
                            const SliverGridDelegateWithFixedCrossAxisCount(
                          crossAxisCount: 3,
                          crossAxisSpacing: 6,
                          mainAxisSpacing: 6,
                        ),
                        itemBuilder: (_, i) {
                          final d =
                              posts[i].data() as Map;

                          return ClipRRect(
                            borderRadius: BorderRadius.circular(10),
                            child: Stack(
                              fit: StackFit.expand,
                              children: [
                                safeImage(d['mediaUrl'] ?? ""),

                                if (d['mediaType'] == "video")
                                  const Center(
                                    child: Icon(
                                      Icons.play_circle_fill,
                                      color: Colors.white,
                                      size: 30,
                                    ),
                                  ),
                              ],
                            ),
                          );
                        },
                      );
                    },
                  ),
                ],
              ),
            );
          },
        ),
      ),
    );
  }
}

💡 What I expected

  • Smooth feed like Instagram

  • Images load once and stay stable

  • No flickering loader after initial load


❌ What is happening

  • Loader appears even after snapshot has data

  • UI rebuild seems to reset image state

  • Images briefly render then disappear/reload

This is my code guys , can you please help ,I will be very thankful

flutter firebase cloudinary