instagram clean architecture

Instagram Clone Clean Architecture Flutter – Part 2

Table of Contents

The user interface (UI) is the space where the interaction between humans and machines occur. The UI design prioritizes the user’s visual experience. A good user interface is functional, reliable, and enjoyable to use. In this article we’re going to design the UI of our Instagram app that will really give the feel of real Instagram. So let’s get started.

Add Dependencies

Add these dependencies in your pubspec.yaml file.

				
					#state management
flutter_bloc: ^8.0.1
equatable: ^2.0.3
flutter_icons: ^1.1.0
#Firebase
cloud_firestore: ^3.1.10
firebase_storage: ^10.2.9
firebase_auth: ^3.3.11
firebase_core: ^1.13.1
#Service Locator
get_it: ^7.2.0
flutter_svg: ^1.0.3
image_picker: ^0.8.4+11
intl: ^0.17.0
uuid: ^3.0.6
cached_network_image: ^3.2.0
#show toast
fluttertoast: ^8.0.9
modal_bottom_sheet: ^2.0.1
				
			

Prevent Build Exceptions

Whenever you create flutter app you should configure your app-level gradle file to avoid build gradle exceptions on Runtime.

Go to android > app > build.gradle

Inside this file scroll a bit down you’ll see the defaultConfig, change minSdkVersion to 19 and add one more flag right after this which is multiDexEnabled and set it to true as its Boolean.

Add theme colors

Create a new file in your lib directory const, in this file add the code below.

				
					import 'package:flutter/material.dart';

const backGroundColor = Color.fromRGBO(0, 0, 0, 1.0);
const blueColor = Color.fromRGBO(0, 149, 246, 1);
const primaryColor = Colors.white;
const secondaryColor = Colors.grey;
const darkGreyColor =  Color.fromRGBO(97, 97, 97, 1);
				
			

With this also add two more functions for vertical spacing like whenever there’s need of vertical spacing we’ll call these functions directly in order not to use SizedBox again and again in our UI.

				
					Widget sizeVer(double height) {
  return SizedBox(height: height,);
}

Widget sizeHor(double width) {
  return SizedBox(width: width);
}
				
			

Modify main.dart

				
					import 'package:flutter/material.dart';
import 'features/presentation/page/credential/sign_up_page.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: "Instagram Clone",
      darkTheme: ThemeData.dark(),
      home: SignUpPage(),
    );
  }
}
				
			

Pages

Go to presentation > pages and create a Directory credential there will go our credential pages like Sign In Page and Sign Up Page. And create these pages also.

Code:

sign_in_page.dart

				
					import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:instagram_clone_app/consts.dart';
import 'package:instagram_clone_app/features/presentation/page/credential/sign_up_page.dart';
import 'package:instagram_clone_app/features/presentation/widgets/button_container_widget.dart';
import 'package:instagram_clone_app/features/presentation/widgets/form_container_widget.dart';

class SignInPage extends StatelessWidget {
  const SignInPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: backGroundColor,
      body: Padding(
        padding: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 10),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Flexible(
              child: Container(),
              flex: 2,
            ),
            Center(child: SvgPicture.asset("assets/ic_instagram.svg", color: primaryColor,)),
            sizeVer(30),
            FormContainerWidget(
              hintText: "Email",
            ),
            sizeVer(15),
            FormContainerWidget(
              hintText: "Password",
              isPasswordField: true,
            ),
            sizeVer(15),
            ButtonContainerWidget(
              color: blueColor,
              text: "Sign In",
              onTapListener: () {},
            ),
            Flexible(
              child: Container(),
              flex: 2,
            ),
            Divider(
              color: secondaryColor,
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Text("Don't have and account? ", style: TextStyle(color: primaryColor),),
                InkWell(
                  onTap: () {
                    Navigator.pushAndRemoveUntil(context, MaterialPageRoute(builder: (context) => SignUpPage()), (route) => false);

                  },
                  child:  Text(
                    "Sign Up.",
                    style: TextStyle(fontWeight: FontWeight.bold, color: primaryColor),
                  ),
                ),
              ],
            )
          ],
        ),
      ),
    );
  }
}
				
			

Sign In Page looks like:

sign_up_page.dart

				
					/widgets/form_container_widget.dart';

class SignUpPage extends StatelessWidget {
  const SignUpPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: backGroundColor,
      body: Padding(
        padding: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 10),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Flexible(
              child: Container(),
              flex: 2,
            ),
            Center(child: SvgPicture.asset("assets/ic_instagram.svg", color: primaryColor,)),
            sizeVer(15),
            Center(
              child: Stack(
                children: [
                  Container(
                    width: 60,
                    height: 60,
                    decoration: BoxDecoration(
                      borderRadius: BorderRadius.circular(30)
                    ),
                    child: Image.asset("assets/profile_default.png"),
                  ),
                  Positioned(
                    right: -10,
                    bottom: -15,
                    child: IconButton(
                      onPressed: () {},
                      icon: Icon(Icons.add_a_photo, color: blueColor,),
                    ),
                  ),
                ],

              ),
            ),
            sizeVer(30),
            FormContainerWidget(
              hintText: "Username",
            ),
            sizeVer(15),
            FormContainerWidget(
              hintText: "Email",
            ),
            sizeVer(15),
            FormContainerWidget(
              hintText: "Password",
              isPasswordField: true,
            ),
            sizeVer(15),

            FormContainerWidget(
              hintText: "Bio",
            ),
            sizeVer(15),
            ButtonContainerWidget(
              color: blueColor,
              text: "Sign Up",
              onTapListener: () {},
            ),
            Flexible(
              child: Container(),
              flex: 2,
            ),
            Divider(
              color: secondaryColor,
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Text("Already have an account? ", style: TextStyle(color: primaryColor),),
                InkWell(
                  onTap: () {
                    Navigator.pushAndRemoveUntil(context, MaterialPageRoute(builder: (context) => SignInPage()), (route) => false);
                  },
                  child:  Text(
                    "Sign In.",
                    style: TextStyle(fontWeight: FontWeight.bold, color: primaryColor),
                  ),
                ),
              ],
            )
          ],
        ),
      ),
    );
  }
}
				
			

Sign Up Page looks like:

sign up page

Widgets

Go to presentation > widgets here create two widgets that will be.

Code:

button_container_widget.dart

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


class ButtonContainerWidget extends StatelessWidget {
  final Color? color;
  final String? text;
  final VoidCallback? onTapListener;
  const ButtonContainerWidget({Key? key, this.color, this.text, this.onTapListener}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return InkWell(
      onTap: onTapListener,
      child: Container(
        width: double.infinity,
        height: 40,
        decoration: BoxDecoration(
            color: color,
            borderRadius: BorderRadius.circular(3)
        ),
        child: Center(child: Text("$text", style: TextStyle(color: primaryColor, fontWeight: FontWeight.w600),),),
      ),
    );
  }
}
				
			

Widgets

form_container_widget

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

class FormContainerWidget extends StatefulWidget {

  final TextEditingController? controller;
  final Key? fieldKey;
  final bool? isPasswordField;
  final String? hintText;
  final String? labelText;
  final String? helperText;
  final FormFieldSetter<String>? onSaved;
  final FormFieldValidator<String>? validator;
  final ValueChanged<String>? onFieldSubmitted;
  final TextInputType? inputType;

  const FormContainerWidget({
    this.controller,
    this.isPasswordField,
    this.fieldKey,
    this.hintText,
    this.labelText,
    this.helperText,
    this.onSaved,
    this.validator,
    this.onFieldSubmitted,
    this.inputType
  });


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

class _FormContainerWidgetState extends State<FormContainerWidget> {

  bool _obscureText = true;


  @override
  Widget build(BuildContext context) {
    return Container(
      width: double.infinity,
      decoration: BoxDecoration(
        color: secondaryColor.withOpacity(.35),
        borderRadius: BorderRadius.circular(3),
      ),
      child: new TextFormField(
        style: TextStyle(color: primaryColor),
        controller: widget.controller,
        keyboardType: widget.inputType,
        key: widget.fieldKey,
        obscureText: widget.isPasswordField == true? _obscureText : false,
        onSaved: widget.onSaved,
        validator: widget.validator,
        onFieldSubmitted: widget.onFieldSubmitted,
        decoration: new InputDecoration(
          border: InputBorder.none,
          filled: true,
          hintText: widget.hintText,
          hintStyle: TextStyle(color: secondaryColor),
          suffixIcon: new GestureDetector(
            onTap: () {
              setState(() {
                _obscureText = !_obscureText;
              });
            },
            child:
            widget.isPasswordField==true? Icon(_obscureText ? Icons.visibility_off : Icons.visibility, color: _obscureText == false ? blueColor : secondaryColor,) : Text(""),
          ),
        ),
      ),
    );
  }
}
				
			

Conclusion

We’ve successfully designed the credential pages in this part, Next we’ll go for our main pages. Hit the link below and subscribe to the channel and also not forget to press the bell icon to make sure you get notified whenever new video is uploaded.

Website:
Have any Questions? Find me on
Share on facebook
Share
Share on twitter
Tweet
Share on linkedin
Share
Share on whatsapp
Share
Share on email
Send

Leave a Reply