Flutter Social Forum Application

Unlock the secrets of Flutter social app development with our complete guide on Firestore CRUD operations. Elevate your app building skills today!

Published March 27, 2020

This Example will show the Prototype for Forum Application with Flutter.

In this Example hanlde the state by ScopedModel

Let's check code:

ScopedModel class

import 'package:flutter/material.dart';
import 'package:scoped_model/scoped_model.dart';

class MyScopeModel extends Model{

  int selectedTyep=1;
  String selectedCategory="";
  get selectedTypes=>selectedTyep;
  get selectedCat=>selectedCategory;

  void setSelected(int value)
  {
    selectedTyep=value;
    notifyListeners();
  }
 void setCategory(String value)
  {
    selectedCategory=value;
    notifyListeners();
  }

}

Login page

import 'package:flutter/material.dart';

class LoginPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        backgroundColor: Colors.green,
        centerTitle: true,
        elevation: 0.0,
        title: new Text(
          "Welcome",
          textScaleFactor: 1.3,
        ),
      ),
      body: new Container(
        color: Colors.amberAccent,
        padding: const EdgeInsets.all(30.0),
        child:  ListView(
          children: <Widget>[
            new Container(
              margin: const EdgeInsets.all(20.0),
              decoration: new BoxDecoration(
                borderRadius: new BorderRadius.all(new Radius.circular(30.0)),
              ),
              height: 100.0,
              alignment: Alignment.center,
              child: new Icon(
                Icons.beach_access,
                size: 100.0,
                color: Colors.green,
              ),
            ),
            new TextField(
              controller: new TextEditingController(),
              decoration: new InputDecoration(
                hintText: 'Username',
                filled: true,
                fillColor: Colors.white,
              ),
            ),
            SizedBox(height: 10,),
            new TextField(
              controller: new TextEditingController(),
              obscureText: true,
              decoration: new InputDecoration(
                hintText: 'Password',
                filled: true,
                fillColor: Colors.white,
              ),
            ),
            new Container(
              // margin: const EdgeInsets.only( bottom: 150.0),
              child: new Column(
                crossAxisAlignment: CrossAxisAlignment.stretch,
                children: <Widget>[
                  new Container(
                    margin: const EdgeInsets.symmetric(vertical: 8.0),
                    child: new RaisedButton(
                      child: new Text("Login",style: TextStyle(color: Colors.white),),
                      onPressed: onPressed,
                      color: Colors.pink,
                    ),
                  ),
                  new RaisedButton(
                    child: new Text("Forgot Password"),
                    onPressed: onPressed,
                  ),
                ],
              ),
            ),
            new Expanded(
              child: new Column(
                crossAxisAlignment: CrossAxisAlignment.stretch,
                mainAxisAlignment: MainAxisAlignment.end,
                children: <Widget>[
                  new Container(
                    margin: const EdgeInsets.symmetric(vertical: 8.0),
                    child: new RaisedButton(
                      child: new Text("Register"),
                      onPressed: onPressed,
                      color: Colors.yellow,
                    ),
                  ),
                  new RaisedButton(
                    child: new Text("Continue as Guest"),
                    onPressed: () {Navigator.pushNamed(context, '/forum');},
                  ),
                ],
              ),
            )
          ],
        )
      ),
    );
  }

  void onPressed() {}

}

 

To handle the Forum category created few model classes.

Forum List page

Flutter Forum Application

import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:practice1/assets/colors.dart';
import 'package:scoped_model/scoped_model.dart';
import 'constants/icons.dart';
import 'model/category.dart';
import 'model/listdata.dart';
import 'model/scopemodel.dart';

class ForumPage extends StatefulWidget {
  ForumPage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _ForumPageState createState() => new _ForumPageState();
}

class _ForumPageState extends State<ForumPage> {

  List<CategoryIcon>listCategory;
  @override
  void initState() {
    super.initState();
    listCategory=new List();
    print("reading");
   loadCategory();
  }

  MyScopeModel model;
   Container topCategoyIcons(model) {
     return new Container(

       alignment: Alignment.center,
       decoration: new BoxDecoration(
           gradient: new LinearGradient(
             colors: [
               AppColorsTheme.myTheme.titleBarGradientStartColor,
               AppColorsTheme.myTheme.titleBarGradientEndColor
             ],
             begin: const FractionalOffset(0.0, 0.0),
             end: const FractionalOffset(0.0, 1.0),
             stops: [0.0, 1.0],
             tileMode: TileMode.clamp,
           )),
       child: new Container(
         margin: EdgeInsets.only(top: 20,left: 10,right: 10),
         alignment: Alignment.bottomCenter,

         padding: EdgeInsets.only(bottom: 10),
         decoration: new BoxDecoration(
           color: AppColorsTheme.myTheme.secondaryGradientColor,
           // border: new Border.all(color: Colors.black, width: 1.0),
           borderRadius: new BorderRadius.only(
             topLeft: new Radius.circular(30.0),
             topRight: new Radius.circular(30.0),
           ),
         ),
         child: new Row(
           mainAxisAlignment: MainAxisAlignment.spaceAround,
           crossAxisAlignment: CrossAxisAlignment.center,
           children: <Widget>[
             listCategory[0],
             listCategory[1],
             listCategory[2],
             listCategory[3],

           ],
         ),
       ),
     );
   }

   Container categoryMetric(model) {
     return new Container(
       padding: const EdgeInsets.all(5.0),
       margin: const EdgeInsets.fromLTRB(10.0, 0.0, 10.0, 15.0),
       decoration: new BoxDecoration(
         gradient: new LinearGradient(
           colors: [
             AppColorsTheme.myTheme.secondaryGradientColor,
             AppColorsTheme.myTheme.secondaryGradientColor
           ],
           begin: const FractionalOffset(0.0, 0.5),
           end: const FractionalOffset(0.0, 1.0),
           stops: [0.0, 1.0],
           tileMode: TileMode.clamp,
         ),
         // border: new Border.all(color: Colors.black, width: 1.0),
         borderRadius: new BorderRadius.only(
           bottomLeft: new Radius.circular(30.0),
           bottomRight: new Radius.circular(30.0),
         ),
       ),
       child: new Row(
         mainAxisAlignment: MainAxisAlignment.spaceAround,
         crossAxisAlignment: CrossAxisAlignment.center,
         children: <Widget>[
           listCategory[4],
           listCategory[5],
           listCategory[6],
           listCategory[7],

         ],
       ),
     );
   }


   listView(MyScopeModel model) {return
     new ListView.builder(
       physics: NeverScrollableScrollPhysics(),
       itemBuilder: (BuildContext context, int index) =>
       new EntryItem(myForums[model.selectedTyep][index]),
       itemCount: myForums[model.selectedTyep].length,
       shrinkWrap: true,
     );}

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        backgroundColor: Colors.green,
        centerTitle: false,
        elevation: 0.0,
        title: new Text(
          widget.title,
          textScaleFactor: 1.3,
        ),
        actions: <Widget>[
          new IconButton(
            icon: new Icon(Icons.search),
            onPressed: _onSearchPressed,
          ),
        ],
      ),
      body: new Container(
        child:ScopedModelDescendant<MyScopeModel>(
          builder: (context,child,model){

            this.model=model;

            return  SingleChildScrollView(
              child: Column(
                children: <Widget>[ (listCategory.length>4)?topCategoyIcons(model):Container(), Divider(height: 1,color: Colors.white,), (listCategory.length>7)?categoryMetric(model):Container(), listView(model)],
              ),
            );
          },
        ),


      ),
    );
  }
  void _onSearchPressed() {
    Navigator.pop(context);
  }

   loadCategory() {
    DefaultAssetBundle.of(context).loadString("assets/category.json")
        .then((s) {

      List list=json.decode(s) as List;
      print(list);
      setState(() { listCategory= list.map((e) => fromJson(e)).toList();});/*{
        setState(() {
          print("reading");
            listCategory.add();
          print("${listCategory.length}");
        })
      });*/
    })
        .catchError((error) {

      print(error);
    });
  }
}

 

Forum Details Page

Flutter Forum Application

import 'package:flutter/material.dart';
import 'package:practice1/assets/colors.dart';
import 'package:scoped_model/scoped_model.dart';

import 'model/scopemodel.dart';

class ForumDetailPage extends StatefulWidget {
  ForumDetailPage();

  @override
  _ForumDetailPageState createState() => new _ForumDetailPageState();
}

var ForumPostArr = [
  new ForumPostEntry("User1", "2 Days ago", 0 , 0 , "Hello,\n\nDummy Text about flutter post "),
  new ForumPostEntry("User2", "23 Hours ago", 1 , 0 , "he basic component in a Flutter program is a "widget", which can in turn consist of other widgets. A widget describes the logic, interaction, and design of a UI element with an implementation similar to React. Unlike other cross-platform toolkits such as React Native and Xamarin which draw widgets using native platform components, Flutter renders widgets itself on a per-pixel basis.
There are two fundamental types of widgets: stateless and stateful. Stateless widgets only update if their inputs change, making them very efficient, while stateful widgets can call the setState() method to update an internal state and redraw.[27]
Although widgets are the primary method of constructing Flutter applications, they can also be bypassed in favor of directly drawing on a canvas. This feature has been occasionally used to implement game engines in Flutter
."),
  new ForumPostEntry("User3", "2 Days ago", 5 , 0 , "Dummy Text about flutter post ."),
  new ForumPostEntry("User4", "2 Days ago", 0 , 0 , "Dummy Text about flutter post ."),
];

class _ForumDetailPageState extends State<ForumDetailPage> {
  int forumtype;
  String category;
  @override
  Widget build(BuildContext context) {

    var questionSection = new Padding(
      padding: const EdgeInsets.all(8.0),
      child: new Column(
        children: <Widget>[
          new Text(
            "How do I become a expert in programming as well as design ??",
            textScaleFactor: 1.5,
            style: new TextStyle(fontWeight: FontWeight.bold),
          ),
          new Padding(
            padding: const EdgeInsets.all(12.0),
            child: new Row(
              mainAxisAlignment: MainAxisAlignment.spaceAround,
              children: <Widget>[
                new IconWithText(Icons.laptop_mac, "Technology"),
                new IconWithText(
                  Icons.check_circle,
                  "Answered",
                  iconColor: Colors.green,
                ),
                new IconWithText(Icons.remove_red_eye, "54")
              ],
            ),
          ),
          new Divider()
        ],
      ),
    );

    var responses = new Container(
      padding: const EdgeInsets.all(8.0),
      child: new ListView.builder(
        itemBuilder: (BuildContext context, int index) => new ForumPost(ForumPostArr[index]),
        itemCount: ForumPostArr.length,
      )
    );

    return ScopedModelDescendant<MyScopeModel>(builder: (context,child, model){
      return Scaffold(
        appBar: new AppBar(
          backgroundColor: Colors.green,
          title: new Text(model.selectedCat,style: TextStyle(color: Colors.white),),
        ),
        body: new Column(
          children: <Widget>[
            questionSection,
            new Expanded(
                child: new Padding(
                  padding: const EdgeInsets.only(bottom: 20.0),
                  child: responses,
                ))
          ],
        ),
      );
    });
  }
}

class ForumPostEntry{
  final String username;
  final String hours;
  final int likes;
  final int dislikes;
  final String text;

  ForumPostEntry(this.username, this.hours, this.likes, this.dislikes, this.text);
}

class ForumPost extends StatelessWidget {
  final ForumPostEntry entry;

  ForumPost(this.entry);

  @override
  Widget build(BuildContext context) {
    return new Container(
      margin: const EdgeInsets.all(5.0),
      decoration: new BoxDecoration(
        color: Colors.green,
        borderRadius: const BorderRadius.all(const Radius.circular(20.0)),
      ),
      child: new Column(
        children: <Widget>[
          new Container(
            decoration: new BoxDecoration(
              color: Colors.green,
              borderRadius: const BorderRadius.only(
                  topLeft: const Radius.circular(20.0),
                  topRight: const Radius.circular(20.0)),
            ),
            child: new Row(
              children: <Widget>[
                new Icon(
                  Icons.person,
                  color: Colors.white,
                  size: 50.0,
                ),
                new Expanded(
                  child: new Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: <Widget>[
                      new Text(
                        entry.username
                            ,style: TextStyle(color: Colors.white),
                      ),
                      new Text(
                        entry.hours,style: TextStyle(color: Colors.white),
                      ),
                    ],
                  ),
                ),
                new Row(
                  children: <Widget>[
                    new Padding(
                      padding: const EdgeInsets.all(2.0),
                      child: new Icon(Icons.thumb_up,color: Colors.amber,),
                    ),
                    new Padding(
                      padding: const EdgeInsets.all(2.0),
                      child: new Text(entry.likes.toString(),style: TextStyle(color: Colors.white),),
                    ),
                    new Padding(
                      padding: const EdgeInsets.all(2.0),
                      child: new Icon(Icons.thumb_down,color: Colors.amber,),
                    ),
                    new Padding(
                      padding: const EdgeInsets.only(right: 8.0, left: 2.0),
                      child: new Text(entry.dislikes.toString(),style: TextStyle(color: Colors.white),),
                    ),
                  ],
                )
              ],
            ),
          ),
          new Container(
            margin: const EdgeInsets.only(left: 2.0,right: 2.0,bottom: 2.0),
            padding: const EdgeInsets.all(8.0),
            decoration: new BoxDecoration(
              color: Colors.grey[200],
              borderRadius: const BorderRadius.only(bottomLeft :const Radius.circular(20.0),bottomRight :const Radius.circular(20.0))
            ),
            child: new Text(entry.text),
          ),
        ],
      ),
    );
  }
}

class IconWithText extends StatelessWidget {
  final IconData iconData;
  final String text;
  final Color iconColor;

  IconWithText(this.iconData, this.text, {this.iconColor});
  @override
  Widget build(BuildContext context) {
    return new Container(
      child: new Row(
        children: <Widget>[
          new Icon(
            this.iconData,
            color: this.iconColor,
          ),
          new Padding(
            padding: const EdgeInsets.only(left: 8.0),
            child: new Text(this.text),
          ),
        ],
      ),
    );
  }
}

Donwload complete code at github repo

Related Tutorials & Resources