Building Connect Day 12: Post Feature

Post Feature

Even with just 5 steps a day, things are starting to feel a bit overwhelming. That’s why I’ve decided to slow down a bit—longer articles, but only 3-4 times a week. This way, I can optimize the website, make the articles more structured, and even throw in some mini-projects in between!

Today, we’re getting serious about posts in Connect—the core feature of any photo-sharing app. We’ll be:
Building a Create Post Page for both mobile & desktop
Designing a responsive home page that adapts across devices
Displaying user-specific posts for a more personalized feed

3-4 more articles, and Connect will be live! Let’s get to work.

Step 1: Create Post Page Mobile

In the lib/features/post/presentation/pages/ create a create_post.dart

Create a stateful widget here.

Return a blank Scaffold here.

In the body, copy the return of _buildmobile method from the profile edit page and paste it here.

Now, get all the necessary files. Along with that provide the responsive helper:

final res = ResponsiveHelper(context);
final isDesktop = res.width(100) >= 800;

Post Feature Post Feature Post Feature


Here we won’t be using the network image we just need to show the uploaded image.

_selectedImage != null
                  ? CircleAvatar(
                      radius: 50,
                      backgroundImage: FileImage(_selectedImage!),
                    )
                  : _webImage != null
                      ? CircleAvatar(
                          radius: 50,
                          backgroundImage: MemoryImage(_webImage!), // For web
                        )
                      : CircleAvatar(
                            radius: 50,
                            child: Icon(Icons.landscape,
                                size: 50, color: Colors.grey),
                          ),

Post Feature Post Feature Post Feature


Replace the methods pick image and update the profile to just empty methods.

Go to the home page and provide an add button there. This button should redirect to our freshly created, create post page. (now that was an alliteration😅)

class _CHomePageState extends State<CHomePage> {
  @override
  Widget build(BuildContext context) {
    return  Scaffold(
      body: IconButton(
        onPressed: () {
          Navigator.push(
                      context,
                      MaterialPageRoute(
                          builder: (context) =>const CCreatePostPage()),
                    );
        }, 
        icon: Icon(Icons.add)),
    );
  }
}

Post Feature Post Feature Post Feature


Now run it on your phone and feel free to customize this UI.

Modify the bio input field component to take text as input. (We need to make it dynamic)

Add the pickImage method along with the setProfileImage method(rename it to setPostImage)

Check if the image comes up in the circle after selecting it.

I will make this circle a little bigger.

I have modified this UI a little bit I moved the camera to the bottom left of the circular placeholder.

Post Feature

Step 2: Create Post Page Desktop

Create a new component for the desktop widget. lib/features/post/presentation/components/create_post_desktop.dart

Copy the same code as mobile and modify accordingly.

Now we need a method to build the desktop layout

Widget _buildDesktopLayout(BuildContext context, ResponsiveHelper res) {
    return Center(
      child: CCreatePostDesktop(
        webImage: _webImage,
        captionController: captionTextController,
        updateProfile: createPost,
        selectedImage: _selectedImage, // New selected image (if any)
        setProfileImage: setProfileImage, // Callback to update image
      ),
    );
  }

Post Feature Post Feature Post Feature


Time to move the mobile UI code to the mobile layout method. And build in Scaffold based on the platform screen size.

Create Post Desktop View

Step 3: Home Page Post Grid Mobile UI

On a mobile screen, it is good to show one post at a time.

Go to the home page.

Move the method that redirects to the create post page to a floating action button.

➡️Click To View Code post_ui.dart
import 'package:cached_network_image/cached_network_image.dart';
import 'package:connect/features/post/domain/entities/post.dart';
import 'package:flutter/material.dart';

class CPostUi extends StatefulWidget {
  final CPost post;
  const CPostUi({super.key, required this.post});

  @override
  State<CPostUi> createState() => _CPostUiState();
}

class _CPostUiState extends State<CPostUi> {
  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.only(bottom:8.0),
      child: Column(
        children: [
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              Row(
                children: [
          SizedBox(width: 8.0,),
                  const CircleAvatar(
                    child: Icon(Icons.person),
                  ),
          SizedBox(width: 5.0,),
              Text(widget.post.userName),
                ],
              ),
              IconButton(onPressed: (){}, icon: const Icon(Icons.delete))
            ]
          ),
          CachedNetworkImage(
            imageUrl: widget.post.imageUrl,
            height: 200,
            width: double.infinity,
            fit: BoxFit.cover,
            placeholder: (context, url) => const SizedBox(height:200),
            errorWidget: (context, url, error) => const Icon(Icons.error),
            ),
          const Padding(
            padding:  EdgeInsets.all(20.0),
            child: Row(
              children: [
                Icon(Icons.favorite_border),
                Text("0"),
            
                 SizedBox(width:20),
                Icon(Icons.comment),
                Text("0")
              ],
            ),
          )
        ],
      ),
    );
  }
}

Step 4: Home Page Post Grid Desktop UI

On a Desktop screen, it would be good to show a 3×3 grid.

Let’s move the mobile code to the mobile method and create a new desktop method as/ always.

➡️Click To View Code post_ui_desktop.dart
import 'package:cached_network_image/cached_network_image.dart';
import 'package:connect/features/post/domain/entities/post.dart';
import 'package:flutter/material.dart';

class CPostUiDesktop extends StatefulWidget {
  final CPost post;
  const CPostUiDesktop({super.key, required this.post});

  @override
  State<CPostUiDesktop> createState() => _CPostUiDesktopState();
}

class _CPostUiDesktopState extends State<CPostUiDesktop> {
  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.only(left:8.0, right:8.0),
      child: Column(
        children: [
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              Row(
                children: [
          SizedBox(width: 8.0,),
                  const CircleAvatar(
                    child: Icon(Icons.person),
                  ),
          SizedBox(width: 5.0,),
              Text(widget.post.userName),
                ],
              ),
              IconButton(onPressed: (){}, icon: const Icon(Icons.delete))
            ]
          ),
          CachedNetworkImage(
            imageUrl: widget.post.imageUrl,
            height: 200,
            width: double.infinity,
            fit: BoxFit.cover,
            placeholder: (context, url) => const SizedBox(height:200),
            errorWidget: (context, url, error) => const Icon(Icons.error),
            ),
          const Padding(
            padding:  EdgeInsets.all(20.0),
            child: Row(
              children: [
                Icon(Icons.favorite_border),
                Text("0"),
            
                 SizedBox(width:20),
                Icon(Icons.comment),
                Text("0")
              ],
            ),
          )
        ],
      ),
    );
  }
}
➡️Click To View Code home_page.dart
import 'package:connect/features/home/presentation/components/post_ui.dart';
import 'package:connect/features/home/presentation/components/post_ui_desktop.dart';
import 'package:connect/features/post/domain/entities/post.dart';
import 'package:connect/features/post/presentation/pages/create_post.dart';
import 'package:connect/utils/responsive_helper.dart';
import 'package:flutter/material.dart';

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

  @override
  State<CHomePage> createState() => _CHomePageState();
}

class _CHomePageState extends State<CHomePage> {
  @override
  Widget build(BuildContext context) {
    final res = ResponsiveHelper(context);
    final isDesktop = res.width(100) >= 800;
    return  Scaffold(
       floatingActionButton: FloatingActionButton(
        onPressed: () {
          Navigator.push(
                        context,
                        MaterialPageRoute(
                            builder: (context) =>const CCreatePostPage()),
                      );
        },
        child: Icon(Icons.add, color:Theme.of(context).colorScheme.inversePrimary),
       ),
      body:Center(
        child: SafeArea(
          child: isDesktop
              ? _buildDesktopLayout(context, res)
              : _buildMobileLayout(context, res),
        ),
      ),
    );
  }
  Widget _buildDesktopLayout(BuildContext context, ResponsiveHelper res){
    return Padding(
        padding: const EdgeInsets.all(100.0),
        child: GridView.count(
           crossAxisCount: 3,
          children: [
            CPostUiDesktop(
              post: CPost(
                id:'1',
                userId: '1',
                userName: 'Emily',
                text:'Beautiful Scene',
                imageUrl: 'https://images.unsplash.com/photo-1499951360447-b19be8fe80f5?w=600&auto=format&fit=crop&q=60&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8Nnx8Y29tcHV0ZXJ8ZW58MHx8MHx8fDA%3D',
                imageId: 'sfhld',
                timestamp: DateTime.now(),
              )
            ),
            CPostUiDesktop(
              post: CPost(
                id:'1',
                userId: '1',
                userName: 'someone',
                text:'Beautiful Scene',
                imageUrl: 'https://images.unsplash.com/photo-1525547719571-a2d4ac8945e2?q=80&w=1964&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
                imageId: 'sfhld',
                timestamp: DateTime.now(),
              )
            ),
            CPostUiDesktop(
              post: CPost(
                id:'1',
                userId: '1',
                userName: 'xyz',
                text:'Beautiful Scene',
                imageUrl: 'https://images.unsplash.com/photo-1515378791036-0648a3ef77b2?w=600&auto=format&fit=crop&q=60&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8MTV8fGNvbXB1dGVyfGVufDB8fDB8fHww',
                imageId: 'sfhld',
                timestamp: DateTime.now(),
              )
            ),
            CPostUiDesktop(
              post: CPost(
                id:'1',
                userId: '1',
                userName: 'xyz',
                text:'Beautiful Scene',
                imageUrl: 'https://images.unsplash.com/photo-1515378791036-0648a3ef77b2?w=600&auto=format&fit=crop&q=60&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8MTV8fGNvbXB1dGVyfGVufDB8fDB8fHww',
                imageId: 'sfhld',
                timestamp: DateTime.now(),
              )
            ),
            CPostUiDesktop(
              post: CPost(
                id:'1',
                userId: '1',
                userName: 'Emily',
                text:'Beautiful Scene',
                imageUrl: 'https://images.unsplash.com/photo-1499951360447-b19be8fe80f5?w=600&auto=format&fit=crop&q=60&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8Nnx8Y29tcHV0ZXJ8ZW58MHx8MHx8fDA%3D',
                imageId: 'sfhld',
                timestamp: DateTime.now(),
              )
            ),
            CPostUiDesktop(
              post: CPost(
                id:'1',
                userId: '1',
                userName: 'someone',
                text:'Beautiful Scene',
                imageUrl: 'https://images.unsplash.com/photo-1525547719571-a2d4ac8945e2?q=80&w=1964&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
                imageId: 'sfhld',
                timestamp: DateTime.now(),
              )
            ),
          ]
        ),
      );
  }
  Widget _buildMobileLayout(BuildContext context, ResponsiveHelper res){
    return Padding(
        padding: const EdgeInsets.only(top:30.0),
        child: ListView(
          children: [
            CPostUi(
              post: CPost(
                id:'1',
                userId: '1',
                userName: 'Emily',
                text:'Beautiful Scene',
                imageUrl: 'https://images.unsplash.com/photo-1499951360447-b19be8fe80f5?w=600&auto=format&fit=crop&q=60&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8Nnx8Y29tcHV0ZXJ8ZW58MHx8MHx8fDA%3D',
                imageId: 'sfhld',
                timestamp: DateTime.now(),
              )
            ),
            CPostUi(
              post: CPost(
                id:'1',
                userId: '1',
                userName: 'someone',
                text:'Beautiful Scene',
                imageUrl: 'https://images.unsplash.com/photo-1525547719571-a2d4ac8945e2?q=80&w=1964&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
                imageId: 'sfhld',
                timestamp: DateTime.now(),
              )
            ),
            CPostUi(
              post: CPost(
                id:'1',
                userId: '1',
                userName: 'xyz',
                text:'Beautiful Scene',
                imageUrl: 'https://images.unsplash.com/photo-1515378791036-0648a3ef77b2?w=600&auto=format&fit=crop&q=60&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8MTV8fGNvbXB1dGVyfGVufDB8fDB8fHww',
                imageId: 'sfhld',
                timestamp: DateTime.now(),
              )
            ),
          ]
        ),
      );
  }
}
Home page desktop View

Step 5: User-Specific Posts UI

All you need to do is modify the profile page and add these layouts.

Check the code here at GitHub: https://github.com/maitry4/Connect/

Yup, that’s it.

With today’s progress, we’re one step closer to launching Connect!

Now, users can create and view posts seamlessly across devices—a key step in making this app functional.

Next up?

Adding likes and comments, because what’s a photo-sharing app without engagement?

We’re almost there—just the post interactions and follow/unfollow features left.

I can’t wait to see it live.

What about you?? 😃

Leave a Reply